diff options
author | Shuyi Chen <shuyichen@google.com> | 2013-05-22 13:10:40 -0700 |
---|---|---|
committer | Shuyi Chen <shuyichen@google.com> | 2013-05-22 13:10:40 -0700 |
commit | 8f4ce9ea0de51fee918bffe19c434612d6bbb2d7 (patch) | |
tree | aa6b731d2b1c404e048839fc3ace150eaef2512d | |
parent | 406fc12177de3a9f13c197838235c2fa3e0f16f0 (diff) | |
download | smack-8f4ce9ea0de51fee918bffe19c434612d6bbb2d7.tar.gz |
Add asmack build environemnt.
Downloaded from https://github.com/Flowdalic/asmack/archive/master.zip.
Change-Id: I93fb953348f2d2c058113874923777530a24bcc6
55 files changed, 9426 insertions, 0 deletions
diff --git a/asmack-master/.gitignore b/asmack-master/.gitignore new file mode 100644 index 0000000..cc97859 --- /dev/null +++ b/asmack-master/.gitignore @@ -0,0 +1,2 @@ +build +local.properties diff --git a/asmack-master/CHANGELOG b/asmack-master/CHANGELOG new file mode 100644 index 0000000..e5f9f21 --- /dev/null +++ b/asmack-master/CHANGELOG @@ -0,0 +1,12 @@ +Release 0.8.2 + - Removed the whitespace ping code SMACK-412 + - SMACK-419 PacketWriter: Only flush the BufferedWriter if the packet queue is empty + - SMACK-417 If both PacketReader and PacketWriter fail at the same time, connectionClosedonError() is called two times + - The default ping intervall is now configured in seconds and not milliseconds + +Release 0.8.1.1 + - Improved 'caps' XEP-0115 support + - Fixes an NPE in 0.8.1 + +Release 0.8 + - First release to test the release process diff --git a/asmack-master/LICENSE b/asmack-master/LICENSE new file mode 100644 index 0000000..d50ac8e --- /dev/null +++ b/asmack-master/LICENSE @@ -0,0 +1,291 @@ +Licences + +All code in this repository is licensed under either +(1) Apache License Version 2.0 +(2) THE OPENLDAP PUBLIC LICENSE (only src/novell-openldap-jldap) + +No GNU code will be included. Other patches are always welcome. + + + + The OpenLDAP Public License + Version 2.8, 17 August 2003 + +Redistribution and use of this software and associated documentation +("Software"), with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions in source form must retain copyright statements + and notices, + +2. Redistributions in binary form must reproduce applicable copyright + statements and notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution, and + +3. Redistributions must contain a verbatim copy of this document. + +The OpenLDAP Foundation may revise this license from time to time. +Each revision is distinguished by a version number. You may use +this Software under terms of this license revision or under the +terms of any subsequent revision of the license. + +THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS +CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) +OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +The names of the authors and copyright holders must not be used in +advertising or otherwise to promote the sale, use or other dealing +in this Software without specific, written prior permission. Title +to copyright in this Software shall at all times remain with copyright +holders. + +OpenLDAP is a registered trademark of the OpenLDAP Foundation. + +Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, +California, USA. All Rights Reserved. Permission to copy and +distribute verbatim copies of this document is granted. + + + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ++++++++++++ ++ dnsjava + ++++++++++++ + +Copyright (c) 1998-2011, Brian Wellington. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. diff --git a/asmack-master/README.asmack b/asmack-master/README.asmack new file mode 100644 index 0000000..9ca40b7 --- /dev/null +++ b/asmack-master/README.asmack @@ -0,0 +1,71 @@ +aSmack README +============= + +Version: $VERSION_TAG +Build date: $BUILD_DATE + +Important Notes +=============== + +Read this, or aSmack won't work for you! + +Static Code +----------- + +In order to work correctly on Android, you need to register Smack's +XMPP Providers and Extensions manually and init some static code +blocks before you doing any XMPP activty. Calling +SmackAndroid.init(Context) (in org.jivesoftware.smack) will do this +for you. + +ConnectionConfiguration +----------------------- + +Please use the provided AndroidConnectionConfiguration class if +possible to create a new connection. + +Compression +----------- + +If you want compressed XMPP streams you have to add +[jzlib-1.0.7](http://www.jcraft.com/jzlib/) to your project. Note that +every version higher then 1.0.7 wont work. +More Info: https://github.com/Flowdalic/smack/issues/12 + +Problems / Debugging +============================== + +aSmack Wiki +----------- + +More information about XMPP File Transfers, SSL Certificates and other +stuff related to aSmack can be found in the wiki: +https://github.com/Flowdalic/asmack/wiki + +How to debug your problem +------------------------- + +We always provide source zips. Attach them to the jar in your favorite +IDE. Enable debugging mode with [BOSH|XMPP]Connection.DEBUG and +config.setDebug. See also: +http://www.igniterealtime.org/builds/smack/docs/latest/documentation/debugging.html + +Reporting a bug +--------------- + +Your issue should contain +1. a logcat +2. a server to reproduce +3. the code you are using (for FOSS project we'll accept reposituroy URLs) + +If you record a logcat and make sure to remove your credentials +(usually a base64 block inside <auth></auth>). + +There is no guarantee that we will reply immediatly. But we will try +to investigate the problem. Feel free to join ##smack @ freenode and +ask for help (you may have to idle for some time before you get a +reply). + +Component Revision Information for this Release +=============================================== + diff --git a/asmack-master/README.markdown b/asmack-master/README.markdown new file mode 100644 index 0000000..751291b --- /dev/null +++ b/asmack-master/README.markdown @@ -0,0 +1,100 @@ +aSmack - buildsystem for Smack on Android +========================================= + +*This repository doesn't contain much code, it's a build environment!* + +Tracking trunk can be hard. Doing massive changes on top of trunk can +be near impossible. We are mixing 6 open source projects to provide a +working xmpp library for Android. All trunk-based. + +This repository contains a source fetching, patching and building +script. As well as all the minor changes to make an Android version +fly. See the patches/ folder for a detailed list of changes and +scripts. + +Compiled JARs +============= + +Can be found @ http://asmack.freakempire.de/ + +Make sure to [*read the +README*](https://github.com/Flowdalic/asmack/blob/master/README.asmack) +for every release. + +Support +======= +[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=Flowdalic&url=https://github.com/flowdalic/asmack&title=asmack&language=&tags=github&category=software) + +Compiling aSmack +================ + +1. copy local.properties.example to local.properties and set the +Android SDK path (e.g. sdk-location=/opt/android-sdk-update-manager/ +on a gentoo system) + +2. Run build.bash + +aSmack uses a [special fork of +smack](https://github.com/Flowdalic/smack). You can read about the +results you will get when using one of the various branches provides +in the +[README](https://github.com/Flowdalic/smack/blob/master/README.markdown). + +Apps that use this fork of aSmack +================================= +- [GTalkSMS](http://code.google.com/p/gtalksms/) uses many features of Smack and XMPP on Android: + - File Transfer + - DNS SRV + - MUC + - Entity Caps + - and many more + +- [yaxim](https://github.com/ge0rg/yaxim) +- your app? + +Contribution +============ + +If possible, please base patches on smack, not on aSmack. You can use +the 'upstream' branch from [smack @ +github](https://github.com/Flowdalic/smack). Only in some cases the +'master' branch should be used. + +If your code follows [Smack's contributor guidelines]( +http://community.igniterealtime.org/docs/DOC-1984), is good documented +and comes with some testcases, then it's possible to commit it +upstream. Simply join ##smack @ freenode and ask for a code review. + +Contributors +============ + +We do not keep a seperate CONTRIBUTORS file, and we discourage @author +tags. However you're free to add your full name to every git commit, +and we will preserver this. Let us know if you've helped on +non-technical stuff and we'll find a way to give you the deserved +credit. + +Contact +======= + +Join ##smack @ freenode + +Licences / Used libraries +========================= + +We only accept Apache and BSD-like licences. +We are currently using code from + + * Apache Harmony (sasl/xml) (Apache Licence) + * smack (xmpp) (Apache Licence) + * novell-openldap-jldap (sasl) ([OpenLDAP Licence][1]) + * Apache qpid (sasl) (Apache Licence) + * jbosh (BOSH) (Apache Licence) + * dnsjava (dns srv lookups) (BSD) + * custom code (various glue stuff) (WTFPL | BSD | Apache) + +This should work for just about every project. Contact us if you have +problems with the licence. + + [1]: http://www.openldap.org/devel/cvsweb.cgi/~checkout~/LICENSE?rev=1.23.2.1&hideattic=1&sortbydate=0 "OpenLDAP Licence" + diff --git a/asmack-master/build.bash b/asmack-master/build.bash new file mode 100755 index 0000000..874f238 --- /dev/null +++ b/asmack-master/build.bash @@ -0,0 +1,570 @@ +#!/bin/bash + +svnfetch() { + REV="${3:-HEAD}" + echo "Fetching from ${1} to ${2} at revision ${REV}" + cd $SRC_DIR + if ! [ -f "${2}/.svn/entries" ]; then + mkdir "${2}" + cd "${2}" + svn co --non-interactive --trust-server-cert "${1}" -r "${REV}" "." + else + cd "${2}" + svn cleanup + svn up -r "${REV}" + fi +} + +gitfetch() { + echo "Fetching ${2} branch/commit from ${1} to ${3} via git" + cd $SRC_DIR + if ! [ -f "${3}/.git/config" ]; then + git clone "${1}" "${3}" + cd "${3}" + git checkout "${2}" + else + cd "${3}" + git fetch + git checkout "${2}" + fi + + if [ $? -ne 0 ]; then + exit + fi +} + +hgfetch() { +( + echo "Fetching ${2} branch from ${1} to ${3} via mercurial" + cd src + if [ -e "${2}/.hg" ] ; then + cd ${2} + hg pull + else + hg clone "${1}" "${2}" + fi + hg up -r ${3} +) + if [ $? -ne 0 ]; then + exit + fi +} + + +testsmackgit() { + cd $SRC_DIR + if [ -f .used-smack-git-repo ] && [ $(cat .used-smack-git-repo) != $SMACK_REPO ] ; then + echo "Used smack repository has changed!" + echo "Old: $(cat .used-smack-git-repo) New: ${SMACK_REPO}." + echo "Deleting old local copy" + rm -rf smack + fi + echo "${SMACK_REPO}" > .used-smack-git-repo +} + +fetchall() { + echo "## Step 15: fetching sources" + if $SMACK_LOCAL ; then + # always clean the local copy first + rm -rf ${SRC_DIR}/smack + mkdir ${SRC_DIR}/smack + cd $SMACK_REPO + git archive $SMACK_BRANCH | tar -x -C ${SRC_DIR}/smack + if [ $? -ne 0 ]; then + exit + fi + else + execute gitfetch "$SMACK_REPO" "$SMACK_BRANCH" "smack" + fi + + if ! $UPDATE_REMOTE ; then + echo "Won't update or fetch third party resources" + wait + return + fi + + execute svnfetch "http://svn.apache.org/repos/asf/qpid/trunk/qpid/java/management/common/src/main/" "qpid" + execute svnfetch "http://svn.apache.org/repos/asf/harmony/enhanced/java/trunk/classlib/modules/auth/src/main/java/common/" "harmony" + execute svnfetch "https://dnsjava.svn.sourceforge.net/svnroot/dnsjava/trunk" "dnsjava" + execute gitfetch "git://kenai.com/jbosh~origin" "master" "jbosh" + # jldap doesn't compile with the latest version (missing deps?), therefore it's a fixed version for now + # execute gitfetch "git://git.openldap.org/openldap-jldap.git" "master" "novell-openldap-jldap" + wait +} + +createVersionTag() { + # Skip this step is no version tag is given + [[ -z $VERSION_TAG ]] && return + + local v + cat <<EOF > $TAG_FILE +#!/bin/bash + +# This file contains the version information of the components that +# were used to build this aSmack version + +declare -g -A COMPONENT_VERSIONS +EOF + + for d in $(ls $SRC_DIR) ; do + cd $SRC_DIR + + # Don't record the components version for static-src + for static in $(ls ${ASMACK_BASE}/static-src) ; do + # Don't record the version if it's from the static sources + [ $d == $static ] && continue + done + + if [[ -d $d/.git ]] ; then + v=$(cd $d && git rev-parse HEAD) + key=$d + COMPONENT_VERSIONS["$d"]=$v + elif [[ -d $d/.svn ]] ; then + v=$(cd $d && svn info |grep Revision |cut -f 2 -d ' ') + key=$d + COMPONENT_VERSIONS["$d"]=$v + fi + done + + if $SMACK_LOCAL ; then + cd $SMACK_REPO + v=$(git rev-parse HEAD) + COMPONENT_VERSIONS[smack]=$v + fi + + cd ${ASMACK_BASE} + v=$(git rev-parse HEAD) + COMPONENT_VERSIONS[asmack]=$v + + for i in "${!COMPONENT_VERSIONS[@]}" ; do + echo "COMPONENT_VERSIONS[$i]=${COMPONENT_VERSIONS[$i]}" >> $TAG_FILE + done +} + +copyfolder() { + cd ${ASMACK_BASE} + ( + cd "${1}" + tar -cSsp --exclude-vcs "${3}" + ) | ( + cd "${2}" + tar -xSsp + ) + wait +} + +createbuildsrc() { + echo "## Step 20: creating build/src" + cd "${ASMACK_BASE}" + rm -rf build/src + mkdir -p build/src/trunk + + execute copyfolder "src/smack/source/" "build/src/trunk" "." + execute copyfolder "src/qpid/java" "build/src/trunk" "org/apache/qpid/management/common/sasl" + execute copyfolder "src/novell-openldap-jldap" "build/src/trunk" "." + execute copyfolder "src/dnsjava" "build/src/trunk" "org" + execute copyfolder "src/harmony" "build/src/trunk" "." + execute copyfolder "src/jbosh/src/main/java" "build/src/trunk" "." + if $BUILD_JINGLE ; then + execute copyfolder "src/smack/jingle/extension/source/" "build/src/trunk" "." + fi + wait + # custom overwrites some files from smack, so this has to be done as last + copyfolder "src/custom" "build/src/trunk" "." +} + +patchsrc() { + echo "## Step 25: patch build/src" + cd ${ASMACK_BASE}/build/src/trunk/ + for PATCH in `(cd "../../../${1}" ; find -maxdepth 1 -type f)|sort` ; do + echo $PATCH + if [[ $PATCH == *.sh ]]; then + "../../../${1}/$PATCH" || exit 1 + elif [[ $PATCH == *.patch ]]; then + patch -p0 < "../../../${1}/$PATCH" || exit 1 + fi + done +} + +build() { + echo "## Step 30: compile" + buildandroid + if [ $? -ne 0 ]; then + exit 1 + fi +} + +buildandroid() { + local sdklocation + local version + local sdks + local minSdkVer=8 + + cd $ASMACK_BASE + + if [ ! -f local.properties ] ; then + echo "Could not find local.properties file" + echo "See local.properties.example" + exit 1 + fi + + sdklocation=$(grep sdk-location local.properties| cut -d= -f2) + if [ -z "$sdklocation" ] ; then + echo "Android SDK not found. Don't build android version" + exit 1 + fi + for f in ${sdklocation/\$\{user.home\}/$HOME}/platforms/* ; do + version=`basename $f` + if [[ "$version" != android-* ]] ; then + echo "$sdklocation contains no Android SDKs" + exit 1 + fi + if [[ ${version#android-} -ge $minSdkVer ]] ; then + if [ -n $BUILD_ANDROID_VERSIONS ] ; then + for build_version in $BUILD_ANDROID_VERSIONS ; do + [ ${version#android-} != $build_version ] && continue 2 + done + fi + echo "Building for ${version}" + sdks="${sdks} ${version}\n" + fi + + done + + if [ -z "${sdks}" ] ; then + echo "No SDKs of a suitable minimal API (${minSdkVer}) version found" + exit 1 + fi + + local asmack_suffix + if [[ -n ${VERSION_TAG} ]] && [[ -n ${1} ]] ; then + asmack_suffix="${1}-${VERSION_TAG}" + elif [[ -n ${VERSION_TAG} ]] ; then + asmack_suffix="-${VERSION_TAG}" + else + asmack_suffix="${1}" + fi + if ! echo -e ${sdks} \ + | xargs -I{} -n 1 $XARGS_ARGS ant \ + -Dandroid.version={} \ + -Djar.suffix="${asmack_suffix}" \ + compile-android ; then + exit 1 + fi +} + +buildcustom() { + for dir in `find patch -maxdepth 1 -mindepth 1 -type d`; do + buildsrc + patchsrc "patch" + if $BUILD_JINGLE ; then + patchsrc "jingle" + JINGLE_ARGS="-Djingle=lib/jstun.jar" + fi + patchsrc "${dir}" + local custom + custom=$(echo ${dir} | sed 's:patch/:-:') + ant -Djar.suffix="${custom}" $JINGLE_ARGS + buildandroid "${custom}" + done +} + +parseopts() { + while getopts a:b:r:t:cdhjpux OPTION "$@"; do + case $OPTION in + a) + BUILD_ANDROID_VERSIONS="${OPTARG}" + ;; + r) + SMACK_REPO="${OPTARG}" + ;; + b) + SMACK_BRANCH="${OPTARG}" + ;; + d) + set -x + XARGS_ARGS="-t" + ;; + j) + BUILD_JINGLE=true + ;; + u) + UPDATE_REMOTE=false + ;; + c) + BUILD_CUSTOM=true + ;; + p) + PARALLEL_BUILD=true + ;; + t) + VERSION_TAG="${OPTARG}" + ;; + x) + PUBLISH_RELEASE=true + ;; + h) + echo "$0 -d -c -u -j -r <repo> -b <branch>" + echo "-d: Enable debug" + echo "-j: Build jingle code" + echo "-c: Apply custom patchs from patch directory" + echo "-u: DON'T update remote third party resources" + echo "-r <repo>: Git repository (can be local or remote) for underlying smack repository" + echo "-b <branch>: Git branch used to build aSmack from underlying smack repository" + echo "-p use parallel build where possible" + echo "-t <version>: Create a new version tag. You should build aSmack before calling this" + echo "-x: Publish the release" + echo "-a <SDK Version(s)>: Build only for the given Android SDK versions" + exit + ;; + esac + done +} + +prepareRelease() { + if [[ -z ${VERSION_TAG} ]]; then + echo "Version tag is not set. Not going to prepare a release" + return + fi + + if [ -d $RELEASE_DIR ] ; then + rm -rf $RELEASE_DIR + fi + mkdir -p $RELEASE_DIR + + mv ${ASMACK_BASE}/build/*.{jar,zip} ${RELEASE_DIR}/ + cp $TAG_FILE ${RELEASE_DIR}/ + cp ${ASMACK_BASE}/CHANGELOG ${RELEASE_DIR} + + if [ -n $GPG_KEY ] ; then + find $RELEASE_DIR -maxdepth 1 -and \( -name '*.jar' -or -name '*.zip' \) -print0 \ + | xargs -n 1 -0 $XARGS_ARGS gpg --local-user $GPG_KEY --detach-sign + fi + + find $RELEASE_DIR -maxdepth 1 -and \( -name '*.jar' -or -name '*.zip' \) -print0 \ + | xargs -I{} -n 1 -0 $XARGS_ARGS sh -c 'md5sum {} > {}.md5' + + local release_readme + release_readme=${RELEASE_DIR}/README + + sed \ + -e "s/\$VERSION_TAG/${VERSION_TAG}/" \ + -e "s/\$BUILD_DATE/${BUILD_DATE}/" \ + README.asmack > $release_readme + + # Pretty print the component versions at the end of README + # Note that there is an exclamation mark at the beginning of the + # associative array to access the keys + for i in "${!COMPONENT_VERSIONS[@]}" ; do + local tabs + if [[ ${#i} -le 6 ]] ; then + tabs="\t\t" + else + tabs="\t" + fi + echo -e "${i}:${tabs}${COMPONENT_VERSIONS[$i]}" >> $release_readme + done +} + +publishRelease() { + if [[ -z ${VERSION_TAG} ]]; then + echo "Version tag is not set. Not going to prepare a release" + return + fi + + if [[ -z ${PUBLISH_RELEASE} ]]; then + echo "User doesn't want to publish this release" + return + fi + + if [[ -z $PUBLISH_HOST || -z $PUBLISH_DIR ]]; then + echo "WARNING: Not going to publish this release as either $PUBLISH_HOST or $PUBLISH_DIR is not set" + return + fi + + cd ${ASMACK_RELEASES} + cat <<EOF | sftp $PUBLISH_HOST +rm ${PUBLISH_DIR}/${VERSION_TAG}/* +mkdir ${PUBLISH_DIR}/${VERSION_TAG} +put -r $VERSION_TAG $PUBLISH_DIR +EOF +} + +islocalrepo() { + local R="^(git|ssh)" + if [[ $1 =~ $R ]]; then + return 1 + else + return 0 + fi +} + +initialize() { + echo "## Step 00: initialize" + if ! [ -d build/src/trunk ]; then + mkdir -p build/src/trunk + fi + if [ ! -d src/ ]; then + mkdir src + fi + find build \( -name '*.jar' -or -name '*.zip' \) -print0 | xargs -0 rm -f + rm -rf src/custom +} + +cleanup() { + echo "## Deleting all temporary files" + rm -rf build + rm -rf src +} + +copystaticsrc() { + cp -ur static-src/* src/ +} + +cmdExists() { + command -v $1 &> /dev/null + return $? +} + +prettyPrintSeconds() { + local ttime + if (( $1 > 59 )); then + ttime=$(printf "%dm %ds\n" $(($1/60%60)) $(($1%60)) ) + else + ttime=$(printf "%ds\n" $(($1)) ) + fi + echo "Execution took $ttime" +} + +execute() { + if [ -n "$BACKGROUND" ]; then + "$@" & + else + "$@" + fi +} + +setdefaults() { + # Default configuration, can be changed with script arguments + SMACK_REPO=git://github.com/Flowdalic/smack.git + SMACK_BRANCH=master + SMACK_LOCAL=false + UPDATE_REMOTE=true + BUILD_CUSTOM=false + BUILD_JINGLE=false + JINGLE_ARGS="" + PARALLEL_BUILD=false + VERSION_TAG="" + PUBLISH_RELEASE="" + PUBLISH_HOST="" + PUBLISH_DIR="" + BUILD_ANDROID_VERSIONS="" + + # Often used variables + ASMACK_BASE=$(pwd) + ASMACK_RELEASES=${ASMACK_BASE}/releases + SRC_DIR=${ASMACK_BASE}/src + VERSION_TAG_DIR=${ASMACK_BASE}/version-tags + STARTTIME=$(date -u "+%s") + BUILD_DATE=$(date) + # Declare an associative array that is in global scope ('-g') + declare -g -A COMPONENT_VERSIONS +} + +parseconfig() { + if [ -f ${ASMACK_BASE}/config ]; then + source ${ASMACK_BASE}/config + fi +} + +setconfig() { + if [ ${PARALLEL_BUILD} == "true" ]; then + XARGS_ARGS="${XARGS_ARGS} -P4" + BACKGROUND="true" + else + XARGS_ARGS="" + BACKGROUND="" + fi + + if islocalrepo $SMACK_REPO; then + SMACK_LOCAL=true + SMACK_REPO=`readlink -f $SMACK_REPO` + fi + + if [[ -n ${VERSION_TAG} ]]; then + if ! grep ${VERSION_TAG} CHANGELOG; then + echo "Could not find the tag in the CHANGELOG file. Please write a short summary of changes" + exit 1 + fi + if ! git diff --exit-code; then + echo "Unstaged changes found, please stages your changes" + exit 1 + fi + if ! git diff --cached --exit-code; then + echo "Staged, but uncommited changes found, please commit" + exit 1 + fi + RELEASE_DIR=${ASMACK_RELEASES}/${VERSION_TAG} + TAG_FILE=${VERSION_TAG_DIR}/${VERSION_TAG}.tag + fi +} + +printconfig() { + echo "Smack git repository $SMACK_REPO with branch $SMACK_BRANCH" + echo -e "SMACK_LOCAL:$SMACK_LOCAL\tUPDATE_REMOTE:$UPDATE_REMOTE\tBUILD_CUSTOM:$BUILD_CUSTOM\tBUILD_JINGLE:$BUILD_JINGLE" + echo -e "PARALLEL_BUILD:$PARALLEL_BUILD\tBASE:$ASMACK_BASE" +} + +checkPrerequisites() { + if [[ $BASH_VERSION < 4 ]] ; then + echo "aSmack's build.bash needs at least bash version 4" + exit 1 + fi + + if ! tar --version |grep GNU &> /dev/null ; then + echo "aSmack's build.bash needs GNU tar" + exit 1 + fi +} + +# Main + +setdefaults +parseopts $@ +checkPrerequisites +parseconfig +setconfig +printconfig +initialize +copystaticsrc +testsmackgit +fetchall +createVersionTag +createbuildsrc +patchsrc "patch" +if $BUILD_JINGLE ; then + patchsrc "jingle" + JINGLE_ARGS="-Djingle=lib/jstun.jar" +fi +build + +if $BUILD_CUSTOM ; then + buildcustom +fi + +if cmdExists advzip ; then + echo "advzip found, compressing files" + find build \( -name '*.jar' -or -name '*.zip' \) -print0 | xargs -n 1 -0 $XARGS_ARGS advzip -z4 +else + echo "Could not find the advzip command." + echo "advzip will further reduce the size of the generated jar and zip files," + echo "consider installing advzip" +fi + +prepareRelease +publishRelease + +STOPTIME=$(date -u "+%s") +RUNTIME=$(( $STOPTIME - $STARTTIME )) +prettyPrintSeconds $RUNTIME +printconfig diff --git a/asmack-master/build.xml b/asmack-master/build.xml new file mode 100644 index 0000000..9ecfb84 --- /dev/null +++ b/asmack-master/build.xml @@ -0,0 +1,80 @@ +<project name="asmack" default="compile" basedir="."> + +<property name="jar.suffix" value="" /> +<property name="jingle" value="" /> +<property file="local.properties" /> +<property name="android.version" value="" /> +<target name="compile-jse" description="Compile for java se"> + <delete dir="build/classes" failonerror="false" /> + <mkdir dir="build/classes" /> + <mkdir dir="build/classes/trunk" /> + <javac + target="6" + source="6" + srcdir="build/src/trunk" + destdir="build/classes/trunk" + classpath="lib/xpp3-1.1.4c.jar:lib/httpclient-4.1.3.jar:lib/httpcore-4.1.4.jar" + debug="true" + debuglevel="source,lines" + excludes="**/de/measite/smack/AndroidDebugger.java" + /> + <copy todir="build/classes/trunk"><fileset dir="build/src/trunk" includes="META-INF/**" /></copy> + <jar + basedir="build/classes/trunk" + destfile="build/asmack-jse${jar.suffix}.jar" + filesonly="true" + level="9" + /> + <zip + basedir="build/src/trunk" + destfile="build/asmack-jse-source${jar.suffix}.zip" + excludes="**/de/measite/smack/AndroidDebugger.java" + filesonly="true" + level="9" + /> +</target> + +<target name="check-android-exists" > + <available property="android.exists" file="${sdk-location}/platforms/${android.version}/android.jar" /> + <fail unless="${android.exists}" message="Android version ${android.version} does not is not available : ${sdk-location}/platforms/${android.version}/android.jar is not found" /> +</target> + +<target name="compile-android" description="Compile for android" depends="check-android-exists" > + <delete dir="build/classes/${android.version}" failonerror="false" /> + <mkdir dir="build/classes/${android.version}" /> + <mkdir dir="build/classes/${android.version}/trunk" /> + <javac + target="6" + source="6" + srcdir="build/src/trunk" + destdir="build/classes/${android.version}/trunk" + bootclasspath="${sdk-location}/platforms/${android.version}/android.jar:${jingle}" + debug="true" + debuglevel="source,lines" + /> + <copy todir="build/classes/${android.version}/trunk"> + <fileset dir="build/src/trunk" includes="META-INF/**" /> + </copy> + <jar + basedir="build/classes/${android.version}/trunk" + destfile="build/asmack-${android.version}${jar.suffix}.jar" + filesonly="true" + level="9" + /> + <zip + basedir="build/src/trunk" + destfile="build/asmack-${android.version}-source${jar.suffix}.zip" + filesonly="true" + level="9" + /> +</target> + + +<target + name="compile" + description="Compile for jse targets" + depends="compile-jse" +/> + +</project> + diff --git a/asmack-master/jingle/60-jingle-ext.patch b/asmack-master/jingle/60-jingle-ext.patch new file mode 100644 index 0000000..4e81be5 --- /dev/null +++ b/asmack-master/jingle/60-jingle-ext.patch @@ -0,0 +1,171 @@ +Index: org/jivesoftware/smackx/packet/JingleContentInfo.java +=================================================================== +--- org/jivesoftware/smackx/packet/JingleContentInfo.java (revision 11644) ++++ org/jivesoftware/smackx/packet/JingleContentInfo.java (working copy) +@@ -96,7 +96,7 @@ + */ + public static class Audio extends JingleContentInfo { + +- public static final String NAMESPACE = "urn:xmpp:tmp:jingle:apps:rtp"; ++ public static final String NAMESPACE = "urn:xmpp:jingle:apps:rtp:1"; + + public Audio(final ContentInfo mi) { + super(mi); +Index: org/jivesoftware/smackx/packet/JingleError.java +=================================================================== +--- org/jivesoftware/smackx/packet/JingleError.java (revision 11644) ++++ org/jivesoftware/smackx/packet/JingleError.java (working copy) +@@ -27,7 +27,7 @@ + + public class JingleError implements PacketExtension { + +- public static String NAMESPACE = "urn:xmpp:tmp:jingle:errors"; ++ public static String NAMESPACE = "urn:xmpp:jingle:errors:1"; + + public static final JingleError OUT_OF_ORDER = new JingleError("out-of-order"); + +Index: org/jivesoftware/smackx/packet/JingleTransport.java +=================================================================== +--- org/jivesoftware/smackx/packet/JingleTransport.java (revision 11644) ++++ org/jivesoftware/smackx/packet/JingleTransport.java (working copy) +@@ -270,7 +270,7 @@ + * RTP-ICE profile + */ + public static class Ice extends JingleTransport { +- public static final String NAMESPACE = "urn:xmpp:tmp:jingle:transports:ice-udp"; ++ public static final String NAMESPACE = "urn:xmpp:jingle:transports:ice-udp:1"; + + public Ice() { + super(); +@@ -352,7 +352,7 @@ + * Raw UDP profile. + */ + public static class RawUdp extends JingleTransport { +- public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0177.html#ns"; ++ public static final String NAMESPACE = "urn:xmpp:jingle:transports:raw-udp:1"; + + public RawUdp() { + super(); +Index: org/jivesoftware/smackx/packet/JingleContentDescription.java +=================================================================== +--- org/jivesoftware/smackx/packet/JingleContentDescription.java (revision 11644) ++++ org/jivesoftware/smackx/packet/JingleContentDescription.java (working copy) +@@ -66,6 +66,13 @@ + public abstract String getNamespace(); + + /** ++ * Return the media type. ++ * ++ * @return The media type ++ */ ++ public abstract String getMediaType(); ++ ++ /** + * Adds a audio payload type to the packet. + * + * @param pt the audio payload type to add. +@@ -153,7 +160,8 @@ + synchronized (payloads) { + if (payloads.size() > 0) { + buf.append("<").append(getElementName()); +- buf.append(" xmlns=\"").append(getNamespace()).append("\" >"); ++ buf.append(" xmlns=\"").append(getNamespace()).append("\""); ++ buf.append(" media=\"").append(getMediaType()).append("\" >"); + + Iterator pt = payloads.listIterator(); + while (pt.hasNext()) { +@@ -172,7 +180,8 @@ + */ + public static class Audio extends JingleContentDescription { + +- public static final String NAMESPACE = "urn:xmpp:tmp:jingle:apps:rtp"; ++ public static final String NAMESPACE = "urn:xmpp:jingle:apps:rtp:1"; ++ public static final String MEDIA_TYPE = "audio"; + + public Audio() { + super(); +@@ -189,6 +198,10 @@ + public String getNamespace() { + return NAMESPACE; + } ++ ++ public String getMediaType() { ++ return MEDIA_TYPE; ++ } + } + + /** +Index: org/jivesoftware/smackx/packet/Jingle.java +=================================================================== +--- org/jivesoftware/smackx/packet/Jingle.java (revision 11644) ++++ org/jivesoftware/smackx/packet/Jingle.java (working copy) +@@ -44,7 +44,7 @@ + + // static + +- public static final String NAMESPACE = "urn:xmpp:tmp:jingle"; ++ public static final String NAMESPACE = "urn:xmpp:jingle:1"; + + public static final String NODENAME = "jingle"; + +Index: org/jivesoftware/smackx/packet/JingleDescription.java +=================================================================== +--- org/jivesoftware/smackx/packet/JingleDescription.java (revision 11644) ++++ org/jivesoftware/smackx/packet/JingleDescription.java (working copy) +@@ -69,6 +69,13 @@ + public abstract String getNamespace(); + + /** ++ * Return the media type. ++ * ++ * @return The media type ++ */ ++ public abstract String getMediaType(); ++ ++ /** + * Adds a audio payload type to the packet. + * + * @param pt the audio payload type to add. +@@ -160,7 +167,8 @@ + synchronized (payloads) { + if (payloads.size() > 0) { + buf.append("<").append(getElementName()); +- buf.append(" xmlns=\"").append(getNamespace()).append("\" >"); ++ buf.append(" xmlns=\"").append(getNamespace()).append("\""); ++ buf.append(" media=\"").append(getMediaType()).append("\" >"); + + for (PayloadType payloadType : payloads) { + if (payloadType != null) { +@@ -179,7 +187,8 @@ + */ + public static class Audio extends JingleDescription { + +- public static final String NAMESPACE = "urn:xmpp:tmp:jingle:apps:rtp"; ++ public static final String NAMESPACE = "urn:xmpp:jingle:apps:rtp:1"; ++ public static final String MEDIA_TYPE = "audio"; + + public Audio() { + super(); +@@ -196,5 +205,9 @@ + public String getNamespace() { + return NAMESPACE; + } ++ ++ public String getMediaType() { ++ return MEDIA_TYPE; ++ } + } + } +Index: org/jivesoftware/smackx/jingle/JingleManager.java +=================================================================== +--- org/jivesoftware/smackx/jingle/JingleManager.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/JingleManager.java (working copy) +@@ -255,7 +255,7 @@ + */ + public static void setJingleServiceEnabled() { + ProviderManager providerManager = ProviderManager.getInstance(); +- providerManager.addIQProvider("jingle", "urn:xmpp:tmp:jingle", new JingleProvider()); ++ providerManager.addIQProvider("jingle", "urn:xmpp:jingle:1", new JingleProvider()); + + // Enable the Jingle support on every established connection + // The ServiceDiscoveryManager class should have been already diff --git a/asmack-master/jingle/60-remove-jingle_mediaimpl.patch b/asmack-master/jingle/60-remove-jingle_mediaimpl.patch new file mode 100644 index 0000000..9aefc18 --- /dev/null +++ b/asmack-master/jingle/60-remove-jingle_mediaimpl.patch @@ -0,0 +1,4039 @@ +Index: org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaSession.java (working copy) +@@ -1,92 +0,0 @@ +-/** +- * $RCSfile: TestMediaSession.java,v $ +- * $Revision: 1.1 $ +- * $Date: 08/11/2006 +- * <p/> +- * Copyright 2003-2006 Jive Software. +- * <p/> +- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * <p/> +- * http://www.apache.org/licenses/LICENSE-2.0 +- * <p/> +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +-package org.jivesoftware.smackx.jingle.mediaimpl.test; +- +-import org.jivesoftware.smackx.jingle.JingleSession; +-import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +-import org.jivesoftware.smackx.jingle.media.PayloadType; +-import org.jivesoftware.smackx.jingle.nat.TransportCandidate; +- +-/** +- * This Class implements a complete JingleMediaSession for unit testing. +- * +- * @author Thiago Camargo +- */ +-public class TestMediaSession extends JingleMediaSession { +- +- /** +- * Creates a TestMediaSession with defined payload type, remote and local candidates +- * +- * @param payloadType Payload of the jmf +- * @param remote the remote information. The candidate that the jmf will be sent to. +- * @param local the local information. The candidate that will receive the jmf +- * @param locator media locator +- */ +- public TestMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, +- final String locator, JingleSession jingleSession) { +- super(payloadType, remote, local, "Test", jingleSession); +- initialize(); +- } +- +- /** +- * Initialize the screen share channels. +- */ +- public void initialize() { +- +- } +- +- /** +- * Starts transmission and for NAT Traversal reasons start receiving also. +- */ +- public void startTrasmit() { +- +- } +- +- /** +- * Set transmit activity. If the active is true, the instance should trasmit. +- * If it is set to false, the instance should pause transmit. +- * +- * @param active active state +- */ +- public void setTrasmit(boolean active) { +- +- } +- +- /** +- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf +- */ +- public void startReceive() { +- // Do nothing +- } +- +- /** +- * Stops transmission and for NAT Traversal reasons stop receiving also. +- */ +- public void stopTrasmit() { +- +- } +- +- /** +- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf +- */ +- public void stopReceive() { +- +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/test/TestMediaManager.java (working copy) +@@ -1,93 +0,0 @@ +-/** +- * $RCSfile: TestMediaManager.java,v $ +- * $Revision: 1.3 $ +- * $Date: 25/12/2006 +- * <p/> +- * Copyright 2003-2006 Jive Software. +- * <p/> +- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * <p/> +- * http://www.apache.org/licenses/LICENSE-2.0 +- * <p/> +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.test; +- +-import org.jivesoftware.smackx.jingle.media.JingleMediaManager; +-import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +-import org.jivesoftware.smackx.jingle.media.PayloadType; +-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; +-import org.jivesoftware.smackx.jingle.nat.TransportCandidate; +-import org.jivesoftware.smackx.jingle.JingleSession; +- +-import java.util.*; +- +-/** +- * Implements a MediaManager for test purposes. +- * +- * @author Thiago Camargo +- */ +- +-public class TestMediaManager extends JingleMediaManager { +- +- public static final String MEDIA_NAME = "TestMedia"; +- +- private List<PayloadType> payloads = new ArrayList<PayloadType>(); +- +- private PayloadType preferredPayloadType = null; +- +- public TestMediaManager(JingleTransportManager transportManager) { +- super(transportManager); +- } +- +- /** +- * Return all supported Payloads for this Manager. +- * +- * @return The Payload List +- */ +- public List<PayloadType> getPayloads() { +- return payloads; +- } +- +- public void setPayloads(List<PayloadType> payloads) { +- this.payloads.addAll(payloads); +- } +- +- /** +- * Returns a new JingleMediaSession +- * +- * @param payloadType payloadType +- * @param remote remote Candidate +- * @param local local Candidate +- * @return JingleMediaSession JingleMediaSession +- */ +- public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, +- final TransportCandidate local, final JingleSession jingleSession) { +- TestMediaSession session = null; +- +- session = new TestMediaSession(payloadType, remote, local, "", jingleSession); +- +- return session; +- } +- +- public PayloadType getPreferredPayloadType() { +- if (preferredPayloadType != null) +- return preferredPayloadType; +- return super.getPreferredPayloadType(); +- } +- +- public void setPreferredPayloadType(PayloadType preferredPayloadType) { +- this.preferredPayloadType = preferredPayloadType; +- } +- +- public String getName() { +- return MEDIA_NAME; +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/JMFInit.java (working copy) +@@ -1,282 +0,0 @@ +-package org.jivesoftware.smackx.jingle.mediaimpl;
+-
+-import java.awt.Frame;
+-import java.awt.TextArea;
+-import java.awt.Toolkit;
+-import java.util.Vector;
+-
+-import javax.media.Format;
+-import javax.media.PlugInManager;
+-import javax.media.Renderer;
+-import javax.media.format.AudioFormat;
+-
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-
+-import com.sun.media.ExclusiveUse;
+-import com.sun.media.util.Registry;
+-
+-public class JMFInit extends Frame implements Runnable {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(JMFInit.class);
+-
+- private String tempDir = "/tmp";
+-
+- private boolean done = false;
+-
+- private String userHome;
+-
+- private boolean visible = false;
+-
+- public JMFInit(String[] args, boolean visible) {
+- super("Initializing JMF...");
+-
+- this.visible = visible;
+-
+- Registry.set("secure.allowCaptureFromApplets", true);
+- Registry.set("secure.allowSaveFileFromApplets", true);
+-
+- updateTemp(args);
+-
+- try {
+- Registry.commit();
+- }
+- catch (Exception e) {
+-
+- message("Failed to commit to JMFRegistry!");
+- }
+-
+- Thread detectThread = new Thread(this);
+- detectThread.run();
+-
+- /*
+- * int slept = 0; while (!done && slept < 60 * 1000 * 2) { try {
+- * Thread.currentThread().sleep(500); } catch (InterruptedException ie) { }
+- * slept += 500; }
+- *
+- * if (!done) { console.error("Detection is taking too long!
+- * Aborting!"); message("Detection is taking too long! Aborting!"); }
+- *
+- * try { Thread.currentThread().sleep(2000); } catch
+- * (InterruptedException ie) { }
+- */
+- }
+-
+- public void run() {
+- detectDirectAudio();
+- detectS8DirectAudio();
+- detectCaptureDevices();
+- done = true;
+- }
+-
+- private void updateTemp(String[] args) {
+- if (args != null && args.length > 0) {
+- tempDir = args[0];
+-
+- message("Setting cache directory to " + tempDir);
+- Registry r = new Registry();
+- try {
+- r.set("secure.cacheDir", tempDir);
+- r.commit();
+-
+- message("Updated registry");
+- }
+- catch (Exception e) {
+- message("Couldn't update registry!");
+- }
+- }
+- }
+-
+- private void detectCaptureDevices() {
+- // check if JavaSound capture is available
+- message("Looking for Audio capturer");
+- Class dsauto;
+- try {
+- dsauto = Class.forName("DirectSoundAuto");
+- dsauto.newInstance();
+- message("Finished detecting DirectSound capturer");
+- }
+- catch (ThreadDeath td) {
+- throw td;
+- }
+- catch (Throwable t) {
+- //Do nothing
+- }
+-
+- Class jsauto;
+- try {
+- jsauto = Class.forName("JavaSoundAuto");
+- jsauto.newInstance();
+- message("Finished detecting javasound capturer");
+- }
+- catch (ThreadDeath td) {
+- throw td;
+- }
+- catch (Throwable t) {
+- message("JavaSound capturer detection failed!");
+- }
+-
+- /*
+- // Check if VFWAuto or SunVideoAuto is available
+- message("Looking for video capture devices");
+- Class auto = null;
+- Class autoPlus = null;
+- try {
+- auto = Class.forName("VFWAuto");
+- }
+- catch (Exception e) {
+- }
+- if (auto == null) {
+- try {
+- auto = Class.forName("SunVideoAuto");
+- }
+- catch (Exception ee) {
+-
+- }
+- try {
+- autoPlus = Class.forName("SunVideoPlusAuto");
+- }
+- catch (Exception ee) {
+-
+- }
+- }
+- if (auto == null) {
+- try {
+- auto = Class.forName("V4LAuto");
+- }
+- catch (Exception ee) {
+-
+- }
+- }
+- try {
+- Object instance = auto.newInstance();
+- if (autoPlus != null) {
+- Object instancePlus = autoPlus.newInstance();
+- }
+-
+- message("Finished detecting video capture devices");
+- }
+- catch (ThreadDeath td) {
+- throw td;
+- }
+- catch (Throwable t) {
+-
+- message("Capture device detection failed!");
+- }
+- */
+- }
+-
+- private void detectDirectAudio() {
+- Class cls;
+- int plType = PlugInManager.RENDERER;
+- String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
+- try {
+- // Check if this is the Windows Performance Pack - hack
+- cls = Class.forName("VFWAuto");
+- // Check if DS capture is supported, otherwise fail DS renderer
+- // since NT doesn't have capture
+- cls = Class.forName("com.sun.media.protocol.dsound.DSound");
+- // Find the renderer class and instantiate it.
+- cls = Class.forName(dar);
+-
+- Renderer rend = (Renderer) cls.newInstance();
+- try {
+- // Set the format and open the device
+- AudioFormat af = new AudioFormat(AudioFormat.LINEAR, 44100, 16,
+- 2);
+- rend.setInputFormat(af);
+- rend.open();
+- Format[] inputFormats = rend.getSupportedInputFormats();
+- // Register the device
+- PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
+- plType);
+- // Move it to the top of the list
+- Vector rendList = PlugInManager.getPlugInList(null, null,
+- plType);
+- int listSize = rendList.size();
+- if (rendList.elementAt(listSize - 1).equals(dar)) {
+- rendList.removeElementAt(listSize - 1);
+- rendList.insertElementAt(dar, 0);
+- PlugInManager.setPlugInList(rendList, plType);
+- PlugInManager.commit();
+- // Log.debug("registered");
+- }
+- rend.close();
+- }
+- catch (Throwable t) {
+- // Log.debug("Error " + t);
+- }
+- }
+- catch (Throwable tt) {
+- //Do nothing
+- }
+- }
+-
+- private void detectS8DirectAudio() {
+- Class cls;
+- int plType = PlugInManager.RENDERER;
+- String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
+- try {
+- // Check if this is the solaris Performance Pack - hack
+- cls = Class.forName("SunVideoAuto");
+-
+- // Find the renderer class and instantiate it.
+- cls = Class.forName(dar);
+-
+- Renderer rend = (Renderer) cls.newInstance();
+-
+- if (rend instanceof ExclusiveUse
+- && !((ExclusiveUse) rend).isExclusive()) {
+- // sol8+, DAR supports mixing
+- Vector rendList = PlugInManager.getPlugInList(null, null,
+- plType);
+- int listSize = rendList.size();
+- boolean found = false;
+- String rname = null;
+-
+- for (int i = 0; i < listSize; i++) {
+- rname = (String) (rendList.elementAt(i));
+- if (rname.equals(dar)) { // DAR is in the registry
+- found = true;
+- rendList.removeElementAt(i);
+- break;
+- }
+- }
+-
+- if (found) {
+- rendList.insertElementAt(dar, 0);
+- PlugInManager.setPlugInList(rendList, plType);
+- PlugInManager.commit();
+- }
+- }
+- }
+- catch (Throwable tt) {
+- //Do nothing
+- }
+- }
+-
+- private void message(String mesg) {
+- LOGGER.debug(mesg);
+- }
+-
+- private void createGUI() {
+- TextArea textBox = new TextArea(5, 50);
+- add("Center", textBox);
+- textBox.setEditable(false);
+- addNotify();
+- pack();
+-
+- int scrWidth = (int) Toolkit.getDefaultToolkit().getScreenSize()
+- .getWidth();
+- int scrHeight = (int) Toolkit.getDefaultToolkit().getScreenSize()
+- .getHeight();
+-
+- setLocation((scrWidth - getWidth()) / 2, (scrHeight - getHeight()) / 2);
+-
+- setVisible(visible);
+-
+- }
+-
+- public static void start(boolean visible) {
+- new JMFInit(null, visible);
+- }
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/demo/Demo.java (working copy) +@@ -1,174 +0,0 @@ +-/**
+- * $RCSfile: Demo.java,v $
+- * $Revision: 1.3 $
+- * $Date: 28/12/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-package org.jivesoftware.smackx.jingle.mediaimpl.demo;
+-
+-import org.jivesoftware.smack.Connection;
+-import org.jivesoftware.smack.XMPPConnection;
+-import org.jivesoftware.smack.XMPPException;
+-import org.jivesoftware.smackx.jingle.JingleManager;
+-import org.jivesoftware.smackx.jingle.JingleSession;
+-import org.jivesoftware.smackx.jingle.JingleSessionRequest;
+-import org.jivesoftware.smackx.jingle.listeners.JingleSessionRequestListener;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
+-import org.jivesoftware.smackx.jingle.mediaimpl.jspeex.SpeexMediaManager;
+-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.ScreenShareMediaManager;
+-import org.jivesoftware.smackx.jingle.nat.ICETransportManager;
+-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
+-
+-import javax.swing.*;
+-import java.awt.event.ActionEvent;
+-import java.util.ArrayList;
+-import java.util.List;
+-
+-/**
+- * Jingle Demo Application. It register in a XMPP Server and let users place calls using a full JID and auto-receive calls.
+- * Parameters: Server User Pass.
+- */
+-public class Demo extends JFrame {
+-
+- private JingleTransportManager transportManager = null;
+- private Connection xmppConnection = null;
+-
+- private String server = null;
+- private String user = null;
+- private String pass = null;
+-
+- private JingleManager jm = null;
+- private JingleSession incoming = null;
+- private JingleSession outgoing = null;
+-
+- private JTextField jid;
+-
+- public Demo(String server, String user, String pass) {
+-
+- this.server = server;
+- this.user = user;
+- this.pass = pass;
+-
+- if (user.equals("jeffw")) {
+- jid = new JTextField("eowyn" + "@" + server + "/Smack");
+- } else {
+- jid = new JTextField("jeffw" + "@" + server + "/Smack");
+- }
+-
+- xmppConnection = new XMPPConnection(server);
+- try {
+- xmppConnection.connect();
+- xmppConnection.login(user, pass);
+- initialize();
+- }
+- catch (XMPPException e) {
+- e.printStackTrace();
+- }
+- }
+-
+- public void initialize() {
+- ICETransportManager icetm0 = new ICETransportManager(xmppConnection, "10.47.47.53", 3478);
+- List<JingleMediaManager> mediaManagers = new ArrayList<JingleMediaManager>();
+- //mediaManagers.add(new JmfMediaManager(icetm0));
+- mediaManagers.add(new SpeexMediaManager(icetm0));
+- mediaManagers.add(new ScreenShareMediaManager(icetm0));
+- jm = new JingleManager(xmppConnection, mediaManagers);
+- jm.addCreationListener(icetm0);
+-
+- jm.addJingleSessionRequestListener(new JingleSessionRequestListener() {
+- public void sessionRequested(JingleSessionRequest request) {
+-
+-// if (incoming != null)
+-// return;
+-
+- try {
+- // Accept the call
+- incoming = request.accept();
+-
+- // Start the call
+- incoming.startIncoming();
+- }
+- catch (XMPPException e) {
+- e.printStackTrace();
+- }
+-
+- }
+- });
+- createGUI();
+- }
+-
+- public void createGUI() {
+-
+- JPanel jPanel = new JPanel();
+-
+- jPanel.add(jid);
+-
+- jPanel.add(new JButton(new AbstractAction("Call") {
+- public void actionPerformed(ActionEvent e) {
+- if (outgoing != null) return;
+- try {
+- outgoing = jm.createOutgoingJingleSession(jid.getText());
+- outgoing.startOutgoing();
+- }
+- catch (XMPPException e1) {
+- e1.printStackTrace();
+- }
+- }
+- }));
+-
+- jPanel.add(new JButton(new AbstractAction("Hangup") {
+- public void actionPerformed(ActionEvent e) {
+- if (outgoing != null)
+- try {
+- outgoing.terminate();
+- }
+- catch (XMPPException e1) {
+- e1.printStackTrace();
+- }
+- finally {
+- outgoing = null;
+- }
+- if (incoming != null)
+- try {
+- incoming.terminate();
+- }
+- catch (XMPPException e1) {
+- e1.printStackTrace();
+- }
+- finally {
+- incoming = null;
+- }
+- }
+- }));
+-
+- this.add(jPanel);
+-
+- }
+-
+- public static void main(String args[]) {
+-
+- Demo demo = null;
+-
+- if (args.length > 2) {
+- demo = new Demo(args[0], args[1], args[2]);
+- demo.pack();
+- demo.setVisible(true);
+- demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+- }
+-
+- }
+-
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareSession.java (working copy) +@@ -1,206 +0,0 @@ +-/** +- * $RCSfile: ScreenShareSession.java,v $ +- * $Revision: 1.2 $ +- * $Date: 08/11/2006 +- * <p/> +- * Copyright 2003-2006 Jive Software. +- * <p/> +- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * <p/> +- * http://www.apache.org/licenses/LICENSE-2.0 +- * <p/> +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare; +- +-import java.awt.Rectangle; +-import java.awt.event.WindowAdapter; +-import java.awt.event.WindowEvent; +-import java.io.IOException; +-import java.net.DatagramSocket; +-import java.net.InetAddress; +-import java.net.ServerSocket; +-import java.net.UnknownHostException; +- +-import javax.swing.JFrame; +-import javax.swing.JPanel; +- +-import org.jivesoftware.smackx.jingle.JingleSession; +-import org.jivesoftware.smackx.jingle.SmackLogger; +-import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +-import org.jivesoftware.smackx.jingle.media.PayloadType; +-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder; +-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder; +-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageReceiver; +-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageTransmitter; +-import org.jivesoftware.smackx.jingle.nat.TransportCandidate; +- +-/** +- * This Class implements a complete JingleMediaSession. +- * It sould be used to transmit and receive captured images from the Display. +- * This Class should be automaticly controlled by JingleSession. +- * For better NAT Traversal support this implementation don't support only receive or only transmit. +- * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit() +- * +- * @author Thiago Camargo +- */ +-public class ScreenShareSession extends JingleMediaSession { +- +- private static final SmackLogger LOGGER = SmackLogger.getLogger(ScreenShareSession.class); +- +- private ImageTransmitter transmitter = null; +- private ImageReceiver receiver = null; +- private int width = 600; +- private int height = 600; +- +- /** +- * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates +- * +- * @param payloadType Payload of the jmf +- * @param remote the remote information. The candidate that the jmf will be sent to. +- * @param local the local information. The candidate that will receive the jmf +- * @param locator media locator +- */ +- public ScreenShareSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, +- final String locator, JingleSession jingleSession) { +- super(payloadType, remote, local, "Screen", jingleSession); +- initialize(); +- } +- +- /** +- * Initialize the screen share channels. +- */ +- public void initialize() { +- +- JingleSession session = getJingleSession(); +- if ((session != null) && (session.getInitiator().equals(session.getConnection().getUser()))) { +- // If the initiator of the jingle session is us then we transmit a screen share. +- try { +- InetAddress remote = InetAddress.getByName(getRemote().getIp()); +- transmitter = new ImageTransmitter(new DatagramSocket(getLocal().getPort()), remote, getRemote().getPort(), +- new Rectangle(0, 0, width, height)); +- } catch (Exception e) { +- e.printStackTrace(); +- } +- +- } else { +- // Otherwise we receive a screen share. +- JFrame window = new JFrame(); +- JPanel jp = new JPanel(); +- window.add(jp); +- +- window.setLocation(0, 0); +- window.setSize(600, 600); +- +- window.addWindowListener(new WindowAdapter() { +- public void windowClosed(WindowEvent e) { +- receiver.stop(); +- } +- }); +- +- try { +- receiver = new ImageReceiver(InetAddress.getByName("0.0.0.0"), getRemote().getPort(), getLocal().getPort(), width, +- height); +- LOGGER.debug("Receiving on:" + receiver.getLocalPort()); +- } catch (UnknownHostException e) { +- e.printStackTrace(); +- } +- +- jp.add(receiver); +- receiver.setVisible(true); +- window.setAlwaysOnTop(true); +- window.setVisible(true); +- } +- } +- +- /** +- * Starts transmission and for NAT Traversal reasons start receiving also. +- */ +- public void startTrasmit() { +- new Thread(transmitter).start(); +- } +- +- /** +- * Set transmit activity. If the active is true, the instance should trasmit. +- * If it is set to false, the instance should pause transmit. +- * +- * @param active active state +- */ +- public void setTrasmit(boolean active) { +- transmitter.setTransmit(true); +- } +- +- /** +- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf +- */ +- public void startReceive() { +- // Do nothing +- } +- +- /** +- * Stops transmission and for NAT Traversal reasons stop receiving also. +- */ +- public void stopTrasmit() { +- if (transmitter != null) { +- transmitter.stop(); +- } +- } +- +- /** +- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf +- */ +- public void stopReceive() { +- if (receiver != null) { +- receiver.stop(); +- } +- } +- +- /** +- * Obtain a free port we can use. +- * +- * @return A free port number. +- */ +- protected int getFreePort() { +- ServerSocket ss; +- int freePort = 0; +- +- for (int i = 0; i < 10; i++) { +- freePort = (int) (10000 + Math.round(Math.random() * 10000)); +- freePort = freePort % 2 == 0 ? freePort : freePort + 1; +- try { +- ss = new ServerSocket(freePort); +- freePort = ss.getLocalPort(); +- ss.close(); +- return freePort; +- } catch (IOException e) { +- e.printStackTrace(); +- } +- } +- try { +- ss = new ServerSocket(0); +- freePort = ss.getLocalPort(); +- ss.close(); +- } catch (IOException e) { +- e.printStackTrace(); +- } +- return freePort; +- } +- +- public void setEncoder(ImageEncoder encoder) { +- if (encoder != null) { +- this.transmitter.setEncoder(encoder); +- } +- } +- +- public void setDecoder(ImageDecoder decoder) { +- if (decoder != null) { +- this.receiver.setDecoder(decoder); +- } +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageTransmitter.java (working copy) +@@ -1,204 +0,0 @@ +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
+-
+-import java.awt.AWTException;
+-import java.awt.Rectangle;
+-import java.awt.Robot;
+-import java.awt.image.BufferedImage;
+-import java.awt.image.PixelGrabber;
+-import java.io.ByteArrayOutputStream;
+-import java.io.IOException;
+-import java.net.DatagramPacket;
+-import java.net.DatagramSocket;
+-import java.net.InetAddress;
+-import java.util.Arrays;
+-
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-
+-/**
+- * UDP Image Receiver.
+- * It uses PNG Tiles into UDP packets.
+- *
+- * @author Thiago Rocha Camargo
+- */
+-public class ImageTransmitter implements Runnable {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(ImageTransmitter.class);
+-
+- private Robot robot;
+- private InetAddress localHost;
+- private InetAddress remoteHost;
+- private int localPort;
+- private int remotePort;
+- public static final int tileWidth = 25;
+- private boolean on = true;
+- private boolean transmit = false;
+- private DatagramSocket socket;
+- private Rectangle area;
+- private int tiles[][][];
+- private int maxI;
+- private int maxJ;
+- private ImageEncoder encoder;
+- public final static int KEYFRAME = 10;
+-
+- public ImageTransmitter(DatagramSocket socket, InetAddress remoteHost, int remotePort, Rectangle area) {
+-
+- try {
+- robot = new Robot();
+-
+- maxI = (int) Math.ceil(area.getWidth() / tileWidth);
+- maxJ = (int) Math.ceil(area.getHeight() / tileWidth);
+-
+- tiles = new int[maxI][maxJ][tileWidth * tileWidth];
+-
+- this.area = area;
+- this.socket = socket;
+- localHost = socket.getLocalAddress();
+- localPort = socket.getLocalPort();
+- this.remoteHost = remoteHost;
+- this.remotePort = remotePort;
+- this.encoder = new DefaultEncoder();
+-
+- transmit = true;
+-
+- }
+- catch (AWTException e) {
+- e.printStackTrace();
+- }
+-
+- }
+-
+- public void start() {
+- byte buf[] = new byte[1024];
+- final DatagramPacket p = new DatagramPacket(buf, 1024);
+-
+- int keyframe = 0;
+-
+- while (on) {
+- if (transmit) {
+-
+- BufferedImage capture = robot.createScreenCapture(area);
+-
+- QuantizeFilter filter = new QuantizeFilter();
+- capture = filter.filter(capture, null);
+-
+- long trace = System.currentTimeMillis();
+-
+- if (++keyframe > KEYFRAME) {
+- keyframe = 0;
+- }
+- LOGGER.debug("KEYFRAME:" + keyframe);
+-
+- for (int i = 0; i < maxI; i++) {
+- for (int j = 0; j < maxJ; j++) {
+-
+- final BufferedImage bufferedImage = capture.getSubimage(i * tileWidth, j * tileWidth, tileWidth, tileWidth);
+-
+- int pixels[] = new int[tileWidth * tileWidth];
+-
+- PixelGrabber pg = new PixelGrabber(bufferedImage, 0, 0, tileWidth, tileWidth, pixels, 0, tileWidth);
+-
+- try {
+- if (pg.grabPixels()) {
+-
+- if (keyframe == KEYFRAME || !Arrays.equals(tiles[i][j], pixels)) {
+-
+- ByteArrayOutputStream baos = encoder.encode(bufferedImage);
+-
+- if (baos != null) {
+-
+- try {
+-
+- Thread.sleep(1);
+-
+- baos.write(i);
+- baos.write(j);
+-
+- byte[] bytesOut = baos.toByteArray();
+-
+- if (bytesOut.length > 1000)
+- LOGGER.error("Bytes out > 1000. Equals " + bytesOut.length);
+-
+- p.setData(bytesOut);
+- p.setAddress(remoteHost);
+- p.setPort(remotePort);
+-
+- try {
+- socket.send(p);
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+-
+- tiles[i][j] = pixels;
+-
+- }
+- catch (Exception e) {
+- }
+-
+- }
+-
+- }
+-
+- }
+- }
+- catch (InterruptedException e) {
+- e.printStackTrace();
+- }
+- }
+- }
+-
+- trace = (System.currentTimeMillis() - trace);
+- LOGGER.debug("Loop Time:" + trace);
+-
+- if (trace < 500) {
+- try {
+- Thread.sleep(500 - trace);
+- }
+- catch (InterruptedException e) {
+- e.printStackTrace();
+- }
+- }
+- }
+- }
+- }
+-
+- public void run() {
+- start();
+- }
+-
+- /**
+- * Set Transmit Enabled/Disabled
+- *
+- * @param transmit boolean Enabled/Disabled
+- */
+- public void setTransmit(boolean transmit) {
+- this.transmit = transmit;
+- }
+-
+- /**
+- * Get the encoder used to encode Images Tiles
+- *
+- * @return encoder
+- */
+- public ImageEncoder getEncoder() {
+- return encoder;
+- }
+-
+- /**
+- * Set the encoder used to encode Image Tiles
+- *
+- * @param encoder encoder
+- */
+- public void setEncoder(ImageEncoder encoder) {
+- this.encoder = encoder;
+- }
+-
+- /**
+- * Stops Transmitter
+- */
+- public void stop() {
+- this.transmit = false;
+- this.on = false;
+- socket.close();
+- }
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageEncoder.java (working copy) +@@ -1,13 +0,0 @@ +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import java.awt.image.BufferedImage; +-import java.io.ByteArrayOutputStream; +- +-/** +- * Image Encoder Interface use this interface if you want to change the default encoder +- * +- * @author Thiago Rocha Camargo +- */ +-public interface ImageEncoder { +- public ByteArrayOutputStream encode(BufferedImage bufferedImage); +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/PixelUtils.java (working copy) +@@ -1,223 +0,0 @@ +-/* +-Copyright 2006 Jerry Huxtable +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import java.awt.*; +-import java.util.Random; +- +-/** +- * Some more useful math functions for image processing. +- * These are becoming obsolete as we move to Java2D. Use MiscComposite instead. +- */ +-public class PixelUtils { +- +- public final static int REPLACE = 0; +- public final static int NORMAL = 1; +- public final static int MIN = 2; +- public final static int MAX = 3; +- public final static int ADD = 4; +- public final static int SUBTRACT = 5; +- public final static int DIFFERENCE = 6; +- public final static int MULTIPLY = 7; +- public final static int HUE = 8; +- public final static int SATURATION = 9; +- public final static int VALUE = 10; +- public final static int COLOR = 11; +- public final static int SCREEN = 12; +- public final static int AVERAGE = 13; +- public final static int OVERLAY = 14; +- public final static int CLEAR = 15; +- public final static int EXCHANGE = 16; +- public final static int DISSOLVE = 17; +- public final static int DST_IN = 18; +- public final static int ALPHA = 19; +- public final static int ALPHA_TO_GRAY = 20; +- +- private static Random randomGenerator = new Random(); +- +- /** +- * Clamp a value to the range 0..255 +- */ +- public static int clamp(int c) { +- if (c < 0) +- return 0; +- if (c > 255) +- return 255; +- return c; +- } +- +- public static int interpolate(int v1, int v2, float f) { +- return clamp((int)(v1+f*(v2-v1))); +- } +- +- public static int brightness(int rgb) { +- int r = (rgb >> 16) & 0xff; +- int g = (rgb >> 8) & 0xff; +- int b = rgb & 0xff; +- return (r+g+b)/3; +- } +- +- public static boolean nearColors(int rgb1, int rgb2, int tolerance) { +- int r1 = (rgb1 >> 16) & 0xff; +- int g1 = (rgb1 >> 8) & 0xff; +- int b1 = rgb1 & 0xff; +- int r2 = (rgb2 >> 16) & 0xff; +- int g2 = (rgb2 >> 8) & 0xff; +- int b2 = rgb2 & 0xff; +- return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance; +- } +- +- private final static float hsb1[] = new float[3];//FIXME-not thread safe +- private final static float hsb2[] = new float[3];//FIXME-not thread safe +- +- // Return rgb1 painted onto rgb2 +- public static int combinePixels(int rgb1, int rgb2, int op) { +- return combinePixels(rgb1, rgb2, op, 0xff); +- } +- +- public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) { +- return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha); +- } +- +- public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) { +- if (op == REPLACE) +- return rgb1; +- int a1 = (rgb1 >> 24) & 0xff; +- int r1 = (rgb1 >> 16) & 0xff; +- int g1 = (rgb1 >> 8) & 0xff; +- int b1 = rgb1 & 0xff; +- int a2 = (rgb2 >> 24) & 0xff; +- int r2 = (rgb2 >> 16) & 0xff; +- int g2 = (rgb2 >> 8) & 0xff; +- int b2 = rgb2 & 0xff; +- +- switch (op) { +- case NORMAL: +- break; +- case MIN: +- r1 = Math.min(r1, r2); +- g1 = Math.min(g1, g2); +- b1 = Math.min(b1, b2); +- break; +- case MAX: +- r1 = Math.max(r1, r2); +- g1 = Math.max(g1, g2); +- b1 = Math.max(b1, b2); +- break; +- case ADD: +- r1 = clamp(r1+r2); +- g1 = clamp(g1+g2); +- b1 = clamp(b1+b2); +- break; +- case SUBTRACT: +- r1 = clamp(r2-r1); +- g1 = clamp(g2-g1); +- b1 = clamp(b2-b1); +- break; +- case DIFFERENCE: +- r1 = clamp(Math.abs(r1-r2)); +- g1 = clamp(Math.abs(g1-g2)); +- b1 = clamp(Math.abs(b1-b2)); +- break; +- case MULTIPLY: +- r1 = clamp(r1*r2/255); +- g1 = clamp(g1*g2/255); +- b1 = clamp(b1*b2/255); +- break; +- case DISSOLVE: +- if ((randomGenerator.nextInt() & 0xff) <= a1) { +- r1 = r2; +- g1 = g2; +- b1 = b2; +- } +- break; +- case AVERAGE: +- r1 = (r1+r2)/2; +- g1 = (g1+g2)/2; +- b1 = (b1+b2)/2; +- break; +- case HUE: +- case SATURATION: +- case VALUE: +- case COLOR: +- Color.RGBtoHSB(r1, g1, b1, hsb1); +- Color.RGBtoHSB(r2, g2, b2, hsb2); +- switch (op) { +- case HUE: +- hsb2[0] = hsb1[0]; +- break; +- case SATURATION: +- hsb2[1] = hsb1[1]; +- break; +- case VALUE: +- hsb2[2] = hsb1[2]; +- break; +- case COLOR: +- hsb2[0] = hsb1[0]; +- hsb2[1] = hsb1[1]; +- break; +- } +- rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]); +- r1 = (rgb1 >> 16) & 0xff; +- g1 = (rgb1 >> 8) & 0xff; +- b1 = rgb1 & 0xff; +- break; +- case SCREEN: +- r1 = 255 - ((255 - r1) * (255 - r2)) / 255; +- g1 = 255 - ((255 - g1) * (255 - g2)) / 255; +- b1 = 255 - ((255 - b1) * (255 - b2)) / 255; +- break; +- case OVERLAY: +- int m, s; +- s = 255 - ((255 - r1) * (255 - r2)) / 255; +- m = r1 * r2 / 255; +- r1 = (s * r1 + m * (255 - r1)) / 255; +- s = 255 - ((255 - g1) * (255 - g2)) / 255; +- m = g1 * g2 / 255; +- g1 = (s * g1 + m * (255 - g1)) / 255; +- s = 255 - ((255 - b1) * (255 - b2)) / 255; +- m = b1 * b2 / 255; +- b1 = (s * b1 + m * (255 - b1)) / 255; +- break; +- case CLEAR: +- r1 = g1 = b1 = 0xff; +- break; +- case DST_IN: +- r1 = clamp((r2*a1)/255); +- g1 = clamp((g2*a1)/255); +- b1 = clamp((b2*a1)/255); +- a1 = clamp((a2*a1)/255); +- return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1; +- case ALPHA: +- a1 = a1*a2/255; +- return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2; +- case ALPHA_TO_GRAY: +- int na = 255-a1; +- return (a1 << 24) | (na << 16) | (na << 8) | na; +- } +- if (extraAlpha != 0xff || a1 != 0xff) { +- a1 = a1*extraAlpha/255; +- int a3 = (255-a1)*a2/255; +- r1 = clamp((r1*a1+r2*a3)/255); +- g1 = clamp((g1*a1+g2*a3)/255); +- b1 = clamp((b1*a1+b2*a3)/255); +- a1 = clamp(a1+a3); +- } +- return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1; +- } +- +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/Quantizer.java (working copy) +@@ -1,53 +0,0 @@ +-/* +-Copyright 2006 Jerry Huxtable +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-/** +- * The interface for an image quantizer. The addColor method is called (repeatedly +- * if necessary) with all the image pixels. A color table can then be returned by +- * calling the buildColorTable method. +- */ +-public interface Quantizer { +- /** +- * Initialize the quantizer. This should be called before adding any pixels. +- * @param numColors the number of colors we're quantizing to. +- */ +- public void setup(int numColors); +- +- /** +- * Add pixels to the quantizer. +- * @param pixels the array of ARGB pixels +- * @param offset the offset into the array +- * @param count the count of pixels +- */ +- public void addPixels(int[] pixels, int offset, int count); +- +- /** +- * Build a color table from the added pixels. +- * @return an array of ARGB pixels representing a color table +- */ +- public int[] buildColorTable(); +- +- /** +- * Using the previously-built color table, return the index into that table for a pixel. +- * This is guaranteed to return a valid index - returning the index of a color closer +- * to that requested if necessary. +- * @param rgb the pixel to find +- * @return the pixel's index in the color table +- */ +- public int getIndexForColor(int rgb); +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultEncoder.java (working copy) +@@ -1,24 +0,0 @@ +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import javax.imageio.ImageIO; +-import java.awt.image.BufferedImage; +-import java.io.ByteArrayOutputStream; +-import java.io.IOException; +- +-/** +- * Implements a default PNG Encoder +- */ +-public class DefaultEncoder implements ImageEncoder{ +- +- public ByteArrayOutputStream encode(BufferedImage bufferedImage) { +- ByteArrayOutputStream baos = new ByteArrayOutputStream(); +- try { +- ImageIO.write(bufferedImage, "png", baos); +- } +- catch (IOException e) { +- e.printStackTrace(); +- baos = null; +- } +- return baos; +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/QuantizeFilter.java (working copy) +@@ -1,178 +0,0 @@ +-/* +-Copyright 2006 Jerry Huxtable +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import java.awt.*; +- +-/** +- * A filter which quantizes an image to a set number of colors - useful for producing +- * images which are to be encoded using an index color model. The filter can perform +- * Floyd-Steinberg error-diffusion dithering if required. At present, the quantization +- * is done using an octtree algorithm but I eventually hope to add more quantization +- * methods such as median cut. Note: at present, the filter produces an image which +- * uses the RGB color model (because the application it was written for required it). +- * I hope to extend it to produce an IndexColorModel by request. +- */ +-public class QuantizeFilter extends WholeImageFilter { +- +- /** +- * Floyd-Steinberg dithering matrix. +- */ +- protected final static int[] matrix = { +- 0, 0, 0, +- 0, 0, 7, +- 3, 5, 1, +- }; +- private int sum = 3+5+7+1; +- +- private boolean dither; +- private int numColors = 256; +- private boolean serpentine = true; +- +- /** +- * Set the number of colors to quantize to. +- * @param numColors the number of colors. The default is 256. +- */ +- public void setNumColors(int numColors) { +- this.numColors = Math.min(Math.max(numColors, 8), 256); +- } +- +- /** +- * Get the number of colors to quantize to. +- * @return the number of colors. +- */ +- public int getNumColors() { +- return numColors; +- } +- +- /** +- * Set whether to use dithering or not. If not, the image is posterized. +- * @param dither true to use dithering +- */ +- public void setDither(boolean dither) { +- this.dither = dither; +- } +- +- /** +- * Return the dithering setting +- * @return the current setting +- */ +- public boolean getDither() { +- return dither; +- } +- +- /** +- * Set whether to use a serpentine pattern for return or not. This can reduce 'avalanche' artifacts in the output. +- * @param serpentine true to use serpentine pattern +- */ +- public void setSerpentine(boolean serpentine) { +- this.serpentine = serpentine; +- } +- +- /** +- * Return the serpentine setting +- * @return the current setting +- */ +- public boolean getSerpentine() { +- return serpentine; +- } +- +- public void quantize(int[] inPixels, int[] outPixels, int width, int height, int numColors, boolean dither, boolean serpentine) { +- int count = width*height; +- Quantizer quantizer = new OctTreeQuantizer(); +- quantizer.setup(numColors); +- quantizer.addPixels(inPixels, 0, count); +- int[] table = quantizer.buildColorTable(); +- +- if (!dither) { +- for (int i = 0; i < count; i++) +- outPixels[i] = table[quantizer.getIndexForColor(inPixels[i])]; +- } else { +- int index = 0; +- for (int y = 0; y < height; y++) { +- boolean reverse = serpentine && (y & 1) == 1; +- int direction; +- if (reverse) { +- index = y*width+width-1; +- direction = -1; +- } else { +- index = y*width; +- direction = 1; +- } +- for (int x = 0; x < width; x++) { +- int rgb1 = inPixels[index]; +- int rgb2 = table[quantizer.getIndexForColor(rgb1)]; +- +- outPixels[index] = rgb2; +- +- int r1 = (rgb1 >> 16) & 0xff; +- int g1 = (rgb1 >> 8) & 0xff; +- int b1 = rgb1 & 0xff; +- +- int r2 = (rgb2 >> 16) & 0xff; +- int g2 = (rgb2 >> 8) & 0xff; +- int b2 = rgb2 & 0xff; +- +- int er = r1-r2; +- int eg = g1-g2; +- int eb = b1-b2; +- +- for (int i = -1; i <= 1; i++) { +- int iy = i+y; +- if (0 <= iy && iy < height) { +- for (int j = -1; j <= 1; j++) { +- int jx = j+x; +- if (0 <= jx && jx < width) { +- int w; +- if (reverse) +- w = matrix[(i+1)*3-j+1]; +- else +- w = matrix[(i+1)*3+j+1]; +- if (w != 0) { +- int k = reverse ? index - j : index + j; +- rgb1 = inPixels[k]; +- r1 = (rgb1 >> 16) & 0xff; +- g1 = (rgb1 >> 8) & 0xff; +- b1 = rgb1 & 0xff; +- r1 += er * w/sum; +- g1 += eg * w/sum; +- b1 += eb * w/sum; +- inPixels[k] = (PixelUtils.clamp(r1) << 16) | (PixelUtils.clamp(g1) << 8) | PixelUtils.clamp(b1); +- } +- } +- } +- } +- } +- index += direction; +- } +- } +- } +- } +- +- protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { +- int[] outPixels = new int[width*height]; +- +- quantize(inPixels, outPixels, width, height, numColors, dither, serpentine); +- +- return outPixels; +- } +- +- public String toString() { +- return "Colors/Quantize..."; +- } +- +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageReceiver.java (working copy) +@@ -1,150 +0,0 @@ +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api;
+-
+-import java.awt.*;
+-import java.awt.image.BufferedImage;
+-import java.io.ByteArrayInputStream;
+-import java.io.IOException;
+-import java.net.DatagramPacket;
+-import java.net.DatagramSocket;
+-import java.net.InetAddress;
+-import java.net.SocketException;
+-
+-/**
+- * UDP Image Receiver.
+- * It uses PNG Tiles into UDP packets.
+- *
+- * @author Thiago Rocha Camargo
+- */
+-public class ImageReceiver extends Canvas {
+-
+- private boolean on = true;
+- private DatagramSocket socket;
+- private BufferedImage tiles[][];
+- private static final int tileWidth = ImageTransmitter.tileWidth;
+- private InetAddress localHost;
+- private InetAddress remoteHost;
+- private int localPort;
+- private int remotePort;
+- private ImageDecoder decoder;
+-
+- public ImageReceiver(final InetAddress remoteHost, final int remotePort, final int localPort, int width, int height) {
+- tiles = new BufferedImage[width][height];
+-
+- try {
+-
+- socket = new DatagramSocket(localPort);
+- localHost = socket.getLocalAddress();
+- this.remoteHost = remoteHost;
+- this.remotePort = remotePort;
+- this.localPort = localPort;
+- this.decoder = new DefaultDecoder();
+-
+- new Thread(new Runnable() {
+- public void run() {
+- byte buf[] = new byte[1024];
+- DatagramPacket p = new DatagramPacket(buf, 1024);
+- try {
+- while (on) {
+- socket.receive(p);
+-
+- int length = p.getLength();
+-
+- BufferedImage bufferedImage = decoder.decode(new ByteArrayInputStream(p.getData(), 0, length - 2));
+-
+- if (bufferedImage != null) {
+-
+- int x = p.getData()[length - 2];
+- int y = p.getData()[length - 1];
+-
+- drawTile(x, y, bufferedImage);
+-
+- }
+-
+- }
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- }
+- }).start();
+-
+- new Thread(new Runnable() {
+- public void run() {
+- byte buf[] = new byte[1024];
+- DatagramPacket p = new DatagramPacket(buf, 1024);
+- try {
+- while (on) {
+-
+- p.setAddress(remoteHost);
+- p.setPort(remotePort);
+- socket.send(p);
+-
+- try {
+- Thread.sleep(1000);
+- }
+- catch (InterruptedException e) {
+- e.printStackTrace();
+- }
+-
+- }
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- }
+- }).start();
+-
+- }
+- catch (SocketException e) {
+- e.printStackTrace();
+- }
+- this.setSize(width, height);
+- }
+-
+- public InetAddress getLocalHost() {
+- return localHost;
+- }
+-
+- public InetAddress getRemoteHost() {
+- return remoteHost;
+- }
+-
+- public int getLocalPort() {
+- return localPort;
+- }
+-
+- public int getRemotePort() {
+- return remotePort;
+- }
+-
+- public DatagramSocket getDatagramSocket() {
+- return socket;
+- }
+-
+- public void drawTile(int x, int y, BufferedImage bufferedImage) {
+- tiles[x][y] = bufferedImage;
+- //repaint(x * tileWidth, y * tileWidth, tileWidth, tileWidth);
+- this.getGraphics().drawImage(bufferedImage, tileWidth * x, tileWidth * y, this);
+- }
+-
+- public void paint(Graphics g) {
+- for (int i = 0; i < tiles.length; i++) {
+- for (int j = 0; j < tiles[0].length; j++) {
+- g.drawImage(tiles[i][j], tileWidth * i, tileWidth * j, this);
+- }
+- }
+- }
+-
+- public ImageDecoder getDecoder() {
+- return decoder;
+- }
+-
+- public void setDecoder(ImageDecoder decoder) {
+- this.decoder = decoder;
+- }
+-
+- public void stop(){
+- this.on=false;
+- socket.close();
+- }
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/WholeImageFilter.java (working copy) +@@ -1,86 +0,0 @@ +-/* +-Copyright 2006 Jerry Huxtable +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import java.awt.*; +-import java.awt.image.BufferedImage; +-import java.awt.image.ColorModel; +-import java.awt.image.WritableRaster; +- +-/** +- * A filter which acts as a superclass for filters which need to have the whole image in memory +- * to do their stuff. +- */ +-public abstract class WholeImageFilter extends AbstractBufferedImageOp { +- +- /** +- * The output image bounds. +- */ +- protected Rectangle transformedSpace; +- +- /** +- * The input image bounds. +- */ +- protected Rectangle originalSpace; +- +- /** +- * Construct a WholeImageFilter. +- */ +- public WholeImageFilter() { +- } +- +- public BufferedImage filter( BufferedImage src, BufferedImage dst ) { +- int width = src.getWidth(); +- int height = src.getHeight(); +- int type = src.getType(); +- WritableRaster srcRaster = src.getRaster(); +- +- originalSpace = new Rectangle(0, 0, width, height); +- transformedSpace = new Rectangle(0, 0, width, height); +- transformSpace(transformedSpace); +- +- if ( dst == null ) { +- ColorModel dstCM = src.getColorModel(); +- dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(transformedSpace.width, transformedSpace.height), dstCM.isAlphaPremultiplied(), null); +- } +- WritableRaster dstRaster = dst.getRaster(); +- +- int[] inPixels = getRGB( src, 0, 0, width, height, null ); +- inPixels = filterPixels( width, height, inPixels, transformedSpace ); +- setRGB( dst, 0, 0, transformedSpace.width, transformedSpace.height, inPixels ); +- +- return dst; +- } +- +- /** +- * Calculate output bounds for given input bounds. +- * @param rect input and output rectangle +- */ +- protected void transformSpace(Rectangle rect) { +- } +- +- /** +- * Actually filter the pixels. +- * @param width the image width +- * @param height the image height +- * @param inPixels the image pixels +- * @param transformedSpace the output bounds +- * @return the output pixels +- */ +- protected abstract int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ); +-} +- +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/AbstractBufferedImageOp.java (working copy) +@@ -1,98 +0,0 @@ +-/* +-Copyright 2006 Jerry Huxtable +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import java.awt.*; +-import java.awt.geom.Point2D; +-import java.awt.geom.Rectangle2D; +-import java.awt.image.BufferedImage; +-import java.awt.image.BufferedImageOp; +-import java.awt.image.ColorModel; +- +-/** +- * A convenience class which implements those methods of BufferedImageOp which are rarely changed. +- */ +-public abstract class AbstractBufferedImageOp implements BufferedImageOp, Cloneable { +- +- public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { +- if ( dstCM == null ) +- dstCM = src.getColorModel(); +- return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dstCM.isAlphaPremultiplied(), null); +- } +- +- public Rectangle2D getBounds2D( BufferedImage src ) { +- return new Rectangle(0, 0, src.getWidth(), src.getHeight()); +- } +- +- public Point2D getPoint2D( Point2D srcPt, Point2D dstPt ) { +- if ( dstPt == null ) +- dstPt = new Point2D.Double(); +- dstPt.setLocation( srcPt.getX(), srcPt.getY() ); +- return dstPt; +- } +- +- public RenderingHints getRenderingHints() { +- return null; +- } +- +- /** +- * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance +- * penalty of BufferedImage.getRGB unmanaging the image. +- * @param image a BufferedImage object +- * @param x the left edge of the pixel block +- * @param y the right edge of the pixel block +- * @param width the width of the pixel arry +- * @param height the height of the pixel arry +- * @param pixels the array to hold the returned pixels. May be null. +- * @return the pixels +- * @see #setRGB +- */ +- public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) { +- int type = image.getType(); +- if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB ) +- return (int [])image.getRaster().getDataElements( x, y, width, height, pixels ); +- return image.getRGB( x, y, width, height, pixels, 0, width ); +- } +- +- /** +- * A convenience method for setting ARGB pixels in an image. This tries to avoid the performance +- * penalty of BufferedImage.setRGB unmanaging the image. +- * @param image a BufferedImage object +- * @param x the left edge of the pixel block +- * @param y the right edge of the pixel block +- * @param width the width of the pixel arry +- * @param height the height of the pixel arry +- * @param pixels the array of pixels to set +- * @see #getRGB +- */ +- public void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) { +- int type = image.getType(); +- if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB ) +- image.getRaster().setDataElements( x, y, width, height, pixels ); +- else +- image.setRGB( x, y, width, height, pixels, 0, width ); +- } +- +- public Object clone() { +- try { +- return super.clone(); +- } +- catch ( CloneNotSupportedException e ) { +- return null; +- } +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/ImageDecoder.java (working copy) +@@ -1,15 +0,0 @@ +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import java.awt.image.BufferedImage; +-import java.io.ByteArrayInputStream; +-import java.io.IOException; +- +-/** +- * Image Decoder Interface use this interface if you want to change the default decoder +- * +- * @author Thiago Rocha Camargo +- */ +-public interface ImageDecoder { +- +- public BufferedImage decode(ByteArrayInputStream stream) throws IOException; +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/OctTreeQuantizer.java (working copy) +@@ -1,287 +0,0 @@ +-/* +-Copyright 2006 Jerry Huxtable +- +-Licensed under the Apache License, Version 2.0 (the "License"); +-you may not use this file except in compliance with the License. +-You may obtain a copy of the License at +- +- http://www.apache.org/licenses/LICENSE-2.0 +- +-Unless required by applicable law or agreed to in writing, software +-distributed under the License is distributed on an "AS IS" BASIS, +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-See the License for the specific language governing permissions and +-limitations under the License. +-*/ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import java.io.PrintStream; +-import java.util.Vector; +- +-import org.jivesoftware.smackx.jingle.SmackLogger; +- +-/** +- * An image Quantizer based on the Octree algorithm. This is a very basic implementation +- * at present and could be much improved by picking the nodes to reduce more carefully +- * (i.e. not completely at random) when I get the time. +- */ +-public class OctTreeQuantizer implements Quantizer { +- +- private static final SmackLogger LOGGER = SmackLogger.getLogger(OctTreeQuantizer.class); +- +- /** +- * The greatest depth the tree is allowed to reach +- */ +- final static int MAX_LEVEL = 5; +- +- /** +- * An Octtree node. +- */ +- class OctTreeNode { +- int children; +- int level; +- OctTreeNode parent; +- OctTreeNode leaf[] = new OctTreeNode[8]; +- boolean isLeaf; +- int count; +- int totalRed; +- int totalGreen; +- int totalBlue; +- int index; +- +- /** +- * A debugging method which prints the tree out. +- */ +- public void list(PrintStream s, int level) { +- String indentStr = ""; +- for (int i = 0; i < level; i++) +- indentStr += " "; +- if (count == 0) +- LOGGER.debug(indentStr + index + ": count=" + count); +- else +- LOGGER.debug(indentStr + index + ": count=" + count + " red=" + (totalRed/count) + " green=" + (totalGreen / count) + " blue=" + (totalBlue / count)); +- for (int i = 0; i < 8; i++) +- if (leaf[i] != null) +- leaf[i].list(s, level+2); +- } +- } +- +- private int nodes = 0; +- private OctTreeNode root; +- private int reduceColors; +- private int maximumColors; +- private int colors = 0; +- private Vector[] colorList; +- +- public OctTreeQuantizer() { +- setup(256); +- colorList = new Vector[MAX_LEVEL+1]; +- for (int i = 0; i < MAX_LEVEL+1; i++) +- colorList[i] = new Vector(); +- root = new OctTreeNode(); +- } +- +- /** +- * Initialize the quantizer. This should be called before adding any pixels. +- * @param numColors the number of colors we're quantizing to. +- */ +- public void setup(int numColors) { +- maximumColors = numColors; +- reduceColors = Math.max(512, numColors * 2); +- } +- +- /** +- * Add pixels to the quantizer. +- * @param pixels the array of ARGB pixels +- * @param offset the offset into the array +- * @param count the count of pixels +- */ +- public void addPixels(int[] pixels, int offset, int count) { +- for (int i = 0; i < count; i++) { +- insertColor(pixels[i+offset]); +- if (colors > reduceColors) +- reduceTree(reduceColors); +- } +- } +- +- /** +- * Get the color table index for a color. +- * @param rgb the color +- * @return the index +- */ +- public int getIndexForColor(int rgb) { +- int red = (rgb >> 16) & 0xff; +- int green = (rgb >> 8) & 0xff; +- int blue = rgb & 0xff; +- +- OctTreeNode node = root; +- +- for (int level = 0; level <= MAX_LEVEL; level++) { +- OctTreeNode child; +- int bit = 0x80 >> level; +- +- int index = 0; +- if ((red & bit) != 0) +- index += 4; +- if ((green & bit) != 0) +- index += 2; +- if ((blue & bit) != 0) +- index += 1; +- +- child = node.leaf[index]; +- +- if (child == null) +- return node.index; +- else if (child.isLeaf) +- return child.index; +- else +- node = child; +- } +- LOGGER.debug("getIndexForColor failed"); +- return 0; +- } +- +- private void insertColor(int rgb) { +- int red = (rgb >> 16) & 0xff; +- int green = (rgb >> 8) & 0xff; +- int blue = rgb & 0xff; +- +- OctTreeNode node = root; +- +-// LOGGER.debug("insertColor="+Integer.toHexString(rgb)); +- for (int level = 0; level <= MAX_LEVEL; level++) { +- OctTreeNode child; +- int bit = 0x80 >> level; +- +- int index = 0; +- if ((red & bit) != 0) +- index += 4; +- if ((green & bit) != 0) +- index += 2; +- if ((blue & bit) != 0) +- index += 1; +- +- child = node.leaf[index]; +- +- if (child == null) { +- node.children++; +- +- child = new OctTreeNode(); +- child.parent = node; +- node.leaf[index] = child; +- node.isLeaf = false; +- nodes++; +- colorList[level].addElement(child); +- +- if (level == MAX_LEVEL) { +- child.isLeaf = true; +- child.count = 1; +- child.totalRed = red; +- child.totalGreen = green; +- child.totalBlue = blue; +- child.level = level; +- colors++; +- return; +- } +- +- node = child; +- } else if (child.isLeaf) { +- child.count++; +- child.totalRed += red; +- child.totalGreen += green; +- child.totalBlue += blue; +- return; +- } else +- node = child; +- } +- LOGGER.debug("insertColor failed"); +- } +- +- private void reduceTree(int numColors) { +- for (int level = MAX_LEVEL-1; level >= 0; level--) { +- Vector v = colorList[level]; +- if (v != null && v.size() > 0) { +- for (int j = 0; j < v.size(); j++) { +- OctTreeNode node = (OctTreeNode)v.elementAt(j); +- if (node.children > 0) { +- for (int i = 0; i < 8; i++) { +- OctTreeNode child = node.leaf[i]; +- if (child != null) { +- if (!child.isLeaf) +- LOGGER.debug("not a leaf!"); +- node.count += child.count; +- node.totalRed += child.totalRed; +- node.totalGreen += child.totalGreen; +- node.totalBlue += child.totalBlue; +- node.leaf[i] = null; +- node.children--; +- colors--; +- nodes--; +- colorList[level+1].removeElement(child); +- } +- } +- node.isLeaf = true; +- colors++; +- if (colors <= numColors) +- return; +- } +- } +- } +- } +- +- LOGGER.debug("Unable to reduce the OctTree"); +- } +- +- /** +- * Build the color table. +- * @return the color table +- */ +- public int[] buildColorTable() { +- int[] table = new int[colors]; +- buildColorTable(root, table, 0); +- return table; +- } +- +- /** +- * A quick way to use the quantizer. Just create a table the right size and pass in the pixels. +- * @param inPixels the input colors +- * @param table the output color table +- */ +- public void buildColorTable(int[] inPixels, int[] table) { +- int count = inPixels.length; +- maximumColors = table.length; +- for (int i = 0; i < count; i++) { +- insertColor(inPixels[i]); +- if (colors > reduceColors) +- reduceTree(reduceColors); +- } +- if (colors > maximumColors) +- reduceTree(maximumColors); +- buildColorTable(root, table, 0); +- } +- +- private int buildColorTable(OctTreeNode node, int[] table, int index) { +- if (colors > maximumColors) +- reduceTree(maximumColors); +- +- if (node.isLeaf) { +- int count = node.count; +- table[index] = 0xff000000 | +- ((node.totalRed/count) << 16) | +- ((node.totalGreen/count) << 8) | +- node.totalBlue/count; +- node.index = index++; +- } else { +- for (int i = 0; i < 8; i++) { +- if (node.leaf[i] != null) { +- node.index = index; +- index = buildColorTable(node.leaf[i], table, index); +- } +- } +- } +- return index; +- } +- +-} +- +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/api/DefaultDecoder.java (working copy) +@@ -1,16 +0,0 @@ +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare.api; +- +-import javax.imageio.ImageIO; +-import java.awt.image.BufferedImage; +-import java.io.ByteArrayInputStream; +-import java.io.IOException; +- +-/** +- * Implements a default PNG decoder. +- */ +-public class DefaultDecoder implements ImageDecoder { +- +- public BufferedImage decode(ByteArrayInputStream stream) throws IOException { +- return ImageIO.read(stream); +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/sshare/ScreenShareMediaManager.java (working copy) +@@ -1,115 +0,0 @@ +-/** +- * $RCSfile: ScreenShareMediaManager.java,v $ +- * $Revision: 1.3 $ +- * $Date: 25/12/2006 +- * <p/> +- * Copyright 2003-2006 Jive Software. +- * <p/> +- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * <p/> +- * http://www.apache.org/licenses/LICENSE-2.0 +- * <p/> +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.sshare; +- +-import org.jivesoftware.smackx.jingle.JingleSession; +-import org.jivesoftware.smackx.jingle.media.JingleMediaManager; +-import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +-import org.jivesoftware.smackx.jingle.media.PayloadType; +-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageDecoder; +-import org.jivesoftware.smackx.jingle.mediaimpl.sshare.api.ImageEncoder; +-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; +-import org.jivesoftware.smackx.jingle.nat.TransportCandidate; +- +-import java.util.ArrayList; +-import java.util.List; +- +-/** +- * Implements a JingleMediaManager for ScreenSharing. +- * It currently uses an Audio payload Type. Which needs to be fixed in the next version. +- * +- * @author Thiago Camargo +- */ +- +-public class ScreenShareMediaManager extends JingleMediaManager { +- +- public static final String MEDIA_NAME = "ScreenShare"; +- +- private List<PayloadType> payloads = new ArrayList<PayloadType>(); +- +- private ImageDecoder decoder = null; +- private ImageEncoder encoder = null; +- +- public ScreenShareMediaManager(JingleTransportManager transportManager) { +- super(transportManager); +- setupPayloads(); +- } +- +- /** +- * Setup API supported Payloads +- */ +- private void setupPayloads() { +- payloads.add(new PayloadType.Audio(30, "sshare")); +- } +- +- /** +- * Return all supported Payloads for this Manager. +- * +- * @return The Payload List +- */ +- public List<PayloadType> getPayloads() { +- return payloads; +- } +- +- /** +- * Returns a new JingleMediaSession +- * +- * @param payloadType payloadType +- * @param remote remote Candidate +- * @param local local Candidate +- * @return JingleMediaSession JingleMediaSession +- */ +- public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) { +- ScreenShareSession session = null; +- session = new ScreenShareSession(payloadType, remote, local, "Screen", jingleSession); +- if (encoder != null) { +- session.setEncoder(encoder); +- } +- if (decoder != null) { +- session.setDecoder(decoder); +- } +- return session; +- } +- +- public PayloadType getPreferredPayloadType() { +- return super.getPreferredPayloadType(); +- } +- +- public ImageDecoder getDecoder() { +- return decoder; +- } +- +- public void setDecoder(ImageDecoder decoder) { +- this.decoder = decoder; +- } +- +- public ImageEncoder getEncoder() { +- return encoder; +- } +- +- public void setEncoder(ImageEncoder encoder) { +- this.encoder = encoder; +- } +- +- public String getName() { +- return MEDIA_NAME; +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/multi/MultiMediaManager.java (working copy) +@@ -1,106 +0,0 @@ +-/** +- * $RCSfile: MultiMediaManager.java,v $ +- * $Revision: 1.3 $ +- * $Date: 25/12/2006 +- * <p/> +- * Copyright 2003-2006 Jive Software. +- * <p/> +- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * <p/> +- * http://www.apache.org/licenses/LICENSE-2.0 +- * <p/> +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-package org.jivesoftware.smackx.jingle.mediaimpl.multi; +- +-import org.jivesoftware.smackx.jingle.JingleSession; +-import org.jivesoftware.smackx.jingle.media.JingleMediaManager; +-import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +-import org.jivesoftware.smackx.jingle.media.PayloadType; +-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; +-import org.jivesoftware.smackx.jingle.nat.TransportCandidate; +- +-import java.util.ArrayList; +-import java.util.List; +- +-/** +- * Implements a MultiMediaManager using other JingleMediaManager implementations. +- * It supports every Codecs that JingleMediaManagers added has. +- * +- * @author Thiago Camargo +- */ +- +-public class MultiMediaManager extends JingleMediaManager { +- +- public static final String MEDIA_NAME = "Multi"; +- +- private List<JingleMediaManager> managers = new ArrayList<JingleMediaManager>(); +- +- private PayloadType preferredPayloadType = null; +- +- public MultiMediaManager(JingleTransportManager transportManager) { +- super(transportManager); +- } +- +- public void addMediaManager(JingleMediaManager manager) { +- managers.add(manager); +- } +- +- public void removeMediaManager(JingleMediaManager manager) { +- managers.remove(manager); +- } +- +- /** +- * Return all supported Payloads for this Manager. +- * +- * @return The Payload List +- */ +- public List<PayloadType> getPayloads() { +- List<PayloadType> list = new ArrayList<PayloadType>(); +- if (preferredPayloadType != null) list.add(preferredPayloadType); +- for (JingleMediaManager manager : managers) { +- for (PayloadType payloadType : manager.getPayloads()) { +- if (!list.contains(payloadType) && !payloadType.equals(preferredPayloadType)) +- list.add(payloadType); +- } +- } +- return list; +- } +- +- /** +- * Returns a new JingleMediaSession +- * +- * @param payloadType payloadType +- * @param remote remote Candidate +- * @param local local Candidate +- * @return JingleMediaSession JingleMediaSession +- */ +- public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) { +- for (JingleMediaManager manager : managers) { +- if (manager.getPayloads().contains(payloadType)) { +- return manager.createMediaSession(payloadType, remote, local, jingleSession); +- } +- } +- return null; +- } +- +- public PayloadType getPreferredPayloadType() { +- if (preferredPayloadType != null) return preferredPayloadType; +- return super.getPreferredPayloadType(); +- } +- +- public void setPreferredPayloadType(PayloadType preferredPayloadType) { +- this.preferredPayloadType = preferredPayloadType; +- } +- +- public String getName() { +- return MEDIA_NAME; +- } +-} +Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioMediaSession.java (working copy) +@@ -1,165 +0,0 @@ +-/**
+- * $RCSfile: AudioMediaSession.java,v $
+- * $Revision: 1.1 $
+- * $Date: 08/11/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
+-
+-import java.io.IOException;
+-import java.net.ServerSocket;
+-
+-import javax.media.MediaLocator;
+-
+-import org.jivesoftware.smackx.jingle.JingleSession;
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
+-import org.jivesoftware.smackx.jingle.media.PayloadType;
+-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
+-
+-/**
+- * This Class implements a complete JingleMediaSession.
+- * It sould be used to transmit and receive audio captured from the Mic.
+- * This Class should be automaticly controlled by JingleSession.
+- * But you could also use in any VOIP application.
+- * For better NAT Traversal support this implementation don't support only receive or only transmit.
+- * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
+- *
+- * @author Thiago Camargo
+- */
+-public class AudioMediaSession extends JingleMediaSession {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
+-
+- private AudioChannel audioChannel;
+-
+- /**
+- * Creates a org.jivesoftware.jingleaudio.jmf.AudioMediaSession with defined payload type, remote and local candidates
+- *
+- * @param payloadType Payload of the jmf
+- * @param remote the remote information. The candidate that the jmf will be sent to.
+- * @param local the local information. The candidate that will receive the jmf
+- * @param locator media locator
+- */
+- public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
+- final TransportCandidate local, String locator, JingleSession jingleSession) {
+- super(payloadType, remote, local, locator==null?"dsound://":locator,jingleSession);
+- initialize();
+- }
+-
+- /**
+- * Initialize the Audio Channel to make it able to send and receive audio
+- */
+- public void initialize() {
+-
+- String ip;
+- String localIp;
+- int localPort;
+- int remotePort;
+-
+- if (this.getLocal().getSymmetric() != null) {
+- ip = this.getLocal().getIp();
+- localIp = this.getLocal().getLocalIp();
+- localPort = getFreePort();
+- remotePort = this.getLocal().getSymmetric().getPort();
+-
+- LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
+-
+- }
+- else {
+- ip = this.getRemote().getIp();
+- localIp = this.getLocal().getLocalIp();
+- localPort = this.getLocal().getPort();
+- remotePort = this.getRemote().getPort();
+- }
+-
+- audioChannel = new AudioChannel(new MediaLocator(this.getMediaLocator()), localIp, ip, localPort, remotePort, AudioFormatUtils.getAudioFormat(this.getPayloadType()),this);
+- }
+-
+- /**
+- * Starts transmission and for NAT Traversal reasons start receiving also.
+- */
+- public void startTrasmit() {
+- audioChannel.start();
+- }
+-
+- /**
+- * Set transmit activity. If the active is true, the instance should trasmit.
+- * If it is set to false, the instance should pause transmit.
+- *
+- * @param active active state
+- */
+- public void setTrasmit(boolean active) {
+- audioChannel.setTrasmit(active);
+- }
+-
+- /**
+- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
+- */
+- public void startReceive() {
+- // Do nothing
+- }
+-
+- /**
+- * Stops transmission and for NAT Traversal reasons stop receiving also.
+- */
+- public void stopTrasmit() {
+- if (audioChannel != null)
+- audioChannel.stop();
+- }
+-
+- /**
+- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
+- */
+- public void stopReceive() {
+- // Do nothing
+- }
+-
+- /**
+- * Obtain a free port we can use.
+- *
+- * @return A free port number.
+- */
+- protected int getFreePort() {
+- ServerSocket ss;
+- int freePort = 0;
+-
+- for (int i = 0; i < 10; i++) {
+- freePort = (int) (10000 + Math.round(Math.random() * 10000));
+- freePort = freePort % 2 == 0 ? freePort : freePort + 1;
+- try {
+- ss = new ServerSocket(freePort);
+- freePort = ss.getLocalPort();
+- ss.close();
+- return freePort;
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- }
+- try {
+- ss = new ServerSocket(0);
+- freePort = ss.getLocalPort();
+- ss.close();
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- return freePort;
+- }
+-
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioReceiver.java (working copy) +@@ -1,171 +0,0 @@ +-/**
+- * $RCSfile: AudioReceiver.java,v $
+- * $Revision: 1.1 $
+- * $Date: 08/11/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
+-
+-import javax.media.ControllerErrorEvent;
+-import javax.media.ControllerEvent;
+-import javax.media.ControllerListener;
+-import javax.media.Player;
+-import javax.media.RealizeCompleteEvent;
+-import javax.media.protocol.DataSource;
+-import javax.media.rtp.Participant;
+-import javax.media.rtp.RTPControl;
+-import javax.media.rtp.ReceiveStream;
+-import javax.media.rtp.ReceiveStreamListener;
+-import javax.media.rtp.SessionListener;
+-import javax.media.rtp.event.ByeEvent;
+-import javax.media.rtp.event.NewParticipantEvent;
+-import javax.media.rtp.event.NewReceiveStreamEvent;
+-import javax.media.rtp.event.ReceiveStreamEvent;
+-import javax.media.rtp.event.RemotePayloadChangeEvent;
+-import javax.media.rtp.event.SessionEvent;
+-import javax.media.rtp.event.StreamMappedEvent;
+-
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
+-
+-/**
+- * This class implements receive methods and listeners to be used in AudioChannel
+- *
+- * @author Thiago Camargo
+- */
+-public class AudioReceiver implements ReceiveStreamListener, SessionListener,
+- ControllerListener {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioReceiver.class);
+-
+- boolean dataReceived = false;
+-
+- Object dataSync;
+- JingleMediaSession jingleMediaSession;
+-
+- public AudioReceiver(final Object dataSync, final JingleMediaSession jingleMediaSession) {
+- this.dataSync = dataSync;
+- this.jingleMediaSession = jingleMediaSession;
+- }
+-
+- /**
+- * JingleSessionListener.
+- */
+- public synchronized void update(SessionEvent evt) {
+- if (evt instanceof NewParticipantEvent) {
+- Participant p = ((NewParticipantEvent) evt).getParticipant();
+- LOGGER.error(" - A new participant had just joined: " + p.getCNAME());
+- }
+- }
+-
+- /**
+- * ReceiveStreamListener
+- */
+- public synchronized void update(ReceiveStreamEvent evt) {
+-
+- Participant participant = evt.getParticipant(); // could be null.
+- ReceiveStream stream = evt.getReceiveStream(); // could be null.
+-
+- if (evt instanceof RemotePayloadChangeEvent) {
+- LOGGER.error(" - Received an RTP PayloadChangeEvent.");
+- LOGGER.error("Sorry, cannot handle payload change.");
+-
+- }
+- else if (evt instanceof NewReceiveStreamEvent) {
+-
+- try {
+- stream = evt.getReceiveStream();
+- DataSource ds = stream.getDataSource();
+-
+- // Find out the formats.
+- RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
+- if (ctl != null) {
+- LOGGER.error(" - Recevied new RTP stream: " + ctl.getFormat());
+- }
+- else
+- LOGGER.error(" - Recevied new RTP stream");
+-
+- if (participant == null)
+- LOGGER.error(" The sender of this stream had yet to be identified.");
+- else {
+- LOGGER.error(" The stream comes from: " + participant.getCNAME());
+- }
+-
+- // create a player by passing datasource to the Media Manager
+- Player p = javax.media.Manager.createPlayer(ds);
+- if (p == null)
+- return;
+-
+- p.addControllerListener(this);
+- p.realize();
+- jingleMediaSession.mediaReceived(participant != null ? participant.getCNAME() : "");
+-
+- // Notify intialize() that a new stream had arrived.
+- synchronized (dataSync) {
+- dataReceived = true;
+- dataSync.notifyAll();
+- }
+-
+- }
+- catch (Exception e) {
+- LOGGER.error("NewReceiveStreamEvent exception " + e.getMessage());
+- return;
+- }
+-
+- }
+- else if (evt instanceof StreamMappedEvent) {
+-
+- if (stream != null && stream.getDataSource() != null) {
+- DataSource ds = stream.getDataSource();
+- // Find out the formats.
+- RTPControl ctl = (RTPControl) ds.getControl("javax.jmf.rtp.RTPControl");
+- LOGGER.error(" - The previously unidentified stream ");
+- if (ctl != null)
+- LOGGER.error(" " + ctl.getFormat());
+- LOGGER.error(" had now been identified as sent by: " + participant.getCNAME());
+- }
+- }
+- else if (evt instanceof ByeEvent) {
+-
+- LOGGER.error(" - Got \"bye\" from: " + participant.getCNAME());
+-
+- }
+-
+- }
+-
+- /**
+- * ControllerListener for the Players.
+- */
+- public synchronized void controllerUpdate(ControllerEvent ce) {
+-
+- Player p = (Player) ce.getSourceController();
+-
+- if (p == null)
+- return;
+-
+- // Get this when the internal players are realized.
+- if (ce instanceof RealizeCompleteEvent) {
+- p.start();
+- }
+-
+- if (ce instanceof ControllerErrorEvent) {
+- p.removeControllerListener(this);
+- LOGGER.error("Receiver internal error: " + ce);
+- }
+-
+- }
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/JmfMediaManager.java (working copy) +@@ -1,170 +0,0 @@ +-/**
+- * $RCSfile: JmfMediaManager.java,v $
+- * $Revision: 1.3 $
+- * $Date: 08/11/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
+-
+-import java.io.File;
+-import java.io.IOException;
+-import java.util.ArrayList;
+-import java.util.List;
+-
+-import org.jivesoftware.smackx.jingle.JingleSession;
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
+-import org.jivesoftware.smackx.jingle.media.PayloadType;
+-import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
+-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
+-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
+-
+-/**
+- * Implements a jingleMediaManager using JMF based API.
+- * It supports GSM and G723 codecs.
+- * <i>This API only currently works on windows and Mac.</i>
+- *
+- * @author Thiago Camargo
+- */
+-public class JmfMediaManager extends JingleMediaManager {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(JmfMediaManager.class);
+-
+- public static final String MEDIA_NAME = "JMF";
+-
+-
+- private List<PayloadType> payloads = new ArrayList<PayloadType>();
+- private String mediaLocator = null;
+-
+- /**
+- * Creates a Media Manager instance
+- */
+- public JmfMediaManager(JingleTransportManager transportManager) {
+- super(transportManager);
+- setupPayloads();
+- }
+-
+- /**
+- * Creates a Media Manager instance
+- *
+- * @param mediaLocator Media Locator
+- */
+- public JmfMediaManager(String mediaLocator, JingleTransportManager transportManager) {
+- super(transportManager);
+- this.mediaLocator = mediaLocator;
+- setupPayloads();
+- }
+-
+- /**
+- * Returns a new jingleMediaSession
+- *
+- * @param payloadType payloadType
+- * @param remote remote Candidate
+- * @param local local Candidate
+- * @return JingleMediaSession
+- */
+- public JingleMediaSession createMediaSession(final PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
+- return new AudioMediaSession(payloadType, remote, local, mediaLocator, jingleSession);
+- }
+-
+- /**
+- * Setup API supported Payloads
+- */
+- private void setupPayloads() {
+- payloads.add(new PayloadType.Audio(3, "gsm"));
+- payloads.add(new PayloadType.Audio(4, "g723"));
+- payloads.add(new PayloadType.Audio(0, "PCMU", 16000));
+- }
+-
+- /**
+- * Return all supported Payloads for this Manager
+- *
+- * @return The Payload List
+- */
+- public List<PayloadType> getPayloads() {
+- return payloads;
+- }
+-
+- /**
+- * Return the media locator or null if not defined
+- *
+- * @return media locator
+- */
+- public String getMediaLocator() {
+- return mediaLocator;
+- }
+-
+- /**
+- * Set the media locator
+- *
+- * @param mediaLocator media locator or null to use default
+- */
+- public void setMediaLocator(String mediaLocator) {
+- this.mediaLocator = mediaLocator;
+- }
+-
+- /**
+- * Runs JMFInit the first time the application is started so that capture
+- * devices are properly detected and initialized by JMF.
+- */
+- public static void setupJMF() {
+- // .jmf is the place where we store the jmf.properties file used
+- // by JMF. if the directory does not exist or it does not contain
+- // a jmf.properties file. or if the jmf.properties file has 0 length
+- // then this is the first time we're running and should continue to
+- // with JMFInit
+- String homeDir = System.getProperty("user.home");
+- File jmfDir = new File(homeDir, ".jmf");
+- String classpath = System.getProperty("java.class.path");
+- classpath += System.getProperty("path.separator")
+- + jmfDir.getAbsolutePath();
+- System.setProperty("java.class.path", classpath);
+-
+- if (!jmfDir.exists())
+- jmfDir.mkdir();
+-
+- File jmfProperties = new File(jmfDir, "jmf.properties");
+-
+- if (!jmfProperties.exists()) {
+- try {
+- jmfProperties.createNewFile();
+- }
+- catch (IOException ex) {
+- LOGGER.debug("Failed to create jmf.properties");
+- ex.printStackTrace();
+- }
+- }
+-
+- // if we're running on linux checkout that libjmutil.so is where it
+- // should be and put it there.
+- runLinuxPreInstall();
+-
+- //if (jmfProperties.length() == 0) {
+- new JMFInit(null, false);
+- //}
+-
+- }
+-
+- private static void runLinuxPreInstall() {
+- // @TODO Implement Linux Pre-Install
+- }
+-
+- public String getName() {
+- return MEDIA_NAME;
+- }
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioChannel.java (working copy) +@@ -1,553 +0,0 @@ +-/**
+- * $RCSfile: AudioChannel.java,v $
+- * $Revision: 1.1 $
+- * $Date: 08/11/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
+-
+-import java.io.IOException;
+-import java.net.InetAddress;
+-import java.net.UnknownHostException;
+-import java.util.ArrayList;
+-import java.util.List;
+-
+-import javax.media.Codec;
+-import javax.media.Controller;
+-import javax.media.ControllerClosedEvent;
+-import javax.media.ControllerEvent;
+-import javax.media.ControllerListener;
+-import javax.media.Format;
+-import javax.media.MediaLocator;
+-import javax.media.NoProcessorException;
+-import javax.media.Processor;
+-import javax.media.UnsupportedPlugInException;
+-import javax.media.control.BufferControl;
+-import javax.media.control.PacketSizeControl;
+-import javax.media.control.TrackControl;
+-import javax.media.format.AudioFormat;
+-import javax.media.protocol.ContentDescriptor;
+-import javax.media.protocol.DataSource;
+-import javax.media.protocol.PushBufferDataSource;
+-import javax.media.protocol.PushBufferStream;
+-import javax.media.rtp.InvalidSessionAddressException;
+-import javax.media.rtp.RTPManager;
+-import javax.media.rtp.SendStream;
+-import javax.media.rtp.SessionAddress;
+-
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
+-
+-/**
+- * An Easy to use Audio Channel implemented using JMF.
+- * It sends and receives jmf for and from desired IPs and ports.
+- * Also has a rport Symetric behavior for better NAT Traversal.
+- * It send data from a defined port and receive data in the same port, making NAT binds easier.
+- * <p/>
+- * Send from portA to portB and receive from portB in portA.
+- * <p/>
+- * Sending
+- * portA ---> portB
+- * <p/>
+- * Receiving
+- * portB ---> portA
+- * <p/>
+- * <i>Transmit and Receive are interdependents. To receive you MUST trasmit. </i>
+- *
+- * @author Thiago Camargo
+- */
+-public class AudioChannel {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioChannel.class);
+-
+- private MediaLocator locator;
+- private String localIpAddress;
+- private String remoteIpAddress;
+- private int localPort;
+- private int portBase;
+- private Format format;
+-
+- private Processor processor = null;
+- private RTPManager rtpMgrs[];
+- private DataSource dataOutput = null;
+- private AudioReceiver audioReceiver;
+-
+- private List<SendStream> sendStreams = new ArrayList<SendStream>();
+-
+- private JingleMediaSession jingleMediaSession;
+-
+- private boolean started = false;
+-
+- /**
+- * Creates an Audio Channel for a desired jmf locator. For instance: new MediaLocator("dsound://")
+- *
+- * @param locator media locator
+- * @param localIpAddress local IP address
+- * @param remoteIpAddress remote IP address
+- * @param localPort local port number
+- * @param remotePort remote port number
+- * @param format audio format
+- */
+- public AudioChannel(MediaLocator locator,
+- String localIpAddress,
+- String remoteIpAddress,
+- int localPort,
+- int remotePort,
+- Format format, JingleMediaSession jingleMediaSession) {
+-
+- this.locator = locator;
+- this.localIpAddress = localIpAddress;
+- this.remoteIpAddress = remoteIpAddress;
+- this.localPort = localPort;
+- this.portBase = remotePort;
+- this.format = format;
+- this.jingleMediaSession = jingleMediaSession;
+- }
+-
+- /**
+- * Starts the transmission. Returns null if transmission started ok.
+- * Otherwise it returns a string with the reason why the setup failed.
+- * Starts receive also.
+- *
+- * @return result description
+- */
+- public synchronized String start() {
+- if (started) return null;
+-
+- // Create a processor for the specified jmf locator
+- String result = createProcessor();
+- if (result != null) {
+- started = false;
+- }
+-
+- // Create an RTP session to transmit the output of the
+- // processor to the specified IP address and port no.
+- result = createTransmitter();
+- if (result != null) {
+- processor.close();
+- processor = null;
+- started = false;
+- }
+- else {
+- started = true;
+- }
+-
+- // Start the transmission
+- processor.start();
+-
+- return null;
+- }
+-
+- /**
+- * Stops the transmission if already started.
+- * Stops the receiver also.
+- */
+- public void stop() {
+- if (!started) return;
+- synchronized (this) {
+- try {
+- started = false;
+- if (processor != null) {
+- processor.stop();
+- processor = null;
+-
+- for (RTPManager rtpMgr : rtpMgrs) {
+- rtpMgr.removeReceiveStreamListener(audioReceiver);
+- rtpMgr.removeSessionListener(audioReceiver);
+- rtpMgr.removeTargets("Session ended.");
+- rtpMgr.dispose();
+- }
+-
+- sendStreams.clear();
+-
+- }
+- }
+- catch (Exception e) {
+- e.printStackTrace();
+- }
+- }
+- }
+-
+- private String createProcessor() {
+- if (locator == null)
+- return "Locator is null";
+-
+- DataSource ds;
+-
+- try {
+- ds = javax.media.Manager.createDataSource(locator);
+- }
+- catch (Exception e) {
+- // Try JavaSound Locator as a last resort
+- try {
+- ds = javax.media.Manager.createDataSource(new MediaLocator("javasound://"));
+- }
+- catch (Exception ee) {
+- return "Couldn't create DataSource";
+- }
+- }
+-
+- // Try to create a processor to handle the input jmf locator
+- try {
+- processor = javax.media.Manager.createProcessor(ds);
+- }
+- catch (NoProcessorException npe) {
+- npe.printStackTrace();
+- return "Couldn't create processor";
+- }
+- catch (IOException ioe) {
+- ioe.printStackTrace();
+- return "IOException creating processor";
+- }
+-
+- // Wait for it to configure
+- boolean result = waitForState(processor, Processor.Configured);
+- if (!result){
+- return "Couldn't configure processor";
+- }
+-
+- // Get the tracks from the processor
+- TrackControl[] tracks = processor.getTrackControls();
+-
+- // Do we have atleast one track?
+- if (tracks == null || tracks.length < 1){
+- return "Couldn't find tracks in processor";
+- }
+-
+- // Set the output content descriptor to RAW_RTP
+- // This will limit the supported formats reported from
+- // Track.getSupportedFormats to only valid RTP formats.
+- ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
+- processor.setContentDescriptor(cd);
+-
+- Format supported[];
+- Format chosen = null;
+- boolean atLeastOneTrack = false;
+-
+- // Program the tracks.
+- for (int i = 0; i < tracks.length; i++) {
+- if (tracks[i].isEnabled()) {
+-
+- supported = tracks[i].getSupportedFormats();
+-
+- if (supported.length > 0) {
+- for (Format format : supported) {
+- if (format instanceof AudioFormat) {
+- if (this.format.matches(format))
+- chosen = format;
+- }
+- }
+- if (chosen != null) {
+- tracks[i].setFormat(chosen);
+- LOGGER.error("Track " + i + " is set to transmit as:");
+- LOGGER.error(" " + chosen);
+-
+- if (tracks[i].getFormat() instanceof AudioFormat) {
+- int packetRate = 20;
+- PacketSizeControl pktCtrl = (PacketSizeControl) processor.getControl(PacketSizeControl.class.getName());
+- if (pktCtrl != null) {
+- try {
+- pktCtrl.setPacketSize(getPacketSize(tracks[i].getFormat(), packetRate));
+- }
+- catch (IllegalArgumentException e) {
+- pktCtrl.setPacketSize(80);
+- // Do nothing
+- }
+- }
+-
+- if (tracks[i].getFormat().getEncoding().equals(AudioFormat.ULAW_RTP)) {
+- Codec codec[] = new Codec[3];
+-
+- codec[0] = new com.ibm.media.codec.audio.rc.RCModule();
+- codec[1] = new com.ibm.media.codec.audio.ulaw.JavaEncoder();
+- codec[2] = new com.sun.media.codec.audio.ulaw.Packetizer();
+- ((com.sun.media.codec.audio.ulaw.Packetizer) codec
+- [2]).setPacketSize(160);
+-
+- try {
+- tracks[i].setCodecChain(codec);
+- }
+- catch (UnsupportedPlugInException e) {
+- e.printStackTrace();
+- }
+- }
+-
+- }
+-
+- atLeastOneTrack = true;
+- }
+- else
+- tracks[i].setEnabled(false);
+- }
+- else
+- tracks[i].setEnabled(false);
+- }
+- }
+-
+- if (!atLeastOneTrack)
+- return "Couldn't set any of the tracks to a valid RTP format";
+-
+- result = waitForState(processor, Controller.Realized);
+- if (!result)
+- return "Couldn't realize processor";
+-
+- // Get the output data source of the processor
+- dataOutput = processor.getDataOutput();
+-
+- return null;
+- }
+-
+- /**
+- * Get the best packet size for a given codec and a codec rate
+- *
+- * @param codecFormat
+- * @param milliseconds
+- * @return
+- * @throws IllegalArgumentException
+- */
+- private int getPacketSize(Format codecFormat, int milliseconds) throws IllegalArgumentException {
+- String encoding = codecFormat.getEncoding();
+- if (encoding.equalsIgnoreCase(AudioFormat.GSM) ||
+- encoding.equalsIgnoreCase(AudioFormat.GSM_RTP)) {
+- return milliseconds * 4; // 1 byte per millisec
+- }
+- else if (encoding.equalsIgnoreCase(AudioFormat.ULAW) ||
+- encoding.equalsIgnoreCase(AudioFormat.ULAW_RTP)) {
+- return milliseconds * 8;
+- }
+- else {
+- throw new IllegalArgumentException("Unknown codec type");
+- }
+- }
+-
+- /**
+- * Use the RTPManager API to create sessions for each jmf
+- * track of the processor.
+- *
+- * @return description
+- */
+- private String createTransmitter() {
+-
+- // Cheated. Should have checked the type.
+- PushBufferDataSource pbds = (PushBufferDataSource) dataOutput;
+- PushBufferStream pbss[] = pbds.getStreams();
+-
+- rtpMgrs = new RTPManager[pbss.length];
+- SessionAddress localAddr, destAddr;
+- InetAddress ipAddr;
+- SendStream sendStream;
+- audioReceiver = new AudioReceiver(this, jingleMediaSession);
+- int port;
+-
+- for (int i = 0; i < pbss.length; i++) {
+- try {
+- rtpMgrs[i] = RTPManager.newInstance();
+-
+- port = portBase + 2 * i;
+- ipAddr = InetAddress.getByName(remoteIpAddress);
+-
+- localAddr = new SessionAddress(InetAddress.getByName(this.localIpAddress),
+- localPort);
+-
+- destAddr = new SessionAddress(ipAddr, port);
+-
+- rtpMgrs[i].addReceiveStreamListener(audioReceiver);
+- rtpMgrs[i].addSessionListener(audioReceiver);
+-
+- BufferControl bc = (BufferControl) rtpMgrs[i].getControl("javax.media.control.BufferControl");
+- if (bc != null) {
+- int bl = 160;
+- bc.setBufferLength(bl);
+- }
+-
+- try {
+-
+- rtpMgrs[i].initialize(localAddr);
+-
+- }
+- catch (InvalidSessionAddressException e) {
+- // In case the local address is not allowed to read, we user another local address
+- SessionAddress sessAddr = new SessionAddress();
+- localAddr = new SessionAddress(sessAddr.getDataAddress(),
+- localPort);
+- rtpMgrs[i].initialize(localAddr);
+- }
+-
+- rtpMgrs[i].addTarget(destAddr);
+-
+- LOGGER.error("Created RTP session at " + localPort + " to: " + remoteIpAddress + " " + port);
+-
+- sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
+-
+- sendStreams.add(sendStream);
+-
+- sendStream.start();
+-
+- }
+- catch (Exception e) {
+- e.printStackTrace();
+- return e.getMessage();
+- }
+- }
+-
+- return null;
+- }
+-
+- /**
+- * Set transmit activity. If the active is true, the instance should trasmit.
+- * If it is set to false, the instance should pause transmit.
+- *
+- * @param active active state
+- */
+- public void setTrasmit(boolean active) {
+- for (SendStream sendStream : sendStreams) {
+- try {
+- if (active) {
+- sendStream.start();
+- LOGGER.debug("START");
+- }
+- else {
+- sendStream.stop();
+- LOGGER.debug("STOP");
+- }
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+-
+- }
+- }
+-
+- /**
+- * *************************************************************
+- * Convenience methods to handle processor's state changes.
+- * **************************************************************
+- */
+-
+- private Integer stateLock = 0;
+- private boolean failed = false;
+-
+- Integer getStateLock() {
+- return stateLock;
+- }
+-
+- void setFailed() {
+- failed = true;
+- }
+-
+- private synchronized boolean waitForState(Processor p, int state) {
+- p.addControllerListener(new StateListener());
+- failed = false;
+-
+- // Call the required method on the processor
+- if (state == Processor.Configured) {
+- p.configure();
+- }
+- else if (state == Processor.Realized) {
+- p.realize();
+- }
+-
+- // Wait until we get an event that confirms the
+- // success of the method, or a failure event.
+- // See StateListener inner class
+- while (p.getState() < state && !failed) {
+- synchronized (getStateLock()) {
+- try {
+- getStateLock().wait();
+- }
+- catch (InterruptedException ie) {
+- return false;
+- }
+- }
+- }
+-
+- return !failed;
+- }
+-
+- /**
+- * *************************************************************
+- * Inner Classes
+- * **************************************************************
+- */
+-
+- class StateListener implements ControllerListener {
+-
+- public void controllerUpdate(ControllerEvent ce) {
+-
+- // If there was an error during configure or
+- // realize, the processor will be closed
+- if (ce instanceof ControllerClosedEvent)
+- setFailed();
+-
+- // All controller events, send a notification
+- // to the waiting thread in waitForState method.
+- if (ce != null) {
+- synchronized (getStateLock()) {
+- getStateLock().notifyAll();
+- }
+- }
+- }
+- }
+-
+- public static void main(String args[]) {
+-
+- InetAddress localhost;
+- try {
+- localhost = InetAddress.getLocalHost();
+-
+- AudioChannel audioChannel0 = new AudioChannel(new MediaLocator("javasound://8000"), localhost.getHostAddress(), localhost.getHostAddress(), 7002, 7020, new AudioFormat(AudioFormat.GSM_RTP), null);
+- AudioChannel audioChannel1 = new AudioChannel(new MediaLocator("javasound://8000"), localhost.getHostAddress(), localhost.getHostAddress(), 7020, 7002, new AudioFormat(AudioFormat.GSM_RTP), null);
+-
+- audioChannel0.start();
+- audioChannel1.start();
+-
+- try {
+- Thread.sleep(5000);
+- }
+- catch (InterruptedException e) {
+- e.printStackTrace();
+- }
+-
+- audioChannel0.setTrasmit(false);
+- audioChannel1.setTrasmit(false);
+-
+- try {
+- Thread.sleep(5000);
+- }
+- catch (InterruptedException e) {
+- e.printStackTrace();
+- }
+-
+- audioChannel0.setTrasmit(true);
+- audioChannel1.setTrasmit(true);
+-
+- try {
+- Thread.sleep(5000);
+- }
+- catch (InterruptedException e) {
+- e.printStackTrace();
+- }
+-
+- audioChannel0.stop();
+- audioChannel1.stop();
+-
+- }
+- catch (UnknownHostException e) {
+- e.printStackTrace();
+- }
+-
+- }
+-} +\ No newline at end of file +Index: org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/jmf/AudioFormatUtils.java (working copy) +@@ -1,55 +0,0 @@ +-/**
+- * $RCSfile: AudioFormatUtils.java,v $
+- * $Revision: 1.1 $
+- * $Date: 08/11/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-package org.jivesoftware.smackx.jingle.mediaimpl.jmf;
+-
+-import org.jivesoftware.smackx.jingle.media.PayloadType;
+-
+-import javax.media.format.AudioFormat;
+-
+-/**
+- * Audio Format Utils.
+- *
+- * @author Thiago Camargo
+- */
+-public class AudioFormatUtils {
+-
+- /**
+- * Return a JMF AudioFormat for a given Jingle Payload type.
+- * Return null if the payload is not supported by this jmf API.
+- *
+- * @param payloadtype payloadtype
+- * @return correspondent audioType
+- */
+- public static AudioFormat getAudioFormat(PayloadType payloadtype) {
+-
+- switch (payloadtype.getId()) {
+- case 0:
+- return new AudioFormat(AudioFormat.ULAW_RTP);
+- case 3:
+- return new AudioFormat(AudioFormat.GSM_RTP);
+- case 4:
+- return new AudioFormat(AudioFormat.G723_RTP);
+- default:
+- return null;
+- }
+-
+- }
+-
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/jspeex/SpeexMediaManager.java (working copy) +@@ -1,134 +0,0 @@ +-/**
+- * $RCSfile: SpeexMediaManager.java,v $
+- * $Revision: 1.3 $
+- * $Date: 25/12/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
+-
+-import java.io.File;
+-import java.io.IOException;
+-import java.util.ArrayList;
+-import java.util.List;
+-
+-import org.jivesoftware.smackx.jingle.JingleSession;
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaManager;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
+-import org.jivesoftware.smackx.jingle.media.PayloadType;
+-import org.jivesoftware.smackx.jingle.mediaimpl.JMFInit;
+-import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
+-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
+-
+-/**
+- * Implements a jingleMediaManager using JMF based API and JSpeex.
+- * It supports Speex codec.
+- * <i>This API only currently works on windows.</i>
+- *
+- * @author Thiago Camargo
+- */
+-public class SpeexMediaManager extends JingleMediaManager {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(SpeexMediaManager.class);
+-
+- public static final String MEDIA_NAME = "Speex";
+-
+- private List<PayloadType> payloads = new ArrayList<PayloadType>();
+-
+- public SpeexMediaManager(JingleTransportManager transportManager) {
+- super(transportManager);
+- setupPayloads();
+- setupJMF();
+- }
+-
+- /**
+- * Returns a new jingleMediaSession
+- *
+- * @param payloadType payloadType
+- * @param remote remote Candidate
+- * @param local local Candidate
+- * @return JingleMediaSession
+- */
+- public JingleMediaSession createMediaSession(PayloadType payloadType, final TransportCandidate remote, final TransportCandidate local, final JingleSession jingleSession) {
+- return new AudioMediaSession(payloadType, remote, local, null,null);
+- }
+-
+- /**
+- * Setup API supported Payloads
+- */
+- private void setupPayloads() {
+- payloads.add(new PayloadType.Audio(15, "speex"));
+- }
+-
+- /**
+- * Return all supported Payloads for this Manager
+- *
+- * @return The Payload List
+- */
+- public List<PayloadType> getPayloads() {
+- return payloads;
+- }
+-
+- /**
+- * Runs JMFInit the first time the application is started so that capture
+- * devices are properly detected and initialized by JMF.
+- */
+- public static void setupJMF() {
+- // .jmf is the place where we store the jmf.properties file used
+- // by JMF. if the directory does not exist or it does not contain
+- // a jmf.properties file. or if the jmf.properties file has 0 length
+- // then this is the first time we're running and should continue to
+- // with JMFInit
+- String homeDir = System.getProperty("user.home");
+- File jmfDir = new File(homeDir, ".jmf");
+- String classpath = System.getProperty("java.class.path");
+- classpath += System.getProperty("path.separator")
+- + jmfDir.getAbsolutePath();
+- System.setProperty("java.class.path", classpath);
+-
+- if (!jmfDir.exists())
+- jmfDir.mkdir();
+-
+- File jmfProperties = new File(jmfDir, "jmf.properties");
+-
+- if (!jmfProperties.exists()) {
+- try {
+- jmfProperties.createNewFile();
+- }
+- catch (IOException ex) {
+- LOGGER.debug("Failed to create jmf.properties");
+- ex.printStackTrace();
+- }
+- }
+-
+- // if we're running on linux checkout that libjmutil.so is where it
+- // should be and put it there.
+- runLinuxPreInstall();
+-
+- if (jmfProperties.length() == 0) {
+- new JMFInit(null, false);
+- }
+-
+- }
+-
+- private static void runLinuxPreInstall() {
+- // @TODO Implement Linux Pre-Install
+- }
+-
+- public String getName() {
+- return MEDIA_NAME;
+- }
+-}
+Index: org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java +=================================================================== +--- org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java (revision 11644) ++++ org/jivesoftware/smackx/jingle/mediaimpl/jspeex/AudioMediaSession.java (working copy) +@@ -1,245 +0,0 @@ +-/**
+- * $RCSfile: AudioMediaSession.java,v $
+- * $Revision: 1.1 $
+- * $Date: 25/12/2006
+- * <p/>
+- * Copyright 2003-2006 Jive Software.
+- * <p/>
+- * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+- * you may not use this file except in compliance with the License.
+- * You may obtain a copy of the License at
+- * <p/>
+- * http://www.apache.org/licenses/LICENSE-2.0
+- * <p/>
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.jivesoftware.smackx.jingle.mediaimpl.jspeex;
+-
+-import java.io.IOException;
+-import java.net.DatagramSocket;
+-import java.net.InetAddress;
+-import java.net.ServerSocket;
+-import java.security.GeneralSecurityException;
+-
+-import javax.media.NoProcessorException;
+-import javax.media.format.UnsupportedFormatException;
+-import javax.media.rtp.rtcp.SenderReport;
+-import javax.media.rtp.rtcp.SourceDescription;
+-
+-import mil.jfcom.cie.media.session.MediaSession;
+-import mil.jfcom.cie.media.session.MediaSessionListener;
+-import mil.jfcom.cie.media.session.StreamPlayer;
+-import mil.jfcom.cie.media.srtp.packetizer.SpeexFormat;
+-
+-import org.jivesoftware.smackx.jingle.JingleSession;
+-import org.jivesoftware.smackx.jingle.SmackLogger;
+-import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
+-import org.jivesoftware.smackx.jingle.media.PayloadType;
+-import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
+-
+-/**
+- * This Class implements a complete JingleMediaSession.
+- * It sould be used to transmit and receive audio captured from the Mic.
+- * This Class should be automaticly controlled by JingleSession.
+- * But you could also use in any VOIP application.
+- * For better NAT Traversal support this implementation don't support only receive or only transmit.
+- * To receive you MUST transmit. So the only implemented and functionally methods are startTransmit() and stopTransmit()
+- *
+- * @author Thiago Camargo
+- */
+-
+-public class AudioMediaSession extends JingleMediaSession implements MediaSessionListener {
+-
+- private static final SmackLogger LOGGER = SmackLogger.getLogger(AudioMediaSession.class);
+-
+- private MediaSession mediaSession;
+-
+- /**
+- * Create a Session using Speex Codec
+- *
+- * @param localhost localHost
+- * @param localPort localPort
+- * @param remoteHost remoteHost
+- * @param remotePort remotePort
+- * @param eventHandler eventHandler
+- * @param quality quality
+- * @param secure secure
+- * @param micOn micOn
+- * @return MediaSession
+- * @throws NoProcessorException
+- * @throws UnsupportedFormatException
+- * @throws IOException
+- * @throws GeneralSecurityException
+- */
+- public static MediaSession createSession(String localhost, int localPort, String remoteHost, int remotePort, MediaSessionListener eventHandler, int quality, boolean secure, boolean micOn) throws NoProcessorException, UnsupportedFormatException, IOException, GeneralSecurityException {
+-
+- SpeexFormat.setFramesPerPacket(1);
+- /**
+- * The master key. Hardcoded for now.
+- */
+- byte[] masterKey = new byte[]{(byte) 0xE1, (byte) 0xF9, 0x7A, 0x0D, 0x3E, 0x01, (byte) 0x8B, (byte) 0xE0, (byte) 0xD6, 0x4F, (byte) 0xA3, 0x2C, 0x06, (byte) 0xDE, 0x41, 0x39};
+-
+- /**
+- * The master salt. Hardcoded for now.
+- */
+- byte[] masterSalt = new byte[]{0x0E, (byte) 0xC6, 0x75, (byte) 0xAD, 0x49, (byte) 0x8A, (byte) 0xFE, (byte) 0xEB, (byte) 0xB6, (byte) 0x96, 0x0B, 0x3A, (byte) 0xAB, (byte) 0xE6};
+-
+- DatagramSocket[] localPorts = MediaSession.getLocalPorts(InetAddress.getByName(localhost), localPort);
+- MediaSession session = MediaSession.createInstance(remoteHost, remotePort, localPorts, quality, secure, masterKey, masterSalt);
+- session.setListener(eventHandler);
+-
+- session.setSourceDescription(new SourceDescription[]{new SourceDescription(SourceDescription.SOURCE_DESC_NAME, "Superman", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_EMAIL, "cdcie.tester@je.jfcom.mil", 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_LOC, InetAddress.getByName(localhost) + " Port " + session.getLocalDataPort(), 1, false), new SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JFCOM CDCIE Audio Chat", 1, false)});
+- return session;
+- }
+-
+-
+- /**
+- * Creates a org.jivesoftware.jingleaudio.jspeex.AudioMediaSession with defined payload type, remote and local candidates
+- *
+- * @param payloadType Payload of the jmf
+- * @param remote the remote information. The candidate that the jmf will be sent to.
+- * @param local the local information. The candidate that will receive the jmf
+- * @param locator media locator
+- */
+- public AudioMediaSession(final PayloadType payloadType, final TransportCandidate remote,
+- final TransportCandidate local, String locator, JingleSession jingleSession) {
+- super(payloadType, remote, local, locator == null ? "dsound://" : locator, jingleSession);
+- initialize();
+- }
+-
+- /**
+- * Initialize the Audio Channel to make it able to send and receive audio
+- */
+- public void initialize() {
+-
+- String ip;
+- String localIp;
+- int localPort;
+- int remotePort;
+-
+- if (this.getLocal().getSymmetric() != null) {
+- ip = this.getLocal().getIp();
+- localIp = this.getLocal().getLocalIp();
+- localPort = getFreePort();
+- remotePort = this.getLocal().getSymmetric().getPort();
+-
+- LOGGER.debug(this.getLocal().getConnection() + " " + ip + ": " + localPort + "->" + remotePort);
+-
+- }
+- else {
+- ip = this.getRemote().getIp();
+- localIp = this.getLocal().getLocalIp();
+- localPort = this.getLocal().getPort();
+- remotePort = this.getRemote().getPort();
+- }
+-
+- try {
+- mediaSession = createSession(localIp, localPort, ip, remotePort, this, 2, false, true);
+- }
+- catch (NoProcessorException e) {
+- e.printStackTrace();
+- }
+- catch (UnsupportedFormatException e) {
+- e.printStackTrace();
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- catch (GeneralSecurityException e) {
+- e.printStackTrace();
+- }
+- }
+-
+- /**
+- * Starts transmission and for NAT Traversal reasons start receiving also.
+- */
+- public void startTrasmit() {
+- try {
+- LOGGER.debug("start");
+- mediaSession.start(true);
+- this.mediaReceived("");
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- }
+-
+- /**
+- * Set transmit activity. If the active is true, the instance should trasmit.
+- * If it is set to false, the instance should pause transmit.
+- *
+- * @param active active state
+- */
+- public void setTrasmit(boolean active) {
+- // Do nothing
+- }
+-
+- /**
+- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
+- */
+- public void startReceive() {
+- // Do nothing
+- }
+-
+- /**
+- * Stops transmission and for NAT Traversal reasons stop receiving also.
+- */
+- public void stopTrasmit() {
+- if (mediaSession != null)
+- mediaSession.close();
+- }
+-
+- /**
+- * For NAT Reasons this method does nothing. Use startTransmit() to start transmit and receive jmf
+- */
+- public void stopReceive() {
+- // Do nothing
+- }
+-
+- public void newStreamIdentified(StreamPlayer streamPlayer) {
+- }
+-
+- public void senderReportReceived(SenderReport report) {
+- }
+-
+- public void streamClosed(StreamPlayer stream, boolean timeout) {
+- }
+-
+- /**
+- * Obtain a free port we can use.
+- *
+- * @return A free port number.
+- */
+- protected int getFreePort() {
+- ServerSocket ss;
+- int freePort = 0;
+-
+- for (int i = 0; i < 10; i++) {
+- freePort = (int) (10000 + Math.round(Math.random() * 10000));
+- freePort = freePort % 2 == 0 ? freePort : freePort + 1;
+- try {
+- ss = new ServerSocket(freePort);
+- freePort = ss.getLocalPort();
+- ss.close();
+- return freePort;
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- }
+- try {
+- ss = new ServerSocket(0);
+- freePort = ss.getLocalPort();
+- ss.close();
+- }
+- catch (IOException e) {
+- e.printStackTrace();
+- }
+- return freePort;
+- }
+-}
diff --git a/asmack-master/lib/.gitignore b/asmack-master/lib/.gitignore new file mode 100644 index 0000000..905be00 --- /dev/null +++ b/asmack-master/lib/.gitignore @@ -0,0 +1 @@ +android-*.jar diff --git a/asmack-master/lib/httpclient-4.1.3.jar b/asmack-master/lib/httpclient-4.1.3.jar Binary files differnew file mode 100644 index 0000000..dfa8793 --- /dev/null +++ b/asmack-master/lib/httpclient-4.1.3.jar diff --git a/asmack-master/lib/httpcore-4.1.4.jar b/asmack-master/lib/httpcore-4.1.4.jar Binary files differnew file mode 100644 index 0000000..1606a2e --- /dev/null +++ b/asmack-master/lib/httpcore-4.1.4.jar diff --git a/asmack-master/lib/jstun.jar b/asmack-master/lib/jstun.jar Binary files differnew file mode 100644 index 0000000..8ef0b92 --- /dev/null +++ b/asmack-master/lib/jstun.jar diff --git a/asmack-master/lib/xpp3-1.1.4c.jar b/asmack-master/lib/xpp3-1.1.4c.jar Binary files differnew file mode 100644 index 0000000..451ac82 --- /dev/null +++ b/asmack-master/lib/xpp3-1.1.4c.jar diff --git a/asmack-master/local.properties.example b/asmack-master/local.properties.example new file mode 100644 index 0000000..abdf234 --- /dev/null +++ b/asmack-master/local.properties.example @@ -0,0 +1 @@ +sdk-location=${user.home}/android/ diff --git a/asmack-master/patch/00-relocate-javax.security.sh b/asmack-master/patch/00-relocate-javax.security.sh new file mode 100755 index 0000000..0924208 --- /dev/null +++ b/asmack-master/patch/00-relocate-javax.security.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +mkdir -p org/apache/harmony/ +mv javax org/apache/harmony/ +find org/apache/harmony/ -name '*.java' -exec sed -i 's:package javax:package org.apache.harmony.javax:g' '{}' ';' +find -name '*.java' -exec sed -i 's:import javax.security.sasl:import org.apache.harmony.javax.security.sasl:g' '{}' ';' +find -name '*.java' -exec sed -i 's:import javax.security.auth:import org.apache.harmony.javax.security.auth:g' '{}' ';' + diff --git a/asmack-master/patch/00-remove-javax-dns.sh b/asmack-master/patch/00-remove-javax-dns.sh new file mode 100755 index 0000000..a4f8f23 --- /dev/null +++ b/asmack-master/patch/00-remove-javax-dns.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rm org/jivesoftware/smack/util/dns/JavaxResolver.java diff --git a/asmack-master/patch/10-remove-unused-harmony.sh b/asmack-master/patch/10-remove-unused-harmony.sh new file mode 100755 index 0000000..ae0b4e3 --- /dev/null +++ b/asmack-master/patch/10-remove-unused-harmony.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +rm -rf org/ietf/ + +rm -rf org/apache/harmony/auth +rm -rf org/apache/harmony/javax/security/auth/kerberos/ +rm -rf org/apache/harmony/javax/security/auth/x500/ + +rm org/apache/harmony/javax/security/auth/Policy.java + diff --git a/asmack-master/patch/11-remove-nls-harmony.sh b/asmack-master/patch/11-remove-nls-harmony.sh new file mode 100755 index 0000000..f1281f5 --- /dev/null +++ b/asmack-master/patch/11-remove-nls-harmony.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +find org/apache/harmony -name '*.java' -exec sed -i 's:import org.apache.harmony.auth.internal.nls.Messages;::' '{}' ';' +find org/apache/harmony -name '*.java' -exec sed -i 's:Messages.getString(\("[^"]*"\)):\1:g' '{}' ';' + diff --git a/asmack-master/patch/12-harmony-nls-msg.patch b/asmack-master/patch/12-harmony-nls-msg.patch new file mode 100644 index 0000000..b201f60 --- /dev/null +++ b/asmack-master/patch/12-harmony-nls-msg.patch @@ -0,0 +1,59 @@ +diff -ur ../../src-unpatched/trunk/org/apache/harmony/javax/security/auth/login/LoginContext.java ./org/apache/harmony/javax/security/auth/login/LoginContext.java +--- ../../src-unpatched/trunk/org/apache/harmony/javax/security/auth/login/LoginContext.java 2009-12-06 15:31:24.000000000 +0100 ++++ ./org/apache/harmony/javax/security/auth/login/LoginContext.java 2009-12-06 15:36:20.000000000 +0100 +@@ -161,7 +161,7 @@ + } + entries = config.getAppConfigurationEntry("other"); //$NON-NLS-1$ + if (entries == null) { +- throw new LoginException(Messages.getString("auth.35", name)); //$NON-NLS-1$ ++ throw new LoginException("auth.35 " + name); //$NON-NLS-1$ + } + } + +@@ -524,8 +524,8 @@ + try { + klass = Class.forName(klassName, false, contextClassLoader); + } catch (ClassNotFoundException ex) { +- throw (LoginException) new LoginException(Messages.getString( +- "auth.39", klassName)).initCause(ex); //$NON-NLS-1$ ++ throw (LoginException) new LoginException( ++ "auth.39 " + klassName).initCause(ex); //$NON-NLS-1$ + } + } + +@@ -533,12 +533,12 @@ + try { + module = (LoginModule) klass.newInstance(); + } catch (IllegalAccessException ex) { +- throw (LoginException) new LoginException(Messages.getString( +- "auth.3A", klassName)) //$NON-NLS-1$ ++ throw (LoginException) new LoginException( ++ "auth.3A " + klassName) //$NON-NLS-1$ + .initCause(ex); + } catch (InstantiationException ex) { +- throw (LoginException) new LoginException(Messages.getString( +- "auth.3A", klassName)) //$NON-NLS-1$ ++ throw (LoginException) new LoginException( ++ "auth.3A" + klassName) //$NON-NLS-1$ + .initCause(ex); + } + module.initialize(subject, callbackHandler, sharedState, entry.getOptions()); +diff -ur ../../src-unpatched/trunk/org/apache/harmony/javax/security/auth/Subject.java ./org/apache/harmony/javax/security/auth/Subject.java +--- ../../src-unpatched/trunk/org/apache/harmony/javax/security/auth/Subject.java 2009-12-06 15:31:24.000000000 +0100 ++++ ./org/apache/harmony/javax/security/auth/Subject.java 2009-12-06 15:32:10.000000000 +0100 +@@ -669,7 +669,7 @@ + + if (!c.isAssignableFrom(o.getClass())) { + throw new IllegalArgumentException( +- Messages.getString("auth.0C", c.getName())); //$NON-NLS-1$ ++ "auth.0C " + c.getName()); //$NON-NLS-1$ + } + + if (elements.contains(o)) { +@@ -779,4 +779,4 @@ + } + } + } +-} +\ No newline at end of file ++} diff --git a/asmack-master/patch/13-mock-configuration.patch b/asmack-master/patch/13-mock-configuration.patch new file mode 100644 index 0000000..ce93b26 --- /dev/null +++ b/asmack-master/patch/13-mock-configuration.patch @@ -0,0 +1,33 @@ +diff -ur ../../src-unpatched/trunk/org/apache/harmony/javax/security/auth/login/Configuration.java ./org/apache/harmony/javax/security/auth/login/Configuration.java +--- ../../src-unpatched/trunk/org/apache/harmony/javax/security/auth/login/Configuration.java 2009-12-06 18:40:25.000000000 +0100 ++++ ./org/apache/harmony/javax/security/auth/login/Configuration.java 2009-12-06 18:44:23.000000000 +0100 +@@ -20,8 +20,6 @@ + import java.security.AccessController; + import org.apache.harmony.javax.security.auth.AuthPermission; + +-import org.apache.harmony.security.fortress.PolicyUtils; +- + public abstract class Configuration { + + // the current configuration +@@ -56,8 +54,18 @@ + * exception, wraps it with SecurityException and throws further. + */ + private static final Configuration getDefaultProvider() { +- return AccessController.doPrivileged(new PolicyUtils.ProviderLoader<Configuration>( +- LOGIN_CONFIGURATION_PROVIDER, Configuration.class)); ++ return new Configuration() { ++ ++ @Override ++ public void refresh() { ++ } ++ ++ @Override ++ public AppConfigurationEntry[] getAppConfigurationEntry( ++ String applicationName) { ++ return new AppConfigurationEntry[0]; ++ } ++ }; + } + + /** diff --git a/asmack-master/patch/20-remove-mxparser.sh b/asmack-master/patch/20-remove-mxparser.sh new file mode 100755 index 0000000..c1d6318 --- /dev/null +++ b/asmack-master/patch/20-remove-mxparser.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +find org/jivesoftware -name '*.java' -exec sed -i 's:import org.xmlpull.mxp1.MXParser:import org.xmlpull.v1.XmlPullParserFactory:' '{}' ';' +find org/jivesoftware -name '*.java' -exec sed -i 's:new MXParser():XmlPullParserFactory.newInstance().newPullParser():g' '{}' ';' + diff --git a/asmack-master/patch/21-remove-unused-smack.sh b/asmack-master/patch/21-remove-unused-smack.sh new file mode 100755 index 0000000..078ff04 --- /dev/null +++ b/asmack-master/patch/21-remove-unused-smack.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +rm org/jivesoftware/smack/debugger/LiteDebugger.java +rm org/jivesoftware/smackx/debugger/EnhancedDebugger.java +rm org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java + diff --git a/asmack-master/patch/22-remove-beans.Property-deps.patch b/asmack-master/patch/22-remove-beans.Property-deps.patch new file mode 100644 index 0000000..8653716 --- /dev/null +++ b/asmack-master/patch/22-remove-beans.Property-deps.patch @@ -0,0 +1,30 @@ +--- ../../src-unpatched/trunk/org/jivesoftware/smack/util/PacketParserUtils.java 2009-12-06 19:45:45.000000000 +0100 ++++ org/jivesoftware/smack/util/PacketParserUtils.java 2009-12-06 19:48:13.000000000 +0100 +@@ -25,7 +25,6 @@ + import org.jivesoftware.smack.provider.ProviderManager; + import org.xmlpull.v1.XmlPullParser; + +-import java.beans.PropertyDescriptor; + import java.io.ByteArrayInputStream; + import java.io.ObjectInputStream; + import java.util.ArrayList; +@@ -828,14 +827,14 @@ + if (eventType == XmlPullParser.START_TAG) { + String name = parser.getName(); + String stringValue = parser.nextText(); +- PropertyDescriptor descriptor = new PropertyDescriptor(name, objectClass); +- // Load the class type of the property. +- Class<?> propertyType = descriptor.getPropertyType(); ++ Class propertyType = object.getClass().getMethod( ++ "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1)).getReturnType(); + // Get the value of the property by converting it from a + // String to the correct object type. + Object value = decode(propertyType, stringValue); + // Set the value of the bean. +- descriptor.getWriteMethod().invoke(object, value); ++ object.getClass().getMethod("set" + Character.toUpperCase(name.charAt(0)) + name.substring(1), propertyType) ++ .invoke(object, value); + } + else if (eventType == XmlPullParser.END_TAG) { + if (parser.getName().equals(elementName)) { + diff --git a/asmack-master/patch/23-strip-unused-xml-transform.patch b/asmack-master/patch/23-strip-unused-xml-transform.patch new file mode 100644 index 0000000..24debbd --- /dev/null +++ b/asmack-master/patch/23-strip-unused-xml-transform.patch @@ -0,0 +1,50 @@ +--- org/jivesoftware/smackx/pubsub/util/XmlUtils.java 2012-06-05 14:35:54.518687907 +0200 ++++ org/jivesoftware/smackx/pubsub/util/XmlUtils.java 2012-06-05 21:07:13.038946699 +0200 +@@ -14,47 +14,15 @@ + package org.jivesoftware.smackx.pubsub.util;
+
+ import java.io.StringReader;
+
+-import javax.xml.transform.OutputKeys;
+-import javax.xml.transform.Transformer;
+-import javax.xml.transform.TransformerFactory;
+-import javax.xml.transform.stream.StreamResult;
+-import javax.xml.transform.stream.StreamSource;
+-
+ /**
+ * Simple utility for pretty printing xml.
+ *
+ * @author Robin Collier
+ */
+ public class XmlUtils
+ {
+- /**
+- *
+- * @param header Just a title for the stanza for readability. Single word no spaces since
+- * it is inserted as the root element in the output.
+- * @param xml The string to pretty print
+- */
+- static public void prettyPrint(String header, String xml)
+- {
+- try
+- {
+- Transformer transformer = TransformerFactory.newInstance().newTransformer();
+- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+- transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
+-
+- if (header != null)
+- {
+- xml = "\n<" + header + ">" + xml + "</" + header + '>';
+- }
+- transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(System.out));
+- }
+- catch (Exception e)
+- {
+- System.out.println("Something wrong with xml in \n---------------\n" + xml + "\n---------------");
+- e.printStackTrace();
+- }
+- }
+
+ static public void appendAttribute(StringBuilder builder, String att, String value)
+ {
+ builder.append(" ");
diff --git a/asmack-master/patch/24-disable-sasl-methods.patch b/asmack-master/patch/24-disable-sasl-methods.patch new file mode 100644 index 0000000..eda5eb0 --- /dev/null +++ b/asmack-master/patch/24-disable-sasl-methods.patch @@ -0,0 +1,20 @@ +--- ../../src-unpatched/trunk/org/jivesoftware/smack/SASLAuthentication.java 2009-12-07 00:03:46.000000000 +0100 ++++ org/jivesoftware/smack/SASLAuthentication.java 2009-12-07 00:05:46.000000000 +0100 +@@ -91,11 +91,11 @@ + registerSASLMechanism("PLAIN", SASLPlainMechanism.class);
+ registerSASLMechanism("ANONYMOUS", SASLAnonymous.class);
+
+- supportSASLMechanism("GSSAPI",0);
+- supportSASLMechanism("DIGEST-MD5",1);
+- supportSASLMechanism("CRAM-MD5",2);
+- supportSASLMechanism("PLAIN",3);
+- supportSASLMechanism("ANONYMOUS",4);
++// supportSASLMechanism("GSSAPI",0);
++ supportSASLMechanism("DIGEST-MD5",0);
++// supportSASLMechanism("CRAM-MD5",2);
++ supportSASLMechanism("PLAIN",1);
++ supportSASLMechanism("ANONYMOUS",2);
+
+ }
+
+ diff --git a/asmack-master/patch/30-switch-debugging-implementations.patch b/asmack-master/patch/30-switch-debugging-implementations.patch new file mode 100644 index 0000000..93be2a0 --- /dev/null +++ b/asmack-master/patch/30-switch-debugging-implementations.patch @@ -0,0 +1,17 @@ +--- ../../../src/smack/org/jivesoftware/smack/Connection.java 2010-02-03 23:29:21.000000000 +0100 ++++ org/jivesoftware/smack/Connection.java 2010-02-03 23:56:56.000000000 +0100 +@@ -743,12 +743,12 @@ + if (debuggerClass == null) { + try { + debuggerClass = +- Class.forName("org.jivesoftware.smackx.debugger.EnhancedDebugger"); ++ Class.forName("de.measite.smack.AndroidDebugger"); + } + catch (Exception ex) { + try { + debuggerClass = +- Class.forName("org.jivesoftware.smack.debugger.LiteDebugger"); ++ Class.forName("org.jivesoftware.smack.debugger.ConsoleDebugger"); + } + catch (Exception ex2) { + ex2.printStackTrace(); diff --git a/asmack-master/patch/31-remove-dns-wrapper.sh b/asmack-master/patch/31-remove-dns-wrapper.sh new file mode 100755 index 0000000..c8c5ede --- /dev/null +++ b/asmack-master/patch/31-remove-dns-wrapper.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rm org/xbill/DNS/spi/DNSJavaNameServiceDescriptor.java + diff --git a/asmack-master/patch/32-remove-jbosh-xlightweb.sh b/asmack-master/patch/32-remove-jbosh-xlightweb.sh new file mode 100755 index 0000000..53ad364 --- /dev/null +++ b/asmack-master/patch/32-remove-jbosh-xlightweb.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rm com/kenai/jbosh/XLightWeb*.java + diff --git a/asmack-master/patch/33-jbosh-android.patch b/asmack-master/patch/33-jbosh-android.patch new file mode 100644 index 0000000..33a9b7d --- /dev/null +++ b/asmack-master/patch/33-jbosh-android.patch @@ -0,0 +1,446 @@ +diff --git com/kenai/jbosh/ApacheHTTPResponse.java com/kenai/jbosh/ApacheHTTPResponse.java +new file mode 100644 +index 0000000..9f6731f +--- /dev/null ++++ com/kenai/jbosh/ApacheHTTPResponse.java +@@ -0,0 +1,253 @@ ++/* ++ * Copyright 2009 Guenther Niess ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.kenai.jbosh; ++ ++import java.io.IOException; ++import java.util.concurrent.locks.Lock; ++import java.util.concurrent.locks.ReentrantLock; ++ ++import org.apache.http.HttpEntity; ++import org.apache.http.HttpResponse; ++import org.apache.http.client.HttpClient; ++import org.apache.http.client.methods.HttpPost; ++import org.apache.http.entity.ByteArrayEntity; ++ ++import org.apache.http.protocol.BasicHttpContext; ++import org.apache.http.protocol.HttpContext; ++import org.apache.http.util.EntityUtils; ++ ++final class ApacheHTTPResponse implements HTTPResponse { ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // Constants: ++ ++ /** ++ * Name of the accept encoding header. ++ */ ++ private static final String ACCEPT_ENCODING = "Accept-Encoding"; ++ ++ /** ++ * Value to use for the ACCEPT_ENCODING header. ++ */ ++ private static final String ACCEPT_ENCODING_VAL = ++ ZLIBCodec.getID() + ", " + GZIPCodec.getID(); ++ ++ /** ++ * Name of the character set to encode the body to/from. ++ */ ++ private static final String CHARSET = "UTF-8"; ++ ++ /** ++ * Content type to use when transmitting the body data. ++ */ ++ private static final String CONTENT_TYPE = "text/xml; charset=utf-8"; ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // Class variables: ++ ++ /** ++ * Lock used for internal synchronization. ++ */ ++ private final Lock lock = new ReentrantLock(); ++ ++ /** ++ * The execution state of an HTTP process. ++ */ ++ private final HttpContext context; ++ ++ /** ++ * HttpClient instance to use to communicate. ++ */ ++ private final HttpClient client; ++ ++ /** ++ * The HTTP POST request is sent to the server. ++ */ ++ private final HttpPost post; ++ ++ /** ++ * A flag which indicates if the transmission was already done. ++ */ ++ private boolean sent; ++ ++ /** ++ * Exception to throw when the response data is attempted to be accessed, ++ * or {@code null} if no exception should be thrown. ++ */ ++ private BOSHException toThrow; ++ ++ /** ++ * The response body which was received from the server or {@code null} ++ * if that has not yet happened. ++ */ ++ private AbstractBody body; ++ ++ /** ++ * The HTTP response status code. ++ */ ++ private int statusCode; ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // Constructors: ++ ++ /** ++ * Create and send a new request to the upstream connection manager, ++ * providing deferred access to the results to be returned. ++ * ++ * @param client client instance to use when sending the request ++ * @param cfg client configuration ++ * @param params connection manager parameters from the session creation ++ * response, or {@code null} if the session has not yet been established ++ * @param request body of the client request ++ */ ++ ApacheHTTPResponse( ++ final HttpClient client, ++ final BOSHClientConfig cfg, ++ final CMSessionParams params, ++ final AbstractBody request) { ++ super(); ++ this.client = client; ++ this.context = new BasicHttpContext(); ++ this.post = new HttpPost(cfg.getURI().toString()); ++ this.sent = false; ++ ++ try { ++ String xml = request.toXML(); ++ byte[] data = xml.getBytes(CHARSET); ++ ++ String encoding = null; ++ if (cfg.isCompressionEnabled() && params != null) { ++ AttrAccept accept = params.getAccept(); ++ if (accept != null) { ++ if (accept.isAccepted(ZLIBCodec.getID())) { ++ encoding = ZLIBCodec.getID(); ++ data = ZLIBCodec.encode(data); ++ } else if (accept.isAccepted(GZIPCodec.getID())) { ++ encoding = GZIPCodec.getID(); ++ data = GZIPCodec.encode(data); ++ } ++ } ++ } ++ ++ ByteArrayEntity entity = new ByteArrayEntity(data); ++ entity.setContentType(CONTENT_TYPE); ++ if (encoding != null) { ++ entity.setContentEncoding(encoding); ++ } ++ post.setEntity(entity); ++ if (cfg.isCompressionEnabled()) { ++ post.setHeader(ACCEPT_ENCODING, ACCEPT_ENCODING_VAL); ++ } ++ } catch (Exception e) { ++ toThrow = new BOSHException("Could not generate request", e); ++ } ++ } ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // HTTPResponse interface methods: ++ ++ /** ++ * Abort the client transmission and response processing. ++ */ ++ public void abort() { ++ if (post != null) { ++ post.abort(); ++ toThrow = new BOSHException("HTTP request aborted"); ++ } ++ } ++ ++ /** ++ * Wait for and then return the response body. ++ * ++ * @return body of the response ++ * @throws InterruptedException if interrupted while awaiting the response ++ * @throws BOSHException on communication failure ++ */ ++ public AbstractBody getBody() throws InterruptedException, BOSHException { ++ if (toThrow != null) { ++ throw(toThrow); ++ } ++ lock.lock(); ++ try { ++ if (!sent) { ++ awaitResponse(); ++ } ++ } finally { ++ lock.unlock(); ++ } ++ return body; ++ } ++ ++ /** ++ * Wait for and then return the response HTTP status code. ++ * ++ * @return HTTP status code of the response ++ * @throws InterruptedException if interrupted while awaiting the response ++ * @throws BOSHException on communication failure ++ */ ++ public int getHTTPStatus() throws InterruptedException, BOSHException { ++ if (toThrow != null) { ++ throw(toThrow); ++ } ++ lock.lock(); ++ try { ++ if (!sent) { ++ awaitResponse(); ++ } ++ } finally { ++ lock.unlock(); ++ } ++ return statusCode; ++ } ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // Package-private methods: ++ ++ /** ++ * Await the response, storing the result in the instance variables of ++ * this class when they arrive. ++ * ++ * @throws InterruptedException if interrupted while awaiting the response ++ * @throws BOSHException on communication failure ++ */ ++ private synchronized void awaitResponse() throws BOSHException { ++ HttpEntity entity = null; ++ try { ++ HttpResponse httpResp = client.execute(post, context); ++ entity = httpResp.getEntity(); ++ byte[] data = EntityUtils.toByteArray(entity); ++ String encoding = entity.getContentEncoding() != null ? ++ entity.getContentEncoding().getValue() : ++ null; ++ if (ZLIBCodec.getID().equalsIgnoreCase(encoding)) { ++ data = ZLIBCodec.decode(data); ++ } else if (GZIPCodec.getID().equalsIgnoreCase(encoding)) { ++ data = GZIPCodec.decode(data); ++ } ++ body = StaticBody.fromString(new String(data, CHARSET)); ++ statusCode = httpResp.getStatusLine().getStatusCode(); ++ sent = true; ++ } catch (IOException iox) { ++ abort(); ++ toThrow = new BOSHException("Could not obtain response", iox); ++ throw(toThrow); ++ } catch (RuntimeException ex) { ++ abort(); ++ throw(ex); ++ } ++ } ++} +diff --git com/kenai/jbosh/ApacheHTTPSender.java com/kenai/jbosh/ApacheHTTPSender.java +new file mode 100644 +index 0000000..2abb4ee +--- /dev/null ++++ com/kenai/jbosh/ApacheHTTPSender.java +@@ -0,0 +1,156 @@ ++/* ++ * Copyright 2009 Guenther Niess ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package com.kenai.jbosh; ++ ++import java.util.concurrent.locks.Lock; ++import java.util.concurrent.locks.ReentrantLock; ++ ++import org.apache.http.HttpHost; ++import org.apache.http.HttpVersion; ++import org.apache.http.client.HttpClient; ++import org.apache.http.conn.ClientConnectionManager; ++import org.apache.http.conn.params.ConnManagerParams; ++import org.apache.http.conn.params.ConnRoutePNames; ++import org.apache.http.conn.scheme.PlainSocketFactory; ++import org.apache.http.conn.scheme.Scheme; ++import org.apache.http.conn.scheme.SchemeRegistry; ++import org.apache.http.conn.ssl.SSLSocketFactory; ++import org.apache.http.impl.client.DefaultHttpClient; ++import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; ++import org.apache.http.params.BasicHttpParams; ++import org.apache.http.params.HttpParams; ++import org.apache.http.params.HttpProtocolParams; ++ ++/** ++ * Implementation of the {@code HTTPSender} interface which uses the ++ * Apache HttpClient API to send messages to the connection manager. ++ */ ++final class ApacheHTTPSender implements HTTPSender { ++ ++ /** ++ * Lock used for internal synchronization. ++ */ ++ private final Lock lock = new ReentrantLock(); ++ ++ /** ++ * Session configuration. ++ */ ++ private BOSHClientConfig cfg; ++ ++ /** ++ * HttpClient instance to use to communicate. ++ */ ++ private HttpClient httpClient; ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // Constructors: ++ ++ /** ++ * Prevent construction apart from our package. ++ */ ++ ApacheHTTPSender() { ++ // Load Apache HTTP client class ++ HttpClient.class.getName(); ++ } ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // HTTPSender interface methods: ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public void init(final BOSHClientConfig session) { ++ lock.lock(); ++ try { ++ cfg = session; ++ httpClient = initHttpClient(session); ++ } finally { ++ lock.unlock(); ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public void destroy() { ++ lock.lock(); ++ try { ++ if (httpClient != null) { ++ httpClient.getConnectionManager().shutdown(); ++ } ++ } finally { ++ cfg = null; ++ httpClient = null; ++ lock.unlock(); ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public HTTPResponse send( ++ final CMSessionParams params, ++ final AbstractBody body) { ++ HttpClient mClient; ++ BOSHClientConfig mCfg; ++ lock.lock(); ++ try { ++ if (httpClient == null) { ++ httpClient = initHttpClient(cfg); ++ } ++ mClient = httpClient; ++ mCfg = cfg; ++ } finally { ++ lock.unlock(); ++ } ++ return new ApacheHTTPResponse(mClient, mCfg, params, body); ++ } ++ ++ /////////////////////////////////////////////////////////////////////////// ++ // Package-private methods: ++ ++ private synchronized HttpClient initHttpClient(final BOSHClientConfig config) { ++ // Create and initialize HTTP parameters ++ HttpParams params = new BasicHttpParams(); ++ ConnManagerParams.setMaxTotalConnections(params, 100); ++ HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); ++ HttpProtocolParams.setUseExpectContinue(params, false); ++ if (config != null && ++ config.getProxyHost() != null && ++ config.getProxyPort() != 0) { ++ HttpHost proxy = new HttpHost( ++ config.getProxyHost(), ++ config.getProxyPort()); ++ params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); ++ } ++ ++ // Create and initialize scheme registry ++ SchemeRegistry schemeRegistry = new SchemeRegistry(); ++ schemeRegistry.register( ++ new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); ++ SSLSocketFactory sslFactory = SSLSocketFactory.getSocketFactory(); ++ sslFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ++ schemeRegistry.register( ++ new Scheme("https", sslFactory, 443)); ++ ++ // Create an HttpClient with the ThreadSafeClientConnManager. ++ // This connection manager must be used if more than one thread will ++ // be using the HttpClient. ++ ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); ++ return new DefaultHttpClient(cm, params); ++ } ++} +diff --git com/kenai/jbosh/BodyParserXmlPull.java com/kenai/jbosh/BodyParserXmlPull.java +index cc95236..5f23b06 100644 +--- com/kenai/jbosh/BodyParserXmlPull.java ++++ com/kenai/jbosh/BodyParserXmlPull.java +@@ -22,7 +22,6 @@ import java.lang.ref.SoftReference; + import java.util.logging.Level; + import java.util.logging.Logger; + import javax.xml.XMLConstants; +-import javax.xml.namespace.QName; + import org.xmlpull.v1.XmlPullParser; + import org.xmlpull.v1.XmlPullParserException; + import org.xmlpull.v1.XmlPullParserFactory; +diff --git com/kenai/jbosh/BodyQName.java com/kenai/jbosh/BodyQName.java +index fc7ab0c..83acdf1 100644 +--- com/kenai/jbosh/BodyQName.java ++++ com/kenai/jbosh/BodyQName.java +@@ -16,8 +16,6 @@ + + package com.kenai.jbosh; + +-import javax.xml.namespace.QName; +- + /** + * Qualified name of an attribute of the wrapper element. This class is + * analagous to the {@code javax.xml.namespace.QName} class. diff --git a/asmack-master/patch/34-pin-jbosh-http-sender.patch b/asmack-master/patch/34-pin-jbosh-http-sender.patch new file mode 100644 index 0000000..daf96df --- /dev/null +++ b/asmack-master/patch/34-pin-jbosh-http-sender.patch @@ -0,0 +1,11 @@ +--- com/kenai/jbosh/BOSHClient.java 2010-01-13 20:57:36.000000000 +0100 ++++ com/kenai/jbosh/BOSHClient.java 2010-02-04 17:40:45.678169320 +0100 +@@ -232,7 +232,7 @@ + * HTTPSender instance. + */ + private final HTTPSender httpSender = +- ServiceLib.loadService(HTTPSender.class); ++ new ApacheHTTPSender(); + + /** + * Storage for test hook implementation. diff --git a/asmack-master/patch/35-pin-jbosh-boddy-parser.patch b/asmack-master/patch/35-pin-jbosh-boddy-parser.patch new file mode 100644 index 0000000..f4c63e8 --- /dev/null +++ b/asmack-master/patch/35-pin-jbosh-boddy-parser.patch @@ -0,0 +1,11 @@ +--- com/kenai/jbosh/StaticBody.java 2010-01-13 20:57:36.000000000 +0100 ++++ com/kenai/jbosh/StaticBody.java 2010-02-04 17:59:06.037770746 +0100 +@@ -42,7 +42,7 @@ + * Selected parser to be used to process raw XML messages. + */ + private static final BodyParser PARSER = +- ServiceLib.loadService(BodyParser.class); ++ new BodyParserXmlPull(); + + /** + * Size of the internal buffer when copying from a stream. diff --git a/asmack-master/patch/40-enable-custom-sasl.sh b/asmack-master/patch/40-enable-custom-sasl.sh new file mode 100755 index 0000000..476bd5b --- /dev/null +++ b/asmack-master/patch/40-enable-custom-sasl.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +find -name '*.java' -exec sed -i 's:import org.apache.harmony.javax.security.sasl.Sasl;:import de.measite.smack.Sasl;:g' '{}' ';' + diff --git a/asmack-master/patch/41-fix-digest-md5.patch b/asmack-master/patch/41-fix-digest-md5.patch new file mode 100644 index 0000000..5f7f1dc --- /dev/null +++ b/asmack-master/patch/41-fix-digest-md5.patch @@ -0,0 +1,13 @@ +--- ../../src-unpatched/trunk/com/novell/sasl/client/DigestMD5SaslClient.java 2009-12-07 19:14:10.000000000 +0100 ++++ com/novell/sasl/client/DigestMD5SaslClient.java 2009-12-07 19:19:07.000000000 +0100 +@@ -673,8 +673,8 @@ + digestResponse.append("00000001"); //nounce count + digestResponse.append(",qop="); + digestResponse.append(m_qopValue); +- digestResponse.append(",digest-uri=\"ldap/"); +- digestResponse.append(m_serverName); ++ digestResponse.append(",digest-uri=\""); ++ digestResponse.append(m_digestURI); + digestResponse.append("\",response="); + digestResponse.append(response); + digestResponse.append(",charset=utf-8,nonce=\""); diff --git a/asmack-master/patch/beem/10-PubSubManager-non-final.patch b/asmack-master/patch/beem/10-PubSubManager-non-final.patch new file mode 100644 index 0000000..4fca228 --- /dev/null +++ b/asmack-master/patch/beem/10-PubSubManager-non-final.patch @@ -0,0 +1,13 @@ +Index: org/jivesoftware/smackx/pubsub/PubSubManager.java +=================================================================== +--- org/jivesoftware/smackx/pubsub/PubSubManager.java (revision 11464) ++++ org/jivesoftware/smackx/pubsub/PubSubManager.java (working copy) +@@ -41,7 +41,7 @@ + *
+ * @author Robin Collier
+ */
+-final public class PubSubManager
++public class PubSubManager
+ {
+ private XMPPConnection con;
+ private String to;
diff --git a/asmack-master/patch/beem/50-improved-pubsub.patch b/asmack-master/patch/beem/50-improved-pubsub.patch new file mode 100644 index 0000000..a3704e7 --- /dev/null +++ b/asmack-master/patch/beem/50-improved-pubsub.patch @@ -0,0 +1,46 @@ +--- ../../../src/smack/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java (révision 11644) ++++ org/jivesoftware/smackx/pubsub/provider/ItemProvider.java (copie de travail) +@@ -45,6 +45,8 @@ + }
+ else
+ {
++ while (tag != XmlPullParser.START_TAG)
++ tag = parser.next();
+ String payloadElemName = parser.getName();
+ String payloadNS = parser.getNamespace();
+
+--- ../../../src/org/jivesoftware/smackx/pubsub/Node.java (révision 11644) ++++ org/jivesoftware/smackx/pubsub/Node.java (copie de travail) +@@ -60,7 +60,7 @@ + *
+ * For example, OpenFire requires the server to be prefixed by <b>pubsub</b>
+ */
+- void setTo(String toAddress)
++ public void setTo(String toAddress)
+ {
+ to = toAddress;
+ }
+--- ../../../src/org/jivesoftware/smackx/pubsub/LeafNode.java (révision 11644) ++++ org/jivesoftware/smackx/pubsub/LeafNode.java (copie de travail) +@@ -34,7 +34,7 @@ + */
+ public class LeafNode extends Node
+ {
+- LeafNode(Connection connection, String nodeName)
++ public LeafNode(Connection connection, String nodeName)
+ {
+ super(connection, nodeName);
+ }
+--- ../../../src/org/jivesoftware/smackx/pubsub/PubSubManager.java (révision 11644) ++++ org/jivesoftware/smackx/pubsub/PubSubManager.java (copie de travail) +@@ -43,8 +43,8 @@ + */
+ final public class PubSubManager
+ {
+- private Connection con;
+- private String to;
++ protected Connection con;
++ protected String to;
+ private Map<String, Node> nodeMap = new ConcurrentHashMap<String, Node>();
+
+ /**
diff --git a/asmack-master/patch/beem/COPYING b/asmack-master/patch/beem/COPYING new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/asmack-master/patch/beem/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/asmack-master/patch/beem/README.txt b/asmack-master/patch/beem/README.txt new file mode 100644 index 0000000..ce58c89 --- /dev/null +++ b/asmack-master/patch/beem/README.txt @@ -0,0 +1,9 @@ +This directory contains different patch to apply on asmack sources. These +patches will allow us to build a custom flavour of asmack for Beem. This +directory must be copied in the patch directory of asmack in order to be used. +Then build asmack the usual way. + +All the patches are released under the Apache License, Version 2.0 +You may obtain a copy of the License at +http://www.apache.org.licenses/LICENCE-2.0 + diff --git a/asmack-master/patch/oldpatch/45-protected-xmpp-socket.patch b/asmack-master/patch/oldpatch/45-protected-xmpp-socket.patch new file mode 100644 index 0000000..72f2d97 --- /dev/null +++ b/asmack-master/patch/oldpatch/45-protected-xmpp-socket.patch @@ -0,0 +1,11 @@ +--- org/jivesoftware/smack/XMPPConnection.java 2010-02-13 11:13:16.478541616 +0100 ++++ org/jivesoftware/smack/XMPPConnection.java 2010-02-13 11:58:49.798590947 +0100 +@@ -55,7 +55,7 @@ + /** + * The socket which is used for this connection. + */ +- Socket socket; ++ protected Socket socket; + + String connectionID = null; + private String user = null; diff --git a/asmack-master/static-src/custom/META-INF/services/com.kenai.jbosh.HTTPSender b/asmack-master/static-src/custom/META-INF/services/com.kenai.jbosh.HTTPSender new file mode 100644 index 0000000..3608d8e --- /dev/null +++ b/asmack-master/static-src/custom/META-INF/services/com.kenai.jbosh.HTTPSender @@ -0,0 +1 @@ +com.kenai.jbosh.ApacheHTTPSender diff --git a/asmack-master/static-src/custom/com/kenai/jbosh/QName.java b/asmack-master/static-src/custom/com/kenai/jbosh/QName.java new file mode 100644 index 0000000..d395a06 --- /dev/null +++ b/asmack-master/static-src/custom/com/kenai/jbosh/QName.java @@ -0,0 +1,269 @@ +/* + * The Apache Software License, Version 1.1 + * + * + * Copyright (c) 2001-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Axis" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ +package com.kenai.jbosh; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + +/** + * <code>QName</code> class represents the value of a qualified name + * as specified in <a href="http://www.w3.org/TR/xmlschema-2/#QName">XML + * Schema Part2: Datatypes specification</a>. + * <p> + * The value of a QName contains a <b>namespaceURI</b>, a <b>localPart</b> and a <b>prefix</b>. + * The localPart provides the local part of the qualified name. The + * namespaceURI is a URI reference identifying the namespace. + * + * @version 1.1 + */ +public class QName implements Serializable { + + /** comment/shared empty string */ + private static final String emptyString = "".intern(); + + /** Field namespaceURI */ + private String namespaceURI; + + /** Field localPart */ + private String localPart; + + /** Field prefix */ + private String prefix; + + /** + * Constructor for the QName. + * + * @param localPart Local part of the QName + */ + public QName(String localPart) { + this(emptyString, localPart, emptyString); + } + + /** + * Constructor for the QName. + * + * @param namespaceURI Namespace URI for the QName + * @param localPart Local part of the QName. + */ + public QName(String namespaceURI, String localPart) { + this(namespaceURI, localPart, emptyString); + } + + /** + * Constructor for the QName. + * + * @param namespaceURI Namespace URI for the QName + * @param localPart Local part of the QName. + * @param prefix Prefix of the QName. + */ + public QName(String namespaceURI, String localPart, String prefix) { + this.namespaceURI = (namespaceURI == null) + ? emptyString + : namespaceURI.intern(); + if (localPart == null) { + throw new IllegalArgumentException("invalid QName local part"); + } else { + this.localPart = localPart.intern(); + } + + if (prefix == null) { + throw new IllegalArgumentException("invalid QName prefix"); + } else { + this.prefix = prefix.intern(); + } + } + + /** + * Gets the Namespace URI for this QName + * + * @return Namespace URI + */ + public String getNamespaceURI() { + return namespaceURI; + } + + /** + * Gets the Local part for this QName + * + * @return Local part + */ + public String getLocalPart() { + return localPart; + } + + /** + * Gets the Prefix for this QName + * + * @return Prefix + */ + public String getPrefix() { + return prefix; + } + + /** + * Returns a string representation of this QName + * + * @return a string representation of the QName + */ + public String toString() { + + return ((namespaceURI == emptyString) + ? localPart + : '{' + namespaceURI + '}' + localPart); + } + + /** + * Tests this QName for equality with another object. + * <p> + * If the given object is not a QName or is null then this method + * returns <tt>false</tt>. + * <p> + * For two QNames to be considered equal requires that both + * localPart and namespaceURI must be equal. This method uses + * <code>String.equals</code> to check equality of localPart + * and namespaceURI. Any class that extends QName is required + * to satisfy this equality contract. + * <p> + * This method satisfies the general contract of the <code>Object.equals</code> method. + * + * @param obj the reference object with which to compare + * + * @return <code>true</code> if the given object is identical to this + * QName: <code>false</code> otherwise. + */ + public final boolean equals(Object obj) { + + if (obj == this) { + return true; + } + + if (!(obj instanceof QName)) { + return false; + } + + if ((namespaceURI == ((QName) obj).namespaceURI) + && (localPart == ((QName) obj).localPart)) { + return true; + } + + return false; + } + + /** + * Returns a QName holding the value of the specified String. + * <p> + * The string must be in the form returned by the QName.toString() + * method, i.e. "{namespaceURI}localPart", with the "{namespaceURI}" + * part being optional. + * <p> + * This method doesn't do a full validation of the resulting QName. + * In particular, it doesn't check that the resulting namespace URI + * is a legal URI (per RFC 2396 and RFC 2732), nor that the resulting + * local part is a legal NCName per the XML Namespaces specification. + * + * @param s the string to be parsed + * @throws java.lang.IllegalArgumentException If the specified String cannot be parsed as a QName + * @return QName corresponding to the given String + */ + public static QName valueOf(String s) { + + if ((s == null) || s.equals("")) { + throw new IllegalArgumentException("invalid QName literal"); + } + + if (s.charAt(0) == '{') { + int i = s.indexOf('}'); + + if (i == -1) { + throw new IllegalArgumentException("invalid QName literal"); + } + + if (i == s.length() - 1) { + throw new IllegalArgumentException("invalid QName literal"); + } else { + return new QName(s.substring(1, i), s.substring(i + 1)); + } + } else { + return new QName(s); + } + } + + /** + * Returns a hash code value for this QName object. The hash code + * is based on both the localPart and namespaceURI parts of the + * QName. This method satisfies the general contract of the + * <code>Object.hashCode</code> method. + * + * @return a hash code value for this Qname object + */ + public final int hashCode() { + return namespaceURI.hashCode() ^ localPart.hashCode(); + } + + /** + * Ensure that deserialization properly interns the results. + * @param in the ObjectInputStream to be read + */ + private void readObject(ObjectInputStream in) throws + IOException, ClassNotFoundException { + in.defaultReadObject(); + + namespaceURI = namespaceURI.intern(); + localPart = localPart.intern(); + prefix = prefix.intern(); + } +} + diff --git a/asmack-master/static-src/custom/de/measite/smack/AndroidDebugger.java b/asmack-master/static-src/custom/de/measite/smack/AndroidDebugger.java new file mode 100644 index 0000000..4dfc622 --- /dev/null +++ b/asmack-master/static-src/custom/de/measite/smack/AndroidDebugger.java @@ -0,0 +1,185 @@ +package de.measite.smack; + +import org.jivesoftware.smack.debugger.SmackDebugger; +import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.Connection; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.util.*; + +import android.util.Log; + +import java.io.Reader; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Very simple debugger that prints to the android log the sent and received stanzas. Use + * this debugger with caution since printing to the console is an expensive operation that may + * even block the thread since only one thread may print at a time.<p> + * <p/> + * It is possible to not only print the raw sent and received stanzas but also the interpreted + * packets by Smack. By default interpreted packets won't be printed. To enable this feature + * just change the <tt>printInterpreted</tt> static variable to <tt>true</tt>. + * + * @author Gaston Dombiak + */ +public class AndroidDebugger implements SmackDebugger { + + public static boolean printInterpreted = false; + private SimpleDateFormat dateFormatter = new SimpleDateFormat("hh:mm:ss aaa"); + + private Connection connection = null; + + private PacketListener listener = null; + private ConnectionListener connListener = null; + + private Writer writer; + private Reader reader; + private ReaderListener readerListener; + private WriterListener writerListener; + + public AndroidDebugger(Connection connection, Writer writer, Reader reader) { + this.connection = connection; + this.writer = writer; + this.reader = reader; + createDebug(); + } + + /** + * Creates the listeners that will print in the console when new activity is detected. + */ + private void createDebug() { + // Create a special Reader that wraps the main Reader and logs data to the GUI. + ObservableReader debugReader = new ObservableReader(reader); + readerListener = new ReaderListener() { + public void read(String str) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " RCV (" + connection.hashCode() + + "): " + + str); + } + }; + debugReader.addReaderListener(readerListener); + + // Create a special Writer that wraps the main Writer and logs data to the GUI. + ObservableWriter debugWriter = new ObservableWriter(writer); + writerListener = new WriterListener() { + public void write(String str) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " SENT (" + connection.hashCode() + + "): " + + str); + } + }; + debugWriter.addWriterListener(writerListener); + + // Assign the reader/writer objects to use the debug versions. The packet reader + // and writer will use the debug versions when they are created. + reader = debugReader; + writer = debugWriter; + + // Create a thread that will listen for all incoming packets and write them to + // the GUI. This is what we call "interpreted" packet data, since it's the packet + // data as Smack sees it and not as it's coming in as raw XML. + listener = new PacketListener() { + public void processPacket(Packet packet) { + if (printInterpreted) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " RCV PKT (" + + connection.hashCode() + + "): " + + packet.toXML()); + } + } + }; + + connListener = new ConnectionListener() { + public void connectionClosed() { + Log.d("SMACK", + dateFormatter.format(new Date()) + " Connection closed (" + + connection.hashCode() + + ")"); + } + + public void connectionClosedOnError(Exception e) { + Log.d("SMACK", + dateFormatter.format(new Date()) + + " Connection closed due to an exception (" + + connection.hashCode() + + ")"); + e.printStackTrace(); + } + public void reconnectionFailed(Exception e) { + Log.d("SMACK", + dateFormatter.format(new Date()) + + " Reconnection failed due to an exception (" + + connection.hashCode() + + ")"); + e.printStackTrace(); + } + public void reconnectionSuccessful() { + Log.d("SMACK", + dateFormatter.format(new Date()) + " Connection reconnected (" + + connection.hashCode() + + ")"); + } + public void reconnectingIn(int seconds) { + Log.d("SMACK", + dateFormatter.format(new Date()) + " Connection (" + + connection.hashCode() + + ") will reconnect in " + seconds); + } + }; + } + + public Reader newConnectionReader(Reader newReader) { + ((ObservableReader)reader).removeReaderListener(readerListener); + ObservableReader debugReader = new ObservableReader(newReader); + debugReader.addReaderListener(readerListener); + reader = debugReader; + return reader; + } + + public Writer newConnectionWriter(Writer newWriter) { + ((ObservableWriter)writer).removeWriterListener(writerListener); + ObservableWriter debugWriter = new ObservableWriter(newWriter); + debugWriter.addWriterListener(writerListener); + writer = debugWriter; + return writer; + } + + public void userHasLogged(String user) { + boolean isAnonymous = "".equals(StringUtils.parseName(user)); + String title = + "User logged (" + connection.hashCode() + "): " + + (isAnonymous ? "" : StringUtils.parseBareAddress(user)) + + "@" + + connection.getServiceName() + + ":" + + connection.getPort(); + title += "/" + StringUtils.parseResource(user); + Log.d("SMACK", title); + // Add the connection listener to the connection so that the debugger can be notified + // whenever the connection is closed. + connection.addConnectionListener(connListener); + } + + public Reader getReader() { + return reader; + } + + public Writer getWriter() { + return writer; + } + + public PacketListener getReaderListener() { + return listener; + } + + public PacketListener getWriterListener() { + return null; + } +} + diff --git a/asmack-master/static-src/custom/de/measite/smack/Sasl.java b/asmack-master/static-src/custom/de/measite/smack/Sasl.java new file mode 100644 index 0000000..a59135d --- /dev/null +++ b/asmack-master/static-src/custom/de/measite/smack/Sasl.java @@ -0,0 +1,108 @@ +/* + * Copyright 2009 Rene Treffer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package de.measite.smack; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Map; + +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.sasl.SaslClient; +import org.apache.harmony.javax.security.sasl.SaslException; +import org.apache.harmony.javax.security.sasl.SaslServer; +import org.apache.harmony.javax.security.sasl.SaslServerFactory; + +public class Sasl { + + // SaslClientFactory service name + private static final String CLIENTFACTORYSRV = "SaslClientFactory"; //$NON-NLS-1$ + + // SaslServerFactory service name + private static final String SERVERFACTORYSRV = "SaslServerFactory"; //$NON-NLS-1$ + + public static final String POLICY_NOPLAINTEXT = "javax.security.sasl.policy.noplaintext"; //$NON-NLS-1$ + + public static final String POLICY_NOACTIVE = "javax.security.sasl.policy.noactive"; //$NON-NLS-1$ + + public static final String POLICY_NODICTIONARY = "javax.security.sasl.policy.nodictionary"; //$NON-NLS-1$ + + public static final String POLICY_NOANONYMOUS = "javax.security.sasl.policy.noanonymous"; //$NON-NLS-1$ + + public static final String POLICY_FORWARD_SECRECY = "javax.security.sasl.policy.forward"; //$NON-NLS-1$ + + public static final String POLICY_PASS_CREDENTIALS = "javax.security.sasl.policy.credentials"; //$NON-NLS-1$ + + public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer"; //$NON-NLS-1$ + + public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize"; //$NON-NLS-1$ + + public static final String REUSE = "javax.security.sasl.reuse"; //$NON-NLS-1$ + + public static final String QOP = "javax.security.sasl.qop"; //$NON-NLS-1$ + + public static final String STRENGTH = "javax.security.sasl.strength"; //$NON-NLS-1$ + + public static final String SERVER_AUTH = "javax.security.sasl.server.authentication"; //$NON-NLS-1$ + + public static Enumeration<SaslClientFactory> getSaslClientFactories() { + Hashtable<SaslClientFactory,Object> factories = new Hashtable<SaslClientFactory,Object>(); + factories.put(new SaslClientFactory(), new Object()); + return factories.keys(); + } + + public static Enumeration<SaslServerFactory> getSaslServerFactories() { + return org.apache.harmony.javax.security.sasl.Sasl.getSaslServerFactories(); + } + + public static SaslServer createSaslServer(String mechanism, String protocol, + String serverName, Map<String, ?> prop, CallbackHandler cbh) throws SaslException { + return org.apache.harmony.javax.security.sasl.Sasl.createSaslServer(mechanism, protocol, serverName, prop, cbh); + } + + public static SaslClient createSaslClient(String[] mechanisms, String authanticationID, + String protocol, String serverName, Map<String, ?> prop, CallbackHandler cbh) + throws SaslException { + if (mechanisms == null) { + throw new NullPointerException("auth.33"); //$NON-NLS-1$ + } + SaslClientFactory fact = getSaslClientFactories().nextElement(); + String[] mech = fact.getMechanismNames(null); + boolean is = false; + if (mech != null) { + for (int j = 0; j < mech.length; j++) { + for (int n = 0; n < mechanisms.length; n++) { + if (mech[j].equals(mechanisms[n])) { + is = true; + break; + } + } + } + } + if (is) { + return fact.createSaslClient( + mechanisms, + authanticationID, + protocol, + serverName, + prop, + cbh + ); + } + return null; + } + +} diff --git a/asmack-master/static-src/custom/de/measite/smack/SaslClientFactory.java b/asmack-master/static-src/custom/de/measite/smack/SaslClientFactory.java new file mode 100644 index 0000000..2fa1ebd --- /dev/null +++ b/asmack-master/static-src/custom/de/measite/smack/SaslClientFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Rene Treffer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package de.measite.smack; + +import java.util.Map; + +import com.novell.sasl.client.DigestMD5SaslClient; + +import org.apache.harmony.javax.security.auth.callback.CallbackHandler; +import org.apache.harmony.javax.security.sasl.SaslClient; +import org.apache.harmony.javax.security.sasl.SaslException; +import org.apache.qpid.management.common.sasl.PlainSaslClient; + +public class SaslClientFactory implements + org.apache.harmony.javax.security.sasl.SaslClientFactory { + + @Override + public SaslClient createSaslClient(String[] mechanisms, + String authorizationId, String protocol, String serverName, + Map<String, ?> props, CallbackHandler cbh) throws SaslException { + for (String mech: mechanisms) { + if ("PLAIN".equals(mech)) { + return new PlainSaslClient(authorizationId, cbh); + } else + if ("DIGEST-MD5".equals(mech)) { + return DigestMD5SaslClient.getClient( + authorizationId, + protocol, + serverName, + props, + cbh + ); + } + } + return null; + } + + @Override + public String[] getMechanismNames(Map<String, ?> props) { + return new String[]{ + "PLAIN", + "DIGEST-MD5" + }; + } + +} diff --git a/asmack-master/static-src/custom/org/jivesoftware/smack/AndroidConnectionConfiguration.java b/asmack-master/static-src/custom/org/jivesoftware/smack/AndroidConnectionConfiguration.java new file mode 100644 index 0000000..6ec05e0 --- /dev/null +++ b/asmack-master/static-src/custom/org/jivesoftware/smack/AndroidConnectionConfiguration.java @@ -0,0 +1,113 @@ +package org.jivesoftware.smack; + +import java.io.File; + +import android.os.Build; + +import org.jivesoftware.smack.proxy.ProxyInfo; +import org.jivesoftware.smack.util.DNSUtil; +import org.jivesoftware.smack.util.dns.HostAddress; + +import java.util.List; + +/** + * This class wraps DNS SRV lookups for a new ConnectionConfiguration in a + * new thread, since Android API >= 11 (Honeycomb) does not allow network + * activity in the main thread. + * + * @author Florian Schmaus fschmaus@gmail.com + * + */ +public class AndroidConnectionConfiguration extends ConnectionConfiguration { + private static final int DEFAULT_TIMEOUT = 10000; + + /** + * Creates a new ConnectionConfiguration for the specified service name. + * A DNS SRV lookup will be performed to find out the actual host address + * and port to use for the connection. + * + * @param serviceName the name of the service provided by an XMPP server. + */ + public AndroidConnectionConfiguration(String serviceName) throws XMPPException { + super(); + AndroidInit(serviceName, DEFAULT_TIMEOUT); + } + + /** + * + * @param serviceName + * @param timeout + * @throws XMPPException + */ + public AndroidConnectionConfiguration(String serviceName, int timeout) throws XMPPException { + super(); + AndroidInit(serviceName, timeout); + } + + public AndroidConnectionConfiguration(String host, int port, String name) { + super(host, port, name); + AndroidInit(); + } + + private void AndroidInit() { + // API 14 is Ice Cream Sandwich + if (Build.VERSION.SDK_INT >= 14) { + setTruststoreType("AndroidCAStore"); + setTruststorePassword(null); + setTruststorePath(null); + } else { + setTruststoreType("BKS"); + String path = System.getProperty("javax.net.ssl.trustStore"); + if (path == null) + path = System.getProperty("java.home") + File.separator + "etc" + + File.separator + "security" + File.separator + + "cacerts.bks"; + setTruststorePath(path); + } + } + + /** + * + * @param serviceName + * @param timeout + * @throws XMPPException + */ + private void AndroidInit(String serviceName, int timeout) throws XMPPException { + AndroidInit(); + class DnsSrvLookupRunnable implements Runnable { + String serviceName; + List<HostAddress> addresses; + + public DnsSrvLookupRunnable(String serviceName) { + this.serviceName = serviceName; + } + + @Override + public void run() { + addresses = DNSUtil.resolveXMPPDomain(serviceName); + } + + public List<HostAddress> getHostAddresses() { + return addresses; + } + } + + DnsSrvLookupRunnable dnsSrv = new DnsSrvLookupRunnable(serviceName); + Thread t = new Thread(dnsSrv, "dns-srv-lookup"); + t.start(); + try { + t.join(timeout); + } catch (InterruptedException e) { + throw new XMPPException("DNS lookup timeout after " + timeout + "ms", e); + } + + hostAddresses = dnsSrv.getHostAddresses(); + if (hostAddresses == null) { + throw new XMPPException("DNS lookup failure"); + } + + ProxyInfo proxy = ProxyInfo.forDefaultProxy(); + + init(serviceName, proxy); + } +} diff --git a/asmack-master/static-src/custom/org/jivesoftware/smack/SmackAndroid.java b/asmack-master/static-src/custom/org/jivesoftware/smack/SmackAndroid.java new file mode 100644 index 0000000..a18d675 --- /dev/null +++ b/asmack-master/static-src/custom/org/jivesoftware/smack/SmackAndroid.java @@ -0,0 +1,59 @@ +package org.jivesoftware.smack; + +import org.jivesoftware.smack.util.DNSUtil; +import org.jivesoftware.smack.util.dns.DNSJavaResolver; +import org.jivesoftware.smackx.ConfigureProviderManager; +import org.jivesoftware.smackx.InitStaticCode; +import org.xbill.DNS.ResolverConfig; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +public class SmackAndroid { + private static SmackAndroid sSmackAndroid = null; + + private BroadcastReceiver mConnectivityChangedReceiver; + private Context mCtx; + + private SmackAndroid(Context ctx) { + mCtx = ctx; + DNSUtil.setDNSResolver(DNSJavaResolver.getInstance()); + InitStaticCode.initStaticCode(ctx); + ConfigureProviderManager.configureProviderManager(); + maybeRegisterReceiver(); + } + + public static SmackAndroid init(Context ctx) { + if (sSmackAndroid == null) { + sSmackAndroid = new SmackAndroid(ctx); + } else { + sSmackAndroid.maybeRegisterReceiver(); + } + return sSmackAndroid; + } + + public void onDestroy() { + if (mConnectivityChangedReceiver != null) { + mCtx.unregisterReceiver(mConnectivityChangedReceiver); + mConnectivityChangedReceiver = null; + } + } + + private void maybeRegisterReceiver() { + if (mConnectivityChangedReceiver == null) { + mConnectivityChangedReceiver = new ConnectivtyChangedReceiver(); + mCtx.registerReceiver(mConnectivityChangedReceiver, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")); + } + } + + class ConnectivtyChangedReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + ResolverConfig.refresh(); + } + + } +} diff --git a/asmack-master/static-src/custom/org/jivesoftware/smackx/ConfigureProviderManager.java b/asmack-master/static-src/custom/org/jivesoftware/smackx/ConfigureProviderManager.java new file mode 100644 index 0000000..7c0cdf2 --- /dev/null +++ b/asmack-master/static-src/custom/org/jivesoftware/smackx/ConfigureProviderManager.java @@ -0,0 +1,207 @@ +/** + * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jivesoftware.smackx; + +import org.jivesoftware.smack.provider.PrivacyProvider; +import org.jivesoftware.smack.provider.ProviderManager; +import org.jivesoftware.smackx.GroupChatInvitation; +import org.jivesoftware.smackx.PrivateDataManager; +import org.jivesoftware.smackx.bytestreams.ibb.provider.CloseIQProvider; +import org.jivesoftware.smackx.bytestreams.ibb.provider.DataPacketProvider; +import org.jivesoftware.smackx.bytestreams.ibb.provider.OpenIQProvider; +import org.jivesoftware.smackx.bytestreams.socks5.provider.BytestreamsProvider; +import org.jivesoftware.smackx.carbons.Carbon; +import org.jivesoftware.smackx.entitycaps.provider.CapsExtensionProvider; +import org.jivesoftware.smackx.forward.Forwarded; +import org.jivesoftware.smackx.packet.AttentionExtension; +import org.jivesoftware.smackx.packet.ChatStateExtension; +import org.jivesoftware.smackx.packet.LastActivity; +import org.jivesoftware.smackx.packet.Nick; +import org.jivesoftware.smackx.packet.OfflineMessageInfo; +import org.jivesoftware.smackx.packet.OfflineMessageRequest; +import org.jivesoftware.smackx.packet.SharedGroupsInfo; +import org.jivesoftware.smackx.ping.provider.PingProvider; +import org.jivesoftware.smackx.provider.DataFormProvider; +import org.jivesoftware.smackx.provider.DelayInformationProvider; +import org.jivesoftware.smackx.provider.DiscoverInfoProvider; +import org.jivesoftware.smackx.provider.DiscoverItemsProvider; +import org.jivesoftware.smackx.provider.HeadersProvider; +import org.jivesoftware.smackx.provider.HeaderProvider; +import org.jivesoftware.smackx.provider.MUCAdminProvider; +import org.jivesoftware.smackx.provider.MUCOwnerProvider; +import org.jivesoftware.smackx.provider.MUCUserProvider; +import org.jivesoftware.smackx.provider.MessageEventProvider; +import org.jivesoftware.smackx.provider.MultipleAddressesProvider; +import org.jivesoftware.smackx.provider.RosterExchangeProvider; +import org.jivesoftware.smackx.provider.StreamInitiationProvider; +import org.jivesoftware.smackx.provider.VCardProvider; +import org.jivesoftware.smackx.provider.XHTMLExtensionProvider; +import org.jivesoftware.smackx.pubsub.provider.AffiliationProvider; +import org.jivesoftware.smackx.pubsub.provider.AffiliationsProvider; +import org.jivesoftware.smackx.pubsub.provider.ConfigEventProvider; +import org.jivesoftware.smackx.pubsub.provider.EventProvider; +import org.jivesoftware.smackx.pubsub.provider.FormNodeProvider; +import org.jivesoftware.smackx.pubsub.provider.ItemProvider; +import org.jivesoftware.smackx.pubsub.provider.ItemsProvider; +import org.jivesoftware.smackx.pubsub.provider.PubSubProvider; +import org.jivesoftware.smackx.pubsub.provider.RetractEventProvider; +import org.jivesoftware.smackx.pubsub.provider.SimpleNodeProvider; +import org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider; +import org.jivesoftware.smackx.pubsub.provider.SubscriptionsProvider; +import org.jivesoftware.smackx.receipts.DeliveryReceipt; +import org.jivesoftware.smackx.search.UserSearch; + +/** + * Since dalvik on Android does not allow the loading of META-INF files from the + * filesystem, you have to register every provider manually. + * + * The full list of providers is at: + * http://fisheye.igniterealtime.org/browse/smack/trunk/build/resources/META-INF/smack.providers?hb=true + * + * @author Florian Schmaus fschmaus@gmail.com + * + */ +public class ConfigureProviderManager { + + public static void configureProviderManager() { + ProviderManager pm = ProviderManager.getInstance(); + + // The order is the same as in the smack.providers file + + // Private Data Storage + pm.addIQProvider("query","jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider()); + // Time + try { + pm.addIQProvider("query","jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time")); + } catch (ClassNotFoundException e) { + System.err.println("Can't load class for org.jivesoftware.smackx.packet.Time"); + } + + // Roster Exchange + pm.addExtensionProvider("x","jabber:x:roster", new RosterExchangeProvider()); + // Message Events + pm.addExtensionProvider("x","jabber:x:event", new MessageEventProvider()); + // Chat State + pm.addExtensionProvider("active","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); + pm.addExtensionProvider("composing","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); + pm.addExtensionProvider("paused","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); + pm.addExtensionProvider("inactive","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); + pm.addExtensionProvider("gone","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); + + // XHTML + pm.addExtensionProvider("html","http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider()); + + // Group Chat Invitations + pm.addExtensionProvider("x","jabber:x:conference", new GroupChatInvitation.Provider()); + // Service Discovery # Items + pm.addIQProvider("query","http://jabber.org/protocol/disco#items", new DiscoverItemsProvider()); + // Service Discovery # Info + pm.addIQProvider("query","http://jabber.org/protocol/disco#info", new DiscoverInfoProvider()); + // Data Forms + pm.addExtensionProvider("x","jabber:x:data", new DataFormProvider()); + // MUC User + pm.addExtensionProvider("x","http://jabber.org/protocol/muc#user", new MUCUserProvider()); + // MUC Admin + pm.addIQProvider("query","http://jabber.org/protocol/muc#admin", new MUCAdminProvider()); + // MUC Owner + pm.addIQProvider("query","http://jabber.org/protocol/muc#owner", new MUCOwnerProvider()); + // Delayed Delivery + pm.addExtensionProvider("x","jabber:x:delay", new DelayInformationProvider()); + pm.addExtensionProvider("delay", "urn:xmpp:delay", new DelayInformationProvider()); + // Version + try { + pm.addIQProvider("query","jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version")); + } catch (ClassNotFoundException e) { + System.err.println("Can't load class for org.jivesoftware.smackx.packet.Version"); + } + // VCard + pm.addIQProvider("vCard","vcard-temp", new VCardProvider()); + // Offline Message Requests + pm.addIQProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider()); + // Offline Message Indicator + pm.addExtensionProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider()); + // Last Activity + pm.addIQProvider("query","jabber:iq:last", new LastActivity.Provider()); + // User Search + pm.addIQProvider("query","jabber:iq:search", new UserSearch.Provider()); + // SharedGroupsInfo + pm.addIQProvider("sharedgroup","http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider()); + + // JEP-33: Extended Stanza Addressing + pm.addExtensionProvider("addresses","http://jabber.org/protocol/address", new MultipleAddressesProvider()); + + // FileTransfer + pm.addIQProvider("si","http://jabber.org/protocol/si", new StreamInitiationProvider()); + pm.addIQProvider("query","http://jabber.org/protocol/bytestreams", new BytestreamsProvider()); + pm.addIQProvider("open","http://jabber.org/protocol/ibb", new OpenIQProvider()); + pm.addIQProvider("data","http://jabber.org/protocol/ibb", new DataPacketProvider()); + pm.addIQProvider("close","http://jabber.org/protocol/ibb", new CloseIQProvider()); + pm.addExtensionProvider("data","http://jabber.org/protocol/ibb", new DataPacketProvider()); + + // Privacy + pm.addIQProvider("query","jabber:iq:privacy", new PrivacyProvider()); + + // SHIM + pm.addExtensionProvider("headers", "http://jabber.org/protocol/shim", new HeadersProvider()); + pm.addExtensionProvider("header", "http://jabber.org/protocol/shim", new HeaderProvider()); + + // PubSub + pm.addIQProvider("pubsub", "http://jabber.org/protocol/pubsub", new PubSubProvider()); + pm.addExtensionProvider("create", "http://jabber.org/protocol/pubsub", new SimpleNodeProvider()); + pm.addExtensionProvider("items", "http://jabber.org/protocol/pubsub", new ItemsProvider()); + pm.addExtensionProvider("item", "http://jabber.org/protocol/pubsub", new ItemProvider()); + pm.addExtensionProvider("subscriptions", "http://jabber.org/protocol/pubsub", new SubscriptionsProvider()); + pm.addExtensionProvider("subscription", "http://jabber.org/protocol/pubsub", new SubscriptionProvider()); + pm.addExtensionProvider("affiliations", "http://jabber.org/protocol/pubsub", new AffiliationsProvider()); + pm.addExtensionProvider("affiliation", "http://jabber.org/protocol/pubsub", new AffiliationProvider()); + pm.addExtensionProvider("options", "http://jabber.org/protocol/pubsub", new FormNodeProvider()); + // PubSub owner + pm.addIQProvider("pubsub", "http://jabber.org/protocol/pubsub#owner", new PubSubProvider()); + pm.addExtensionProvider("configure", "http://jabber.org/protocol/pubsub#owner", new FormNodeProvider()); + pm.addExtensionProvider("default", "http://jabber.org/protocol/pubsub#owner", new FormNodeProvider()); + // PubSub event + pm.addExtensionProvider("event", "http://jabber.org/protocol/pubsub#event", new EventProvider()); + pm.addExtensionProvider("configuration", "http://jabber.org/protocol/pubsub#event", new ConfigEventProvider()); + pm.addExtensionProvider("delete", "http://jabber.org/protocol/pubsub#event", new SimpleNodeProvider()); + pm.addExtensionProvider("options", "http://jabber.org/protocol/pubsub#event", new FormNodeProvider()); + pm.addExtensionProvider("items", "http://jabber.org/protocol/pubsub#event", new ItemsProvider()); + pm.addExtensionProvider("item", "http://jabber.org/protocol/pubsub#event", new ItemProvider()); + pm.addExtensionProvider("retract", "http://jabber.org/protocol/pubsub#event", new RetractEventProvider()); + pm.addExtensionProvider("purge", "http://jabber.org/protocol/pubsub#event", new SimpleNodeProvider()); + + // Nick Exchange + pm.addExtensionProvider("nick", "http://jabber.org/protocol/nick", new Nick.Provider()); + + // Attention + pm.addExtensionProvider("attention", "urn:xmpp:attention:0", new AttentionExtension.Provider()); + + // XEP-0297 Stanza Forwarding + pm.addExtensionProvider("forwarded", "urn:xmpp:forward:0", new Forwarded.Provider()); + + // XEP-0280 Message Carbons + pm.addExtensionProvider("sent", "urn:xmpp:carbons:2", new Carbon.Provider()); + pm.addExtensionProvider("received", "urn:xmpp:carbons:2", new Carbon.Provider()); + + // XEP-0199 XMPP Ping + pm.addIQProvider("ping", "urn:xmpp:ping", new PingProvider()); + + // XEP-184 Message Delivery Receipts + pm.addExtensionProvider("received", "urn:xmpp:receipts", new DeliveryReceipt.Provider()); + pm.addExtensionProvider("request", "urn:xmpp:receipts", new DeliveryReceipt.Provider()); + + // XEP-0115 Entity Capabilities + pm.addExtensionProvider("c", "http://jabber.org/protocol/caps", new CapsExtensionProvider()); + } +} diff --git a/asmack-master/static-src/custom/org/jivesoftware/smackx/InitStaticCode.java b/asmack-master/static-src/custom/org/jivesoftware/smackx/InitStaticCode.java new file mode 100644 index 0000000..12de5af --- /dev/null +++ b/asmack-master/static-src/custom/org/jivesoftware/smackx/InitStaticCode.java @@ -0,0 +1,51 @@ +/** + * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jivesoftware.smackx; + +import android.content.Context; + +/** + * Since dalvik on Android does not allow the loading of META-INF files from the + * filesystem, the static blocks of some classes have to be inited manually. + * + * The full list can be found here: + * http://fisheye.igniterealtime.org/browse/smack/trunk/build/resources/META-INF/smack-config.xml?hb=true + * + * @author Florian Schmaus fschmaus@gmail.com + * + */ +public class InitStaticCode { + + public static void initStaticCode(Context ctx) { + // This has the be the application class loader, + // *not* the system class loader + ClassLoader appClassLoader = ctx.getClassLoader(); + + try { + Class.forName(org.jivesoftware.smackx.ServiceDiscoveryManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smack.PrivacyListManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smackx.XHTMLManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smackx.muc.MultiUserChat.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smackx.filetransfer.FileTransferManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smackx.LastActivityManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smack.ReconnectionManager.class.getName(), true, appClassLoader); + Class.forName(org.jivesoftware.smackx.commands.AdHocCommandManager.class.getName(), true, appClassLoader); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Could not init static class blocks", e); + } + } +} diff --git a/asmack-master/static-src/custom/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java b/asmack-master/static-src/custom/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java new file mode 100644 index 0000000..a6b8694 --- /dev/null +++ b/asmack-master/static-src/custom/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java @@ -0,0 +1,92 @@ +/**
+ * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jivesoftware.smackx.pubsub.provider;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.pubsub.Item;
+import org.jivesoftware.smackx.pubsub.PayloadItem;
+import org.jivesoftware.smackx.pubsub.SimplePayload;
+import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Parses an <b>item</b> element as is defined in both the {@link PubSubNamespace#BASIC} and {@link PubSubNamespace#EVENT}
+ * namespaces. To parse the item contents, it will use whatever {@link PacketExtensionProvider} is registered in
+ * <b>smack.providers</b> for its element name and namespace. If no provider is registered, it will return a {@link SimplePayload}.
+ *
+ * @author Robin Collier
+ */
+public class ItemProvider implements PacketExtensionProvider {
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
+ String id = parser.getAttributeValue(null, "id");
+ String node = parser.getAttributeValue(null, "node");
+ String elem = parser.getName();
+
+ int tag = parser.next();
+
+ if (tag == XmlPullParser.END_TAG) {
+ return new Item(id, node);
+ } else {
+ String payloadElemName = parser.getName();
+ String payloadNS = parser.getNamespace();
+
+ if (ProviderManager.getInstance().getExtensionProvider(payloadElemName, payloadNS) == null) {
+ StringBuilder payloadText = new StringBuilder();
+ boolean done = false;
+ boolean isEmptyElement = false;
+
+ // Parse custom payload
+ while (!done) {
+ if (tag == XmlPullParser.END_TAG && parser.getName().equals(elem)) {
+ done = true;
+ } else if (parser.getEventType() == XmlPullParser.START_TAG) {
+ payloadText.append("<").append(parser.getName());
+ if (parser.getName().equals(payloadElemName) && (!"".equals(payloadNS))) {
+ payloadText.append(" xmlns=\"").append(payloadNS).append("\"");
+ }
+ int n = parser.getAttributeCount();
+ for (int i = 0; i < n; i++) {
+ payloadText.append(" ").append(parser.getAttributeName(i)).append("=\"")
+ .append(parser.getAttributeValue(i)).append("\"");
+ }
+ if (parser.isEmptyElementTag()) {
+ payloadText.append("/>");
+ isEmptyElement = true;
+ } else {
+ payloadText.append(">");
+ }
+ } else if (parser.getEventType() == XmlPullParser.END_TAG) {
+ if (isEmptyElement) {
+ isEmptyElement = false;
+ } else {
+ payloadText.append("</").append(parser.getName()).append(">");
+ }
+ } else if (parser.getEventType() == XmlPullParser.TEXT) {
+ payloadText.append(parser.getText());
+ }
+
+ tag = parser.next();
+ }
+ return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS,
+ payloadText.toString()));
+ } else {
+ return new PayloadItem<PacketExtension>(id, node, PacketParserUtils.parsePacketExtension(
+ payloadElemName, payloadNS, parser));
+ }
+ }
+ }
+}
diff --git a/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DigestChallenge.java b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DigestChallenge.java new file mode 100644 index 0000000..90e6247 --- /dev/null +++ b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DigestChallenge.java @@ -0,0 +1,393 @@ +/* ************************************************************************** + * $OpenLDAP: /com/novell/sasl/client/DigestChallenge.java,v 1.3 2005/01/17 15:00:54 sunilk Exp $ + * + * Copyright (C) 2003 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ +package com.novell.sasl.client; + +import java.util.*; +import org.apache.harmony.javax.security.sasl.*; + +/** + * Implements the DigestChallenge class which will be used by the + * DigestMD5SaslClient class + */ +class DigestChallenge extends Object +{ + public static final int QOP_AUTH = 0x01; + public static final int QOP_AUTH_INT = 0x02; + public static final int QOP_AUTH_CONF = 0x04; + public static final int QOP_UNRECOGNIZED = 0x08; + + private static final int CIPHER_3DES = 0x01; + private static final int CIPHER_DES = 0x02; + private static final int CIPHER_RC4_40 = 0x04; + private static final int CIPHER_RC4 = 0x08; + private static final int CIPHER_RC4_56 = 0x10; + private static final int CIPHER_UNRECOGNIZED = 0x20; + private static final int CIPHER_RECOGNIZED_MASK = + CIPHER_3DES | CIPHER_DES | CIPHER_RC4_40 | CIPHER_RC4 | CIPHER_RC4_56; + + private ArrayList m_realms; + private String m_nonce; + private int m_qop; + private boolean m_staleFlag; + private int m_maxBuf; + private String m_characterSet; + private String m_algorithm; + private int m_cipherOptions; + + DigestChallenge( + byte[] challenge) + throws SaslException + { + m_realms = new ArrayList(5); + m_nonce = null; + m_qop = 0; + m_staleFlag = false; + m_maxBuf = -1; + m_characterSet = null; + m_algorithm = null; + m_cipherOptions = 0; + + DirectiveList dirList = new DirectiveList(challenge); + try + { + dirList.parseDirectives(); + checkSemantics(dirList); + } + catch (SaslException e) + { + } + } + + /** + * Checks the semantics of the directives in the directive list as parsed + * from the digest challenge byte array. + * + * @param dirList the list of directives parsed from the digest challenge + * + * @exception SaslException If a semantic error occurs + */ + void checkSemantics( + DirectiveList dirList) throws SaslException + { + Iterator directives = dirList.getIterator(); + ParsedDirective directive; + String name; + + while (directives.hasNext()) + { + directive = (ParsedDirective)directives.next(); + name = directive.getName(); + if (name.equals("realm")) + handleRealm(directive); + else if (name.equals("nonce")) + handleNonce(directive); + else if (name.equals("qop")) + handleQop(directive); + else if (name.equals("maxbuf")) + handleMaxbuf(directive); + else if (name.equals("charset")) + handleCharset(directive); + else if (name.equals("algorithm")) + handleAlgorithm(directive); + else if (name.equals("cipher")) + handleCipher(directive); + else if (name.equals("stale")) + handleStale(directive); + } + + /* post semantic check */ + if (-1 == m_maxBuf) + m_maxBuf = 65536; + + if (m_qop == 0) + m_qop = QOP_AUTH; + else if ( (m_qop & QOP_AUTH) != QOP_AUTH ) + throw new SaslException("Only qop-auth is supported by client"); + else if ( ((m_qop & QOP_AUTH_CONF) == QOP_AUTH_CONF) && + (0 == (m_cipherOptions & CIPHER_RECOGNIZED_MASK)) ) + throw new SaslException("Invalid cipher options"); + else if (null == m_nonce) + throw new SaslException("Missing nonce directive"); + else if (m_staleFlag) + throw new SaslException("Unexpected stale flag"); + else if ( null == m_algorithm ) + throw new SaslException("Missing algorithm directive"); + } + + /** + * This function implements the semenatics of the nonce directive. + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to too many nonce + * values + */ + void handleNonce( + ParsedDirective pd) throws SaslException + { + if (null != m_nonce) + throw new SaslException("Too many nonce values."); + + m_nonce = pd.getValue(); + } + + /** + * This function implements the semenatics of the realm directive. + * + * @param pd ParsedDirective + */ + void handleRealm( + ParsedDirective pd) + { + m_realms.add(pd.getValue()); + } + + /** + * This function implements the semenatics of the qop (quality of protection) + * directive. The value of the qop directive is as defined below: + * qop-options = "qop" "=" <"> qop-list <"> + * qop-list = 1#qop-value + * qop-value = "auth" | "auth-int" | "auth-conf" | token + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to too many qop + * directives + */ + void handleQop( + ParsedDirective pd) throws SaslException + { + String token; + TokenParser parser; + + if (m_qop != 0) + throw new SaslException("Too many qop directives."); + + parser = new TokenParser(pd.getValue()); + for (token = parser.parseToken(); + token != null; + token = parser.parseToken()) + { + if (token.equals("auth")) + m_qop |= QOP_AUTH; + else if (token.equals("auth-int")) + m_qop |= QOP_AUTH_INT; + else if (token.equals("auth-conf")) + m_qop |= QOP_AUTH_CONF; + else + m_qop |= QOP_UNRECOGNIZED; + } + } + + /** + * This function implements the semenatics of the Maxbuf directive. + * the value is defined as: 1*DIGIT + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occur + */ + void handleMaxbuf( + ParsedDirective pd) throws SaslException + { + if (-1 != m_maxBuf) /*it's initialized to -1 */ + throw new SaslException("Too many maxBuf directives."); + + m_maxBuf = Integer.parseInt(pd.getValue()); + + if (0 == m_maxBuf) + throw new SaslException("Max buf value must be greater than zero."); + } + + /** + * This function implements the semenatics of the charset directive. + * the value is defined as: 1*DIGIT + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs dur to too many charset + * directives or Invalid character encoding + * directive + */ + void handleCharset( + ParsedDirective pd) throws SaslException + { + if (null != m_characterSet) + throw new SaslException("Too many charset directives."); + + m_characterSet = pd.getValue(); + + if (!m_characterSet.equals("utf-8")) + throw new SaslException("Invalid character encoding directive"); + } + + /** + * This function implements the semenatics of the charset directive. + * the value is defined as: 1*DIGIT + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to too many algorith + * directive or Invalid algorithm directive + * value + */ + void handleAlgorithm( + ParsedDirective pd) throws SaslException + { + if (null != m_algorithm) + throw new SaslException("Too many algorithm directives."); + + m_algorithm = pd.getValue(); + + if (!"md5-sess".equals(m_algorithm)) + throw new SaslException("Invalid algorithm directive value: " + + m_algorithm); + } + + /** + * This function implements the semenatics of the cipher-opts directive + * directive. The value of the qop directive is as defined below: + * qop-options = "qop" "=" <"> qop-list <"> + * qop-list = 1#qop-value + * qop-value = "auth" | "auth-int" | "auth-conf" | token + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to Too many cipher + * directives + */ + void handleCipher( + ParsedDirective pd) throws SaslException + { + String token; + TokenParser parser; + + if (0 != m_cipherOptions) + throw new SaslException("Too many cipher directives."); + + parser = new TokenParser(pd.getValue()); + token = parser.parseToken(); + for (token = parser.parseToken(); + token != null; + token = parser.parseToken()) + { + if ("3des".equals(token)) + m_cipherOptions |= CIPHER_3DES; + else if ("des".equals(token)) + m_cipherOptions |= CIPHER_DES; + else if ("rc4-40".equals(token)) + m_cipherOptions |= CIPHER_RC4_40; + else if ("rc4".equals(token)) + m_cipherOptions |= CIPHER_RC4; + else if ("rc4-56".equals(token)) + m_cipherOptions |= CIPHER_RC4_56; + else + m_cipherOptions |= CIPHER_UNRECOGNIZED; + } + + if (m_cipherOptions == 0) + m_cipherOptions = CIPHER_UNRECOGNIZED; + } + + /** + * This function implements the semenatics of the stale directive. + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to Too many stale + * directives or Invalid stale directive value + */ + void handleStale( + ParsedDirective pd) throws SaslException + { + if (false != m_staleFlag) + throw new SaslException("Too many stale directives."); + + if ("true".equals(pd.getValue())) + m_staleFlag = true; + else + throw new SaslException("Invalid stale directive value: " + + pd.getValue()); + } + + /** + * Return the list of the All the Realms + * + * @return List of all the realms + */ + public ArrayList getRealms() + { + return m_realms; + } + + /** + * @return Returns the Nonce + */ + public String getNonce() + { + return m_nonce; + } + + /** + * Return the quality-of-protection + * + * @return The quality-of-protection + */ + public int getQop() + { + return m_qop; + } + + /** + * @return The state of the Staleflag + */ + public boolean getStaleFlag() + { + return m_staleFlag; + } + + /** + * @return The Maximum Buffer value + */ + public int getMaxBuf() + { + return m_maxBuf; + } + + /** + * @return character set values as string + */ + public String getCharacterSet() + { + return m_characterSet; + } + + /** + * @return The String value of the algorithm + */ + public String getAlgorithm() + { + return m_algorithm; + } + + /** + * @return The cipher options + */ + public int getCipherOptions() + { + return m_cipherOptions; + } +} + diff --git a/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DigestMD5SaslClient.java b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DigestMD5SaslClient.java new file mode 100644 index 0000000..eb488fe --- /dev/null +++ b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DigestMD5SaslClient.java @@ -0,0 +1,820 @@ +/* ************************************************************************** + * $OpenLDAP: /com/novell/sasl/client/DigestMD5SaslClient.java,v 1.4 2005/01/17 15:00:54 sunilk Exp $ + * + * Copyright (C) 2003 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ +package com.novell.sasl.client; + +import org.apache.harmony.javax.security.sasl.*; +import org.apache.harmony.javax.security.auth.callback.*; +import java.security.SecureRandom; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.io.UnsupportedEncodingException; +import java.io.IOException; +import java.util.*; + +/** + * Implements the Client portion of DigestMD5 Sasl mechanism. + */ +public class DigestMD5SaslClient implements SaslClient +{ + private String m_authorizationId = ""; + private String m_protocol = ""; + private String m_serverName = ""; + private Map m_props; + private CallbackHandler m_cbh; + private int m_state; + private String m_qopValue = ""; + private char[] m_HA1 = null; + private String m_digestURI; + private DigestChallenge m_dc; + private String m_clientNonce = ""; + private String m_realm = ""; + private String m_name = ""; + + private static final int STATE_INITIAL = 0; + private static final int STATE_DIGEST_RESPONSE_SENT = 1; + private static final int STATE_VALID_SERVER_RESPONSE = 2; + private static final int STATE_INVALID_SERVER_RESPONSE = 3; + private static final int STATE_DISPOSED = 4; + + private static final int NONCE_BYTE_COUNT = 32; + private static final int NONCE_HEX_COUNT = 2*NONCE_BYTE_COUNT; + + private static final String DIGEST_METHOD = "AUTHENTICATE"; + + /** + * Creates an DigestMD5SaslClient object using the parameters supplied. + * Assumes that the QOP, STRENGTH, and SERVER_AUTH properties are + * contained in props + * + * @param authorizationId The possibly null protocol-dependent + * identification to be used for authorization. If + * null or empty, the server derives an authorization + * ID from the client's authentication credentials. + * When the SASL authentication completes + * successfully, the specified entity is granted + * access. + * + * @param protocol The non-null string name of the protocol for which + * the authentication is being performed (e.g. "ldap") + * + * @param serverName The non-null fully qualified host name of the server + * to authenticate to + * + * @param props The possibly null set of properties used to select + * the SASL mechanism and to configure the + * authentication exchange of the selected mechanism. + * See the Sasl class for a list of standard properties. + * Other, possibly mechanism-specific, properties can + * be included. Properties not relevant to the selected + * mechanism are ignored. + * + * @param cbh The possibly null callback handler to used by the + * SASL mechanisms to get further information from the + * application/library to complete the authentication. + * For example, a SASL mechanism might require the + * authentication ID, password and realm from the + * caller. The authentication ID is requested by using + * a NameCallback. The password is requested by using + * a PasswordCallback. The realm is requested by using + * a RealmChoiceCallback if there is a list of realms + * to choose from, and by using a RealmCallback if the + * realm must be entered. + * + * @return A possibly null SaslClient created using the + * parameters supplied. If null, this factory cannot + * produce a SaslClient using the parameters supplied. + * + * @exception SaslException If a SaslClient instance cannot be created + * because of an error + */ + public static SaslClient getClient( + String authorizationId, + String protocol, + String serverName, + Map props, + CallbackHandler cbh) + { + String desiredQOP = (String)props.get(Sasl.QOP); + String desiredStrength = (String)props.get(Sasl.STRENGTH); + String serverAuth = (String)props.get(Sasl.SERVER_AUTH); + + //only support qop equal to auth + if ((desiredQOP != null) && !"auth".equals(desiredQOP)) + return null; + + //doesn't support server authentication + if ((serverAuth != null) && !"false".equals(serverAuth)) + return null; + + //need a callback handler to get the password + if (cbh == null) + return null; + + return new DigestMD5SaslClient(authorizationId, protocol, + serverName, props, cbh); + } + + /** + * Creates an DigestMD5SaslClient object using the parameters supplied. + * Assumes that the QOP, STRENGTH, and SERVER_AUTH properties are + * contained in props + * + * @param authorizationId The possibly null protocol-dependent + * identification to be used for authorization. If + * null or empty, the server derives an authorization + * ID from the client's authentication credentials. + * When the SASL authentication completes + * successfully, the specified entity is granted + * access. + * + * @param protocol The non-null string name of the protocol for which + * the authentication is being performed (e.g. "ldap") + * + * @param serverName The non-null fully qualified host name of the server + * to authenticate to + * + * @param props The possibly null set of properties used to select + * the SASL mechanism and to configure the + * authentication exchange of the selected mechanism. + * See the Sasl class for a list of standard properties. + * Other, possibly mechanism-specific, properties can + * be included. Properties not relevant to the selected + * mechanism are ignored. + * + * @param cbh The possibly null callback handler to used by the + * SASL mechanisms to get further information from the + * application/library to complete the authentication. + * For example, a SASL mechanism might require the + * authentication ID, password and realm from the + * caller. The authentication ID is requested by using + * a NameCallback. The password is requested by using + * a PasswordCallback. The realm is requested by using + * a RealmChoiceCallback if there is a list of realms + * to choose from, and by using a RealmCallback if the + * realm must be entered. + * + */ + private DigestMD5SaslClient( + String authorizationId, + String protocol, + String serverName, + Map props, + CallbackHandler cbh) + { + m_authorizationId = authorizationId; + m_protocol = protocol; + m_serverName = serverName; + m_props = props; + m_cbh = cbh; + + m_state = STATE_INITIAL; + } + + /** + * Determines if this mechanism has an optional initial response. If true, + * caller should call evaluateChallenge() with an empty array to get the + * initial response. + * + * @return true if this mechanism has an initial response + */ + public boolean hasInitialResponse() + { + return false; + } + + /** + * Determines if the authentication exchange has completed. This method + * may be called at any time, but typically, it will not be called until + * the caller has received indication from the server (in a protocol- + * specific manner) that the exchange has completed. + * + * @return true if the authentication exchange has completed; + * false otherwise. + */ + public boolean isComplete() + { + if ((m_state == STATE_VALID_SERVER_RESPONSE) || + (m_state == STATE_INVALID_SERVER_RESPONSE) || + (m_state == STATE_DISPOSED)) + return true; + else + return false; + } + + /** + * Unwraps a byte array received from the server. This method can be called + * only after the authentication exchange has completed (i.e., when + * isComplete() returns true) and only if the authentication exchange has + * negotiated integrity and/or privacy as the quality of protection; + * otherwise, an IllegalStateException is thrown. + * + * incoming is the contents of the SASL buffer as defined in RFC 2222 + * without the leading four octet field that represents the length. + * offset and len specify the portion of incoming to use. + * + * @param incoming A non-null byte array containing the encoded bytes + * from the server + * @param offset The starting position at incoming of the bytes to use + * + * @param len The number of bytes from incoming to use + * + * @return A non-null byte array containing the decoded bytes + * + */ + public byte[] unwrap( + byte[] incoming, + int offset, + int len) + throws SaslException + { + throw new IllegalStateException( + "unwrap: QOP has neither integrity nor privacy>"); + } + + /** + * Wraps a byte array to be sent to the server. This method can be called + * only after the authentication exchange has completed (i.e., when + * isComplete() returns true) and only if the authentication exchange has + * negotiated integrity and/or privacy as the quality of protection; + * otherwise, an IllegalStateException is thrown. + * + * The result of this method will make up the contents of the SASL buffer as + * defined in RFC 2222 without the leading four octet field that represents + * the length. offset and len specify the portion of outgoing to use. + * + * @param outgoing A non-null byte array containing the bytes to encode + * @param offset The starting position at outgoing of the bytes to use + * @param len The number of bytes from outgoing to use + * + * @return A non-null byte array containing the encoded bytes + * + * @exception SaslException if incoming cannot be successfully unwrapped. + * + * @exception IllegalStateException if the authentication exchange has + * not completed, or if the negotiated quality of + * protection has neither integrity nor privacy. + */ + public byte[] wrap( + byte[] outgoing, + int offset, + int len) + throws SaslException + { + throw new IllegalStateException( + "wrap: QOP has neither integrity nor privacy>"); + } + + /** + * Retrieves the negotiated property. This method can be called only after + * the authentication exchange has completed (i.e., when isComplete() + * returns true); otherwise, an IllegalStateException is thrown. + * + * @param propName The non-null property name + * + * @return The value of the negotiated property. If null, the property was + * not negotiated or is not applicable to this mechanism. + * + * @exception IllegalStateException if this authentication exchange has + * not completed + */ + public Object getNegotiatedProperty( + String propName) + { + if (m_state != STATE_VALID_SERVER_RESPONSE) + throw new IllegalStateException( + "getNegotiatedProperty: authentication exchange not complete."); + + if (Sasl.QOP.equals(propName)) + return "auth"; + else + return null; + } + + /** + * Disposes of any system resources or security-sensitive information the + * SaslClient might be using. Invoking this method invalidates the + * SaslClient instance. This method is idempotent. + * + * @exception SaslException if a problem was encountered while disposing + * of the resources + */ + public void dispose() + throws SaslException + { + if (m_state != STATE_DISPOSED) + { + m_state = STATE_DISPOSED; + } + } + + /** + * Evaluates the challenge data and generates a response. If a challenge + * is received from the server during the authentication process, this + * method is called to prepare an appropriate next response to submit to + * the server. + * + * @param challenge The non-null challenge sent from the server. The + * challenge array may have zero length. + * + * @return The possibly null reponse to send to the server. It is null + * if the challenge accompanied a "SUCCESS" status and the + * challenge only contains data for the client to update its + * state and no response needs to be sent to the server. + * The response is a zero-length byte array if the client is to + * send a response with no data. + * + * @exception SaslException If an error occurred while processing the + * challenge or generating a response. + */ + public byte[] evaluateChallenge( + byte[] challenge) + throws SaslException + { + byte[] response = null; + + //printState(); + switch (m_state) + { + case STATE_INITIAL: + if (challenge.length == 0) + throw new SaslException("response = byte[0]"); + else + try + { + response = createDigestResponse(challenge). + getBytes("UTF-8"); + m_state = STATE_DIGEST_RESPONSE_SENT; + } + catch (java.io.UnsupportedEncodingException e) + { + throw new SaslException( + "UTF-8 encoding not suppported by platform", e); + } + break; + case STATE_DIGEST_RESPONSE_SENT: + if (checkServerResponseAuth(challenge)) + m_state = STATE_VALID_SERVER_RESPONSE; + else + { + m_state = STATE_INVALID_SERVER_RESPONSE; + throw new SaslException("Could not validate response-auth " + + "value from server"); + } + break; + case STATE_VALID_SERVER_RESPONSE: + case STATE_INVALID_SERVER_RESPONSE: + throw new SaslException("Authentication sequence is complete"); + case STATE_DISPOSED: + throw new SaslException("Client has been disposed"); + default: + throw new SaslException("Unknown client state."); + } + + return response; + } + + /** + * This function takes a 16 byte binary md5-hash value and creates a 32 + * character (plus a terminating null character) hex-digit + * representation of binary data. + * + * @param hash 16 byte binary md5-hash value in bytes + * + * @return 32 character (plus a terminating null character) hex-digit + * representation of binary data. + */ + char[] convertToHex( + byte[] hash) + { + int i; + byte j; + byte fifteen = 15; + char[] hex = new char[32]; + + for (i = 0; i < 16; i++) + { + //convert value of top 4 bits to hex char + hex[i*2] = getHexChar((byte)((hash[i] & 0xf0) >> 4)); + //convert value of bottom 4 bits to hex char + hex[(i*2)+1] = getHexChar((byte)(hash[i] & 0x0f)); + } + + return hex; + } + + /** + * Calculates the HA1 portion of the response + * + * @param algorithm Algorith to use. + * @param userName User being authenticated + * @param realm realm information + * @param password password of teh user + * @param nonce nonce value + * @param clientNonce Clients Nonce value + * + * @return HA1 portion of the response in a character array + * + * @exception SaslException If an error occurs + */ + char[] DigestCalcHA1( + String algorithm, + String userName, + String realm, + String password, + String nonce, + String clientNonce) throws SaslException + { + byte[] hash; + + try + { + MessageDigest md = MessageDigest.getInstance("MD5"); + + md.update(userName.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + md.update(realm.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + md.update(password.getBytes("UTF-8")); + hash = md.digest(); + + if ("md5-sess".equals(algorithm)) + { + md.update(hash); + md.update(":".getBytes("UTF-8")); + md.update(nonce.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + md.update(clientNonce.getBytes("UTF-8")); + hash = md.digest(); + } + } + catch(NoSuchAlgorithmException e) + { + throw new SaslException("No provider found for MD5 hash", e); + } + catch(UnsupportedEncodingException e) + { + throw new SaslException( + "UTF-8 encoding not supported by platform.", e); + } + + return convertToHex(hash); + } + + + /** + * This function calculates the response-value of the response directive of + * the digest-response as documented in RFC 2831 + * + * @param HA1 H(A1) + * @param serverNonce nonce from server + * @param nonceCount 8 hex digits + * @param clientNonce client nonce + * @param qop qop-value: "", "auth", "auth-int" + * @param method method from the request + * @param digestUri requested URL + * @param clientResponseFlag request-digest or response-digest + * + * @return Response-value of the response directive of the digest-response + * + * @exception SaslException If an error occurs + */ + char[] DigestCalcResponse( + char[] HA1, /* H(A1) */ + String serverNonce, /* nonce from server */ + String nonceCount, /* 8 hex digits */ + String clientNonce, /* client nonce */ + String qop, /* qop-value: "", "auth", "auth-int" */ + String method, /* method from the request */ + String digestUri, /* requested URL */ + boolean clientResponseFlag) /* request-digest or response-digest */ + throws SaslException + { + byte[] HA2; + byte[] respHash; + char[] HA2Hex; + + // calculate H(A2) + try + { + MessageDigest md = MessageDigest.getInstance("MD5"); + if (clientResponseFlag) + md.update(method.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + md.update(digestUri.getBytes("UTF-8")); + if ("auth-int".equals(qop)) + { + md.update(":".getBytes("UTF-8")); + md.update("00000000000000000000000000000000".getBytes("UTF-8")); + } + HA2 = md.digest(); + HA2Hex = convertToHex(HA2); + + // calculate response + md.update(new String(HA1).getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + md.update(serverNonce.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + if (qop.length() > 0) + { + md.update(nonceCount.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + md.update(clientNonce.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + md.update(qop.getBytes("UTF-8")); + md.update(":".getBytes("UTF-8")); + } + md.update(new String(HA2Hex).getBytes("UTF-8")); + respHash = md.digest(); + } + catch(NoSuchAlgorithmException e) + { + throw new SaslException("No provider found for MD5 hash", e); + } + catch(UnsupportedEncodingException e) + { + throw new SaslException( + "UTF-8 encoding not supported by platform.", e); + } + + return convertToHex(respHash); + } + + + /** + * Creates the intial response to be sent to the server. + * + * @param challenge Challenge in bytes recived form the Server + * + * @return Initial response to be sent to the server + */ + private String createDigestResponse( + byte[] challenge) + throws SaslException + { + char[] response; + StringBuffer digestResponse = new StringBuffer(512); + int realmSize; + + m_dc = new DigestChallenge(challenge); + + m_digestURI = m_protocol + "/" + m_serverName; + + if ((m_dc.getQop() & DigestChallenge.QOP_AUTH) + == DigestChallenge.QOP_AUTH ) + m_qopValue = "auth"; + else + throw new SaslException("Client only supports qop of 'auth'"); + + //get call back information + Callback[] callbacks = new Callback[3]; + ArrayList realms = m_dc.getRealms(); + realmSize = realms.size(); + if (realmSize == 0) + { + callbacks[0] = new RealmCallback("Realm"); + } + else if (realmSize == 1) + { + callbacks[0] = new RealmCallback("Realm", (String)realms.get(0)); + } + else + { + callbacks[0] = + new RealmChoiceCallback( + "Realm", + (String[])realms.toArray(new String[realmSize]), + 0, //the default choice index + false); //no multiple selections + } + + callbacks[1] = new PasswordCallback("Password", false); + //false = no echo + + if (m_authorizationId == null || m_authorizationId.length() == 0) + callbacks[2] = new NameCallback("Name"); + else + callbacks[2] = new NameCallback("Name", m_authorizationId); + + try + { + m_cbh.handle(callbacks); + } + catch(UnsupportedCallbackException e) + { + throw new SaslException("Handler does not support" + + " necessary callbacks",e); + } + catch(IOException e) + { + throw new SaslException("IO exception in CallbackHandler.", e); + } + + if (realmSize > 1) + { + int[] selections = + ((RealmChoiceCallback)callbacks[0]).getSelectedIndexes(); + + if (selections.length > 0) + m_realm = + ((RealmChoiceCallback)callbacks[0]).getChoices()[selections[0]]; + else + m_realm = ((RealmChoiceCallback)callbacks[0]).getChoices()[0]; + } + else + m_realm = ((RealmCallback)callbacks[0]).getText(); + + m_clientNonce = getClientNonce(); + + m_name = ((NameCallback)callbacks[2]).getName(); + if (m_name == null) + m_name = ((NameCallback)callbacks[2]).getDefaultName(); + if (m_name == null) + throw new SaslException("No user name was specified."); + + m_HA1 = DigestCalcHA1( + m_dc.getAlgorithm(), + m_name, + m_realm, + new String(((PasswordCallback)callbacks[1]).getPassword()), + m_dc.getNonce(), + m_clientNonce); + + response = DigestCalcResponse(m_HA1, + m_dc.getNonce(), + "00000001", + m_clientNonce, + m_qopValue, + "AUTHENTICATE", + m_digestURI, + true); + + digestResponse.append("username=\""); + digestResponse.append(m_authorizationId); + if (0 != m_realm.length()) + { + digestResponse.append("\",realm=\""); + digestResponse.append(m_realm); + } + digestResponse.append("\",cnonce=\""); + digestResponse.append(m_clientNonce); + digestResponse.append("\",nc="); + digestResponse.append("00000001"); //nounce count + digestResponse.append(",qop="); + digestResponse.append(m_qopValue); + digestResponse.append(",digest-uri=\"ldap/"); + digestResponse.append(m_serverName); + digestResponse.append("\",response="); + digestResponse.append(response); + digestResponse.append(",charset=utf-8,nonce=\""); + digestResponse.append(m_dc.getNonce()); + digestResponse.append("\""); + + return digestResponse.toString(); + } + + + /** + * This function validates the server response. This step performs a + * modicum of mutual authentication by verifying that the server knows + * the user's password + * + * @param serverResponse Response recived form Server + * + * @return true if the mutual authentication succeeds; + * else return false + * + * @exception SaslException If an error occurs + */ + boolean checkServerResponseAuth( + byte[] serverResponse) throws SaslException + { + char[] response; + ResponseAuth responseAuth = null; + String responseStr; + + responseAuth = new ResponseAuth(serverResponse); + + response = DigestCalcResponse(m_HA1, + m_dc.getNonce(), + "00000001", + m_clientNonce, + m_qopValue, + DIGEST_METHOD, + m_digestURI, + false); + + responseStr = new String(response); + + return responseStr.equals(responseAuth.getResponseValue()); + } + + + /** + * This function returns hex character representing the value of the input + * + * @param value Input value in byte + * + * @return Hex value of the Input byte value + */ + private static char getHexChar( + byte value) + { + switch (value) + { + case 0: + return '0'; + case 1: + return '1'; + case 2: + return '2'; + case 3: + return '3'; + case 4: + return '4'; + case 5: + return '5'; + case 6: + return '6'; + case 7: + return '7'; + case 8: + return '8'; + case 9: + return '9'; + case 10: + return 'a'; + case 11: + return 'b'; + case 12: + return 'c'; + case 13: + return 'd'; + case 14: + return 'e'; + case 15: + return 'f'; + default: + return 'Z'; + } + } + + /** + * Calculates the Nonce value of the Client + * + * @return Nonce value of the client + * + * @exception SaslException If an error Occurs + */ + String getClientNonce() throws SaslException + { + byte[] nonceBytes = new byte[NONCE_BYTE_COUNT]; + SecureRandom prng; + byte nonceByte; + char[] hexNonce = new char[NONCE_HEX_COUNT]; + + try + { + prng = SecureRandom.getInstance("SHA1PRNG"); + prng.nextBytes(nonceBytes); + for(int i=0; i<NONCE_BYTE_COUNT; i++) + { + //low nibble + hexNonce[i*2] = getHexChar((byte)(nonceBytes[i] & 0x0f)); + //high nibble + hexNonce[(i*2)+1] = getHexChar((byte)((nonceBytes[i] & 0xf0) + >> 4)); + } + return new String(hexNonce); + } + catch(NoSuchAlgorithmException e) + { + throw new SaslException("No random number generator available", e); + } + } + + /** + * Returns the IANA-registered mechanism name of this SASL client. + * (e.g. "CRAM-MD5", "GSSAPI") + * + * @return "DIGEST-MD5"the IANA-registered mechanism name of this SASL + * client. + */ + public String getMechanismName() + { + return "DIGEST-MD5"; + } + +} //end class DigestMD5SaslClient + diff --git a/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DirectiveList.java b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DirectiveList.java new file mode 100644 index 0000000..fc26a6b --- /dev/null +++ b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/DirectiveList.java @@ -0,0 +1,363 @@ +/* ************************************************************************** + * $OpenLDAP: /com/novell/sasl/client/DirectiveList.java,v 1.4 2005/01/17 15:00:54 sunilk Exp $ + * + * Copyright (C) 2002 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ +package com.novell.sasl.client; + +import java.util.*; +import org.apache.harmony.javax.security.sasl.*; +import java.io.UnsupportedEncodingException; + +/** + * Implements the DirectiveList class whihc will be used by the + * DigestMD5SaslClient class + */ +class DirectiveList extends Object +{ + private static final int STATE_LOOKING_FOR_FIRST_DIRECTIVE = 1; + private static final int STATE_LOOKING_FOR_DIRECTIVE = 2; + private static final int STATE_SCANNING_NAME = 3; + private static final int STATE_LOOKING_FOR_EQUALS = 4; + private static final int STATE_LOOKING_FOR_VALUE = 5; + private static final int STATE_LOOKING_FOR_COMMA = 6; + private static final int STATE_SCANNING_QUOTED_STRING_VALUE = 7; + private static final int STATE_SCANNING_TOKEN_VALUE = 8; + private static final int STATE_NO_UTF8_SUPPORT = 9; + + private int m_curPos; + private int m_errorPos; + private String m_directives; + private int m_state; + private ArrayList m_directiveList; + private String m_curName; + private int m_scanStart; + + /** + * Constructs a new DirectiveList. + */ + DirectiveList( + byte[] directives) + { + m_curPos = 0; + m_state = STATE_LOOKING_FOR_FIRST_DIRECTIVE; + m_directiveList = new ArrayList(10); + m_scanStart = 0; + m_errorPos = -1; + try + { + m_directives = new String(directives, "UTF-8"); + } + catch(UnsupportedEncodingException e) + { + m_state = STATE_NO_UTF8_SUPPORT; + } + } + + /** + * This function takes a US-ASCII character string containing a list of comma + * separated directives, and parses the string into the individual directives + * and their values. A directive consists of a token specifying the directive + * name followed by an equal sign (=) and the directive value. The value is + * either a token or a quoted string + * + * @exception SaslException If an error Occurs + */ + void parseDirectives() throws SaslException + { + char prevChar; + char currChar; + int rc = 0; + boolean haveQuotedPair = false; + String currentName = "<no name>"; + + if (m_state == STATE_NO_UTF8_SUPPORT) + throw new SaslException("No UTF-8 support on platform"); + + prevChar = 0; + + while (m_curPos < m_directives.length()) + { + currChar = m_directives.charAt(m_curPos); + switch (m_state) + { + case STATE_LOOKING_FOR_FIRST_DIRECTIVE: + case STATE_LOOKING_FOR_DIRECTIVE: + if (isWhiteSpace(currChar)) + { + break; + } + else if (isValidTokenChar(currChar)) + { + m_scanStart = m_curPos; + m_state = STATE_SCANNING_NAME; + } + else + { + m_errorPos = m_curPos; + throw new SaslException("Parse error: Invalid name character"); + } + break; + + case STATE_SCANNING_NAME: + if (isValidTokenChar(currChar)) + { + break; + } + else if (isWhiteSpace(currChar)) + { + currentName = m_directives.substring(m_scanStart, m_curPos); + m_state = STATE_LOOKING_FOR_EQUALS; + } + else if ('=' == currChar) + { + currentName = m_directives.substring(m_scanStart, m_curPos); + m_state = STATE_LOOKING_FOR_VALUE; + } + else + { + m_errorPos = m_curPos; + throw new SaslException("Parse error: Invalid name character"); + } + break; + + case STATE_LOOKING_FOR_EQUALS: + if (isWhiteSpace(currChar)) + { + break; + } + else if ('=' == currChar) + { + m_state = STATE_LOOKING_FOR_VALUE; + } + else + { + m_errorPos = m_curPos; + throw new SaslException("Parse error: Expected equals sign '='."); + } + break; + + case STATE_LOOKING_FOR_VALUE: + if (isWhiteSpace(currChar)) + { + break; + } + else if ('"' == currChar) + { + m_scanStart = m_curPos+1; /* don't include the quote */ + m_state = STATE_SCANNING_QUOTED_STRING_VALUE; + } + else if (isValidTokenChar(currChar)) + { + m_scanStart = m_curPos; + m_state = STATE_SCANNING_TOKEN_VALUE; + } + else + { + m_errorPos = m_curPos; + throw new SaslException("Parse error: Unexpected character"); + } + break; + + case STATE_SCANNING_TOKEN_VALUE: + if (isValidTokenChar(currChar)) + { + break; + } + else if (isWhiteSpace(currChar)) + { + addDirective(currentName, false); + m_state = STATE_LOOKING_FOR_COMMA; + } + else if (',' == currChar) + { + addDirective(currentName, false); + m_state = STATE_LOOKING_FOR_DIRECTIVE; + } + else + { + m_errorPos = m_curPos; + throw new SaslException("Parse error: Invalid value character"); + } + break; + + case STATE_SCANNING_QUOTED_STRING_VALUE: + if ('\\' == currChar) + haveQuotedPair = true; + if ( ('"' == currChar) && + ('\\' != prevChar) ) + { + addDirective(currentName, haveQuotedPair); + haveQuotedPair = false; + m_state = STATE_LOOKING_FOR_COMMA; + } + break; + + case STATE_LOOKING_FOR_COMMA: + if (isWhiteSpace(currChar)) + break; + else if (currChar == ',') + m_state = STATE_LOOKING_FOR_DIRECTIVE; + else + { + m_errorPos = m_curPos; + throw new SaslException("Parse error: Expected a comma."); + } + break; + } + if (0 != rc) + break; + prevChar = currChar; + m_curPos++; + } /* end while loop */ + + + if (rc == 0) + { + /* check the ending state */ + switch (m_state) + { + case STATE_SCANNING_TOKEN_VALUE: + addDirective(currentName, false); + break; + + case STATE_LOOKING_FOR_FIRST_DIRECTIVE: + case STATE_LOOKING_FOR_COMMA: + break; + + case STATE_LOOKING_FOR_DIRECTIVE: + throw new SaslException("Parse error: Trailing comma."); + + case STATE_SCANNING_NAME: + case STATE_LOOKING_FOR_EQUALS: + case STATE_LOOKING_FOR_VALUE: + throw new SaslException("Parse error: Missing value."); + + case STATE_SCANNING_QUOTED_STRING_VALUE: + throw new SaslException("Parse error: Missing closing quote."); + } + } + + } + + /** + * This function returns TRUE if the character is a valid token character. + * + * token = 1*<any CHAR except CTLs or separators> + * + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + * + * CTL = <any US-ASCII control character + * (octets 0 - 31) and DEL (127)> + * + * CHAR = <any US-ASCII character (octets 0 - 127)> + * + * @param c character to be tested + * + * @return Returns TRUE if the character is a valid token character. + */ + boolean isValidTokenChar( + char c) + { + if ( ( (c >= '\u0000') && (c <='\u0020') ) || + ( (c >= '\u003a') && (c <= '\u0040') ) || + ( (c >= '\u005b') && (c <= '\u005d') ) || + ('\u002c' == c) || + ('\u0025' == c) || + ('\u0028' == c) || + ('\u0029' == c) || + ('\u007b' == c) || + ('\u007d' == c) || + ('\u007f' == c) ) + return false; + + return true; + } + + /** + * This function returns TRUE if the character is linear white space (LWS). + * LWS = [CRLF] 1*( SP | HT ) + * @param c Input charcter to be tested + * + * @return Returns TRUE if the character is linear white space (LWS) + */ + boolean isWhiteSpace( + char c) + { + if ( ('\t' == c) || // HORIZONTAL TABULATION. + ('\n' == c) || // LINE FEED. + ('\r' == c) || // CARRIAGE RETURN. + ('\u0020' == c) ) + return true; + + return false; + } + + /** + * This function creates a directive record and adds it to the list, the + * value will be added later after it is parsed. + * + * @param name Name + * @param haveQuotedPair true if quoted pair is there else false + */ + void addDirective( + String name, + boolean haveQuotedPair) + { + String value; + int inputIndex; + int valueIndex; + char valueChar; + int type; + + if (!haveQuotedPair) + { + value = m_directives.substring(m_scanStart, m_curPos); + } + else + { //copy one character at a time skipping backslash excapes. + StringBuffer valueBuf = new StringBuffer(m_curPos - m_scanStart); + valueIndex = 0; + inputIndex = m_scanStart; + while (inputIndex < m_curPos) + { + if ('\\' == (valueChar = m_directives.charAt(inputIndex))) + inputIndex++; + valueBuf.setCharAt(valueIndex, m_directives.charAt(inputIndex)); + valueIndex++; + inputIndex++; + } + value = new String(valueBuf); + } + + if (m_state == STATE_SCANNING_QUOTED_STRING_VALUE) + type = ParsedDirective.QUOTED_STRING_VALUE; + else + type = ParsedDirective.TOKEN_VALUE; + m_directiveList.add(new ParsedDirective(name, value, type)); + } + + + /** + * Returns the List iterator. + * + * @return Returns the Iterator Object for the List. + */ + Iterator getIterator() + { + return m_directiveList.iterator(); + } +} + diff --git a/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/ParsedDirective.java b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/ParsedDirective.java new file mode 100644 index 0000000..17bf70e --- /dev/null +++ b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/ParsedDirective.java @@ -0,0 +1,56 @@ +/* ************************************************************************** + * $OpenLDAP: /com/novell/sasl/client/ParsedDirective.java,v 1.1 2003/08/21 10:06:26 kkanil Exp $ + * + * Copyright (C) 2002 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ +package com.novell.sasl.client; + +/** + * Implements the ParsedDirective class which will be used in the + * DigestMD5SaslClient mechanism. + */ +class ParsedDirective +{ + public static final int QUOTED_STRING_VALUE = 1; + public static final int TOKEN_VALUE = 2; + + private int m_valueType; + private String m_name; + private String m_value; + + ParsedDirective( + String name, + String value, + int type) + { + m_name = name; + m_value = value; + m_valueType = type; + } + + String getValue() + { + return m_value; + } + + String getName() + { + return m_name; + } + + int getValueType() + { + return m_valueType; + } + +} + diff --git a/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/ResponseAuth.java b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/ResponseAuth.java new file mode 100644 index 0000000..0aef955 --- /dev/null +++ b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/ResponseAuth.java @@ -0,0 +1,83 @@ +/* ************************************************************************** + * $OpenLDAP: /com/novell/sasl/client/ResponseAuth.java,v 1.3 2005/01/17 15:00:54 sunilk Exp $ + * + * Copyright (C) 2002 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ +package com.novell.sasl.client; + +import java.util.*; +import org.apache.harmony.javax.security.sasl.*; + +/** + * Implements the ResponseAuth class used by the DigestMD5SaslClient mechanism + */ +class ResponseAuth +{ + + private String m_responseValue; + + ResponseAuth( + byte[] responseAuth) + throws SaslException + { + m_responseValue = null; + + DirectiveList dirList = new DirectiveList(responseAuth); + try + { + dirList.parseDirectives(); + checkSemantics(dirList); + } + catch (SaslException e) + { + } + } + + /** + * Checks the semantics of the directives in the directive list as parsed + * from the digest challenge byte array. + * + * @param dirList the list of directives parsed from the digest challenge + * + * @exception SaslException If a semantic error occurs + */ + void checkSemantics( + DirectiveList dirList) throws SaslException + { + Iterator directives = dirList.getIterator(); + ParsedDirective directive; + String name; + + while (directives.hasNext()) + { + directive = (ParsedDirective)directives.next(); + name = directive.getName(); + if (name.equals("rspauth")) + m_responseValue = directive.getValue(); + } + + /* post semantic check */ + if (m_responseValue == null) + throw new SaslException("Missing response-auth directive."); + } + + /** + * returns the ResponseValue + * + * @return the ResponseValue as a String. + */ + public String getResponseValue() + { + return m_responseValue; + } +} + diff --git a/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/TokenParser.java b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/TokenParser.java new file mode 100644 index 0000000..3d3491d --- /dev/null +++ b/asmack-master/static-src/novell-openldap-jldap/com/novell/sasl/client/TokenParser.java @@ -0,0 +1,208 @@ +/* ************************************************************************** + * $OpenLDAP: /com/novell/sasl/client/TokenParser.java,v 1.3 2005/01/17 15:00:54 sunilk Exp $ + * + * Copyright (C) 2002 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ +package com.novell.sasl.client; + +import org.apache.harmony.javax.security.sasl.*; +/** + * The TokenParser class will parse individual tokens from a list of tokens that + * are a directive value for a DigestMD5 authentication.The tokens are separated + * commas. + */ +class TokenParser extends Object +{ + private static final int STATE_LOOKING_FOR_FIRST_TOKEN = 1; + private static final int STATE_LOOKING_FOR_TOKEN = 2; + private static final int STATE_SCANNING_TOKEN = 3; + private static final int STATE_LOOKING_FOR_COMMA = 4; + private static final int STATE_PARSING_ERROR = 5; + private static final int STATE_DONE = 6; + + private int m_curPos; + private int m_scanStart; + private int m_state; + private String m_tokens; + + + TokenParser( + String tokens) + { + m_tokens = tokens; + m_curPos = 0; + m_scanStart = 0; + m_state = STATE_LOOKING_FOR_FIRST_TOKEN; + } + + /** + * This function parses the next token from the tokens string and returns + * it as a string. If there are no more tokens a null reference is returned. + * + * @return the parsed token or a null reference if there are no more + * tokens + * + * @exception SASLException if an error occurs while parsing + */ + String parseToken() throws SaslException + { + char currChar; + String token = null; + + + if (m_state == STATE_DONE) + return null; + + while (m_curPos < m_tokens.length() && (token == null)) + { + currChar = m_tokens.charAt(m_curPos); + switch (m_state) + { + case STATE_LOOKING_FOR_FIRST_TOKEN: + case STATE_LOOKING_FOR_TOKEN: + if (isWhiteSpace(currChar)) + { + break; + } + else if (isValidTokenChar(currChar)) + { + m_scanStart = m_curPos; + m_state = STATE_SCANNING_TOKEN; + } + else + { + m_state = STATE_PARSING_ERROR; + throw new SaslException("Invalid token character at position " + m_curPos); + } + break; + + case STATE_SCANNING_TOKEN: + if (isValidTokenChar(currChar)) + { + break; + } + else if (isWhiteSpace(currChar)) + { + token = m_tokens.substring(m_scanStart, m_curPos); + m_state = STATE_LOOKING_FOR_COMMA; + } + else if (',' == currChar) + { + token = m_tokens.substring(m_scanStart, m_curPos); + m_state = STATE_LOOKING_FOR_TOKEN; + } + else + { + m_state = STATE_PARSING_ERROR; + throw new SaslException("Invalid token character at position " + m_curPos); + } + break; + + + case STATE_LOOKING_FOR_COMMA: + if (isWhiteSpace(currChar)) + break; + else if (currChar == ',') + m_state = STATE_LOOKING_FOR_TOKEN; + else + { + m_state = STATE_PARSING_ERROR; + throw new SaslException("Expected a comma, found '" + + currChar + "' at postion " + + m_curPos); + } + break; + } + m_curPos++; + } /* end while loop */ + + if (token == null) + { /* check the ending state */ + switch (m_state) + { + case STATE_SCANNING_TOKEN: + token = m_tokens.substring(m_scanStart); + m_state = STATE_DONE; + break; + + case STATE_LOOKING_FOR_FIRST_TOKEN: + case STATE_LOOKING_FOR_COMMA: + break; + + case STATE_LOOKING_FOR_TOKEN: + throw new SaslException("Trialing comma"); + } + } + + return token; + } + + /** + * This function returns TRUE if the character is a valid token character. + * + * token = 1*<any CHAR except CTLs or separators> + * + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + * + * CTL = <any US-ASCII control character + * (octets 0 - 31) and DEL (127)> + * + * CHAR = <any US-ASCII character (octets 0 - 127)> + * + * @param c character to be validated + * + * @return True if character is valid Token character else it returns + * false + */ + boolean isValidTokenChar( + char c) + { + if ( ( (c >= '\u0000') && (c <='\u0020') ) || + ( (c >= '\u003a') && (c <= '\u0040') ) || + ( (c >= '\u005b') && (c <= '\u005d') ) || + ('\u002c' == c) || + ('\u0025' == c) || + ('\u0028' == c) || + ('\u0029' == c) || + ('\u007b' == c) || + ('\u007d' == c) || + ('\u007f' == c) ) + return false; + + return true; + } + + /** + * This function returns TRUE if the character is linear white space (LWS). + * LWS = [CRLF] 1*( SP | HT ) + * + * @param c character to be validated + * + * @return True if character is liner whitespace else it returns false + */ + boolean isWhiteSpace( + char c) + { + if ( ('\t' == c) || // HORIZONTAL TABULATION. + ('\n' == c) || // LINE FEED. + ('\r' == c) || // CARRIAGE RETURN. + ('\u0020' == c) ) + return true; + + return false; + } + +} + |