Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bill Burke 2016-09-07 23:11:38 -04:00
commit 3f35234cf5
154 changed files with 17348 additions and 315 deletions

View file

@ -154,7 +154,7 @@
return;
} else if (initOptions) {
if (initOptions.token || initOptions.refreshToken) {
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken, false);
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
kc.timeSkew = initOptions.timeSkew || 0;
if (loginIframe.enable) {
@ -406,10 +406,10 @@
timeLocal = (timeLocal + new Date().getTime()) / 2;
var tokenResponse = JSON.parse(req.responseText);
setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], true);
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
p.setSuccess(true);
@ -444,7 +444,7 @@
kc.clearToken = function() {
if (kc.token) {
setToken(null, null, null, true);
setToken(null, null, null);
kc.onAuthLogout && kc.onAuthLogout();
if (kc.loginRequired) {
kc.login();
@ -525,7 +525,7 @@
function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
timeLocal = (timeLocal + new Date().getTime()) / 2;
setToken(accessToken, refreshToken, idToken, true);
setToken(accessToken, refreshToken, idToken);
if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
(kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
@ -609,7 +609,7 @@
return promise.promise;
}
function setToken(token, refreshToken, idToken, useTokenTime) {
function setToken(token, refreshToken, idToken) {
if (kc.tokenTimeoutHandle) {
clearTimeout(kc.tokenTimeoutHandle);
kc.tokenTimeoutHandle = null;
@ -629,9 +629,12 @@
kc.resourceAccess = kc.tokenParsed.resource_access;
if (kc.onTokenExpired) {
var start = useTokenTime ? kc.tokenParsed.iat : (new Date().getTime() / 1000);
var expiresIn = kc.tokenParsed.exp - start;
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn * 1000);
var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
if (expiresIn <= 0) {
kc.onTokenExpired();
} else {
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
}
}
} else {

View file

@ -83,7 +83,6 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-kerberos-federation</artifactId>
</dependency>
<!-- saml -->
<dependency>
<groupId>org.keycloak</groupId>
@ -110,6 +109,12 @@
</exclusions>
</dependency>
<!-- Dependencies for RHEL IdM -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-sssd-federation</artifactId>
</dependency>
<!-- Built-in Authorization Policy Providers -->
<dependency>
<groupId>org.keycloak</groupId>

View file

@ -0,0 +1,31 @@
#!/bin/sh
# Setup for SSSD
SSSD_FILE="/etc/sssd/sssd.conf"
if [ -f "$SSSD_FILE" ];
then
sed -i '/ldap_tls_cacert/a ldap_user_extra_attrs = mail:mail, sn:sn, givenname:givenname, telephoneNumber:telephoneNumber' $SSSD_FILE
sed -i 's/nss, sudo, pam/nss, sudo, pam, ifp/' $SSSD_FILE
sed -i '/\[ifp\]/a allowed_uids = root\nuser_attributes = +mail, +telephoneNumber, +givenname, +sn' $SSSD_FILE
systemctl restart sssd
else
echo "Please make sure you have $SSSD_FILE into your system! Aborting."
exit 1
fi
# Setup for PAM
PAM_FILE="/etc/pam.d/keycloak"
if [ ! -f "$PAM_FILE" ];
then
cat <<EOF > $PAM_FILE
auth required pam_sss.so
account required pam_sss.so
EOF
else
echo "$PAM_FILE already exists. Skipping it..."
exit 0
fi

View file

@ -35,6 +35,7 @@
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
<module name="org.keycloak.keycloak-sssd-federation" services="import"/>
<module name="org.keycloak.keycloak-server-spi" services="import"/>
<module name="org.keycloak.keycloak-model-jpa" services="import"/>
<module name="org.keycloak.keycloak-model-mongo" services="import"/>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ 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.
-->
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-sssd-federation">
<properties>
<property name="jboss.api" value="private"/>
</properties>
<resources>
<artifact name="${org.keycloak:keycloak-sssd-federation}"/>
</resources>
<dependencies>
<module name="org.jboss.logging"/>
<module name="org.keycloak.keycloak-core" />
<module name="org.keycloak.keycloak-server-spi" />
</dependencies>
</module>

View file

@ -35,6 +35,7 @@
<modules>
<module>ldap</module>
<module>kerberos</module>
<module>sssd</module>
</modules>
</project>

56
federation/sssd/pom.xml Normal file
View file

@ -0,0 +1,56 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.2.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-sssd-federation</artifactId>
<name>Keycloak SSSD Federation</name>
<description/>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,49 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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 cx.ath.matthew;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
*/
public class LibraryLoader {
private static final Logger LOGGER = Logger.getLogger(LibraryLoader.class.getSimpleName());
private static final String[] PATHS = {"/usr/lib/", "/usr/lib64/", "/usr/local/lib/", "/opt/local/lib/"};
private static final String LIBRARY_NAME = "libunix_dbus_java";
private static final String VERSION = "0.0.8";
private static boolean loadSucceeded;
public static void load() {
for (String path : PATHS) {
try {
System.load(String.format("%s/%s.so.%s", path, LIBRARY_NAME, VERSION));
loadSucceeded = true;
break;
} catch (UnsatisfiedLinkError e) {
loadSucceeded = false;
}
}
if (!loadSucceeded) LOGGER.log(Level.WARNING, "libunix_dbus_java not found\n" +
"Please, make sure you have the package libunix-dbus-java installed.");
}
}

View file

@ -0,0 +1,671 @@
/* Copyright (C) 1991-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* This header is separate from features.h so that the compiler can
include it implicitly at the start of every compilation. It must
not itself include <features.h> or any other header that includes
<features.h> because the implicit include comes before any feature
test macros that may be defined in a source file before it first
explicitly includes a system header. GCC knows the name of this
header in order to preinclude it. */
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent are available, use them to determine
whether the overall intent is to support these features; otherwise,
presume an older compiler has intent to support these features and
define these macros by default. */
/* wchar_t uses Unicode 7.0.0. Version 7.0 of the Unicode Standard is
synchronized with ISO/IEC 10646:2012, plus Amendments 1 (published
on April, 2013) and 2 (not yet published as of February, 2015).
Additionally, it includes the accelerated publication of U+20BD
RUBLE SIGN. Therefore Unicode 7.0.0 is between 10646:2012 and
10646:2014, and so we use the date ISO/IEC 10646:2012 Amd.1 was
published. */
/* We do not support C11 <threads.h>. */
/*
* Java Debug Library
*
* Copyright (c) Matthew Johnson 2005
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.debug;
import cx.ath.matthew.utils.Hexdump;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
/**
* Add debugging to your program, has support for large projects with multiple
* classes and debug levels per class. Supports optional enabling of debug
* per-level per-class and debug targets of files, Streams or stderr.
* Also supports timing between debug outputs, printing of stack traces for Throwables
* and files/line numbers on each message.
* <p>
* Debug now automatically figures out which class it was called from, so all
* methods passing in the calling class are deprecated.
* </p>
* <p>
* The defaults are to print all messages to stderr with class and method name.
* </p>
* <p>
* Should be called like this:
* </p>
* <pre>
* if (Debug.debug) Debug.print(Debug.INFO, "Debug Message");
* </pre>
*/
public class Debug {
/**
* This interface can be used to provide custom printing filters
* for certain classes.
*/
public static interface FilterCommand {
/**
* Called to print debug messages with a custom filter.
*
* @param output The PrintStream to output to.
* @param level The debug level of this message.
* @param location The textual location of the message.
* @param extra Extra information such as timing details.
* @param message The debug message.
* @param lines Other lines of a multiple-line debug message.
*/
public void filter(PrintStream output, int level, String location, String extra, String message, String[] lines);
}
/**
* Highest priority messages
*/
public static final int CRIT = 1;
/**
* Error messages
*/
public static final int ERR = 2;
/**
* Warnings
*/
public static final int WARN = 3;
/**
* Information
*/
public static final int INFO = 4;
/**
* Debug messages
*/
public static final int DEBUG = 5;
/**
* Verbose debug messages
*/
public static final int VERBOSE = 6;
/**
* Set this to false to disable compilation of Debug statements
*/
public static final boolean debug = false;
/**
* The current output stream (defaults to System.err)
*/
public static PrintStream debugout = System.err;
private static Properties prop = null;
private static boolean timing = false;
private static boolean ttrace = false;
private static boolean lines = false;
private static boolean hexdump = false;
private static long last = 0;
private static int balen = 36;
private static int bawidth = 80;
private static Class saveclass = null;
//TODO: 1.5 private static Map<Class<? extends Object>, FilterCommand> filterMap = new HashMap<Class<? extends Object>, FilterCommand>();
private static Map filterMap = new HashMap();
/**
* Set properties to configure debugging.
* Format of properties is class =&gt; level, e.g.
* <pre>
* cx.ath.matthew.io.TeeOutputStream = INFO
* cx.ath.matthew.io.DOMPrinter = DEBUG
* </pre>
* The debug level can be one of CRIT, ERR, WARN, INFO, DEBUG or VERBOSE which
* correspond to all messages up to that level. The special words YES, ALL and TRUE
* cause all messages to be printed regardless of level. All other terms disable
* messages for that class. CRIT and ERR messages are always printed if debugging is enabled
* unless explicitly disabled.
* The special class name ALL can be used to set the default level for all classes.
*
* @param prop Properties object to use.
*/
public static void setProperties(Properties prop) {
Debug.prop = prop;
}
/**
* Read which class to debug on at which level from the given File.
* Syntax the same as Java Properties files:
* <pre>
* &lt;class&gt; = &lt;debuglevel&gt;
* </pre>
* E.G.
* <pre>
* cx.ath.matthew.io.TeeOutputStream = INFO
* cx.ath.matthew.io.DOMPrinter = DEBUG
* </pre>
* The debug level can be one of CRIT, ERR, WARN, INFO, DEBUG or VERBOSE which
* correspond to all messages up to that level. The special words YES, ALL and TRUE
* cause all messages to be printed regardless of level. All other terms disable
* messages for that class. CRIT and ERR messages are always printed if debugging is enabled
* unless explicitly disabled.
* The special class name ALL can be used to set the default level for all classes.
*
* @param f File to read from.
*/
public static void loadConfig(File f) throws IOException {
prop = new Properties();
prop.load(new FileInputStream(f));
}
/**
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static boolean debugging(Class c, int loglevel) {
if (debug) {
if (null == c) return true;
return debugging(c.getName(), loglevel);
}
return false;
}
public static boolean debugging(String s, int loglevel) {
if (debug) {
try {
if (null == s) return true;
if (null == prop) return loglevel <= DEBUG;
String d = prop.getProperty(s);
if (null == d || "".equals(d)) d = prop.getProperty("ALL");
if (null == d) return loglevel <= ERR;
if ("".equals(d)) return loglevel <= ERR;
d = d.toLowerCase();
if ("true".equals(d)) return true;
if ("yes".equals(d)) return true;
if ("all".equals(d)) return true;
if ("verbose".equals(d)) return loglevel <= VERBOSE;
if ("debug".equals(d)) return loglevel <= DEBUG;
if ("info".equals(d)) return loglevel <= INFO;
if ("warn".equals(d)) return loglevel <= WARN;
if ("err".equals(d)) return loglevel <= ERR;
if ("crit".equals(d)) return loglevel <= CRIT;
int i = Integer.parseInt(d);
return i >= loglevel;
} catch (Exception e) {
return false;
}
}
return false;
}
/**
* Output to the given Stream
*/
public static void setOutput(PrintStream p) throws IOException {
debugout = p;
}
/**
* Output to the given file
*/
public static void setOutput(String filename) throws IOException {
debugout = new PrintStream(new FileOutputStream(filename, true));
}
/**
* Output to the default debug.log
*/
public static void setOutput() throws IOException {
setOutput("./debug.log");
}
/**
* Log at DEBUG
*
* @param d The object to log
*/
public static void print(Object d) {
if (debug) {
if (d instanceof String)
print(DEBUG, (String) d);
else if (d instanceof Throwable)
print(DEBUG, (Throwable) d);
else if (d instanceof byte[])
print(DEBUG, (byte[]) d);
else if (d instanceof Map)
printMap(DEBUG, (Map) d);
else print(DEBUG, d);
}
}
/**
* Log at DEBUG
*
* @param o The object doing the logging
* @param d The object to log
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void print(Object o, Object d) {
if (debug) {
if (o instanceof Class)
saveclass = (Class) o;
else
saveclass = o.getClass();
print(d);
}
}
/**
* Log an Object
*
* @param o The object doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param d The object to log with d.toString()
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void print(Object o, int loglevel, Object d) {
if (debug) {
if (o instanceof Class)
saveclass = (Class) o;
else
saveclass = o.getClass();
print(loglevel, d);
}
}
/**
* Log a String
*
* @param o The object doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param s The log message
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void print(Object o, int loglevel, String s) {
if (debug) {
if (o instanceof Class)
saveclass = (Class) o;
else
saveclass = o.getClass();
print(loglevel, s);
}
}
/**
* Log a Throwable
*
* @param o The object doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param t The throwable to log with .toString and .printStackTrace
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void print(Object o, int loglevel, Throwable t) {
if (debug) {
if (o instanceof Class)
saveclass = (Class) o;
else
saveclass = o.getClass();
print(loglevel, t);
}
}
/**
* Log a Throwable
*
* @param c The class doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param t The throwable to log with .toString and .printStackTrace
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void print(Class c, int loglevel, Throwable t) {
if (debug) {
saveclass = c;
print(loglevel, t);
}
}
/**
* Log a Throwable
*
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param t The throwable to log with .toString and .printStackTrace
* @see #setThrowableTraces to turn on stack traces.
*/
public static void print(int loglevel, Throwable t) {
if (debug) {
String timestr = "";
String[] data = getTraceElements();
if (debugging(data[0], loglevel)) {
if (timing) {
long now = System.currentTimeMillis();
timestr = "{" + (now - last) + "} ";
last = now;
}
String[] lines = null;
if (ttrace) {
StackTraceElement[] ste = t.getStackTrace();
lines = new String[ste.length];
for (int i = 0; i < ste.length; i++)
lines[i] = "\tat " + ste[i].toString();
}
_print(t.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, t.toString(), lines);
}
}
}
/**
* Log a byte array
*
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param b The byte array to print.
* @see #setHexDump to enable hex dumping.
* @see #setByteArrayCount to change how many bytes are printed.
* @see #setByteArrayWidth to change the formatting width of hex.
*/
public static void print(int loglevel, byte[] b) {
if (debug) {
String timestr = "";
String[] data = getTraceElements();
if (debugging(data[0], loglevel)) {
if (timing) {
long now = System.currentTimeMillis();
timestr = "{" + (now - last) + "} ";
last = now;
}
String[] lines = null;
if (hexdump) {
if (balen >= b.length)
lines = Hexdump.format(b, bawidth).split("\n");
else {
byte[] buf = new byte[balen];
System.arraycopy(b, 0, buf, 0, balen);
lines = Hexdump.format(buf, bawidth).split("\n");
}
}
_print(b.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, b.length + " bytes", lines);
}
}
}
/**
* Log a String
*
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param s The string to log with d.toString()
*/
public static void print(int loglevel, String s) {
if (debug)
print(loglevel, (Object) s);
}
/**
* Log an Object
*
* @param c The class doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param d The object to log with d.toString()
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void print(Class c, int loglevel, Object d) {
if (debug) {
saveclass = c;
print(loglevel, d);
}
}
/**
* Log a String
*
* @param c The class doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param s The log message
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void print(Class c, int loglevel, String s) {
if (debug) {
saveclass = c;
print(loglevel, s);
}
}
private static String[] getTraceElements() {
String[] data = new String[]{"", "", ""};
try {
Method m = Thread.class.getMethod("getStackTrace", new Class[0]);
StackTraceElement[] stes = (StackTraceElement[]) m.invoke(Thread.currentThread(), new Object[0]);
for (StackTraceElement ste : stes) {
if (Debug.class.getName().equals(ste.getClassName())) continue;
if (Thread.class.getName().equals(ste.getClassName())) continue;
if (Method.class.getName().equals(ste.getClassName())) continue;
if (ste.getClassName().startsWith("sun.reflect")) continue;
data[0] = ste.getClassName();
data[1] = ste.getMethodName();
if (lines)
data[2] = " " + ste.getFileName() + ":" + ste.getLineNumber();
break;
}
} catch (NoSuchMethodException NSMe) {
if (null != saveclass)
data[0] = saveclass.getName();
} catch (IllegalAccessException IAe) {
} catch (InvocationTargetException ITe) {
}
return data;
}
/**
* Log an Object
*
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param o The object to log
*/
public static void print(int loglevel, Object o) {
if (debug) {
String timestr = "";
String[] data = getTraceElements();
if (debugging(data[0], loglevel)) {
if (timing) {
long now = System.currentTimeMillis();
timestr = "{" + (now - last) + "} ";
last = now;
}
_print(o.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, o.toString(), null);
}
}
}
/**
* Log a Map
*
* @param o The object doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param m The Map to print out
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void printMap(Object o, int loglevel, Map m) {
if (debug) {
if (o instanceof Class)
saveclass = (Class) o;
else
saveclass = o.getClass();
printMap(loglevel, m);
}
}
/**
* Log a Map
*
* @param c The class doing the logging
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param m The Map to print out
* @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
*/
//TODO: 1.5 @Deprecated()
public static void printMap(Class c, int loglevel, Map m) {
if (debug) {
saveclass = c;
printMap(loglevel, m);
}
}
/**
* Log a Map at DEBUG log level
*
* @param m The Map to print out
*/
public static void printMap(Map m) {
printMap(DEBUG, m);
}
/**
* Log a Map
*
* @param loglevel The level to log at (DEBUG, WARN, etc)
* @param m The Map to print out
*/
public static void printMap(int loglevel, Map m) {
if (debug) {
String timestr = "";
String[] data = getTraceElements();
if (debugging(data[0], loglevel)) {
if (timing) {
long now = System.currentTimeMillis();
timestr = "{" + (now - last) + "} ";
last = now;
}
Iterator i = m.keySet().iterator();
String[] lines = new String[m.size()];
int j = 0;
while (i.hasNext()) {
Object key = i.next();
lines[j++] = "\t\t- " + key + " => " + m.get(key);
}
_print(m.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, "Map:", lines);
}
}
}
/**
* Enable or disable stack traces in Debuging throwables.
*/
public static void setThrowableTraces(boolean ttrace) {
Debug.ttrace = ttrace;
}
/**
* Enable or disable timing in Debug messages.
*/
public static void setTiming(boolean timing) {
Debug.timing = timing;
}
/**
* Enable or disable line numbers.
*/
public static void setLineNos(boolean lines) {
Debug.lines = lines;
}
/**
* Enable or disable hexdumps.
*/
public static void setHexDump(boolean hexdump) {
Debug.hexdump = hexdump;
}
/**
* Set the size of hexdumps.
* (Default: 36)
*/
public static void setByteArrayCount(int count) {
Debug.balen = count;
}
/**
* Set the formatted width of hexdumps.
* (Default: 80 chars)
*/
public static void setByteArrayWidth(int width) {
Debug.bawidth = width;
}
/**
* Add a filter command for a specific type.
* This command will be called with the output stream
* and the text to be sent. It should perform any
* changes necessary to the text and then print the
* result to the output stream.
*/
public static void addFilterCommand(Class c, FilterCommand f)
//TODO 1.5: public static void addFilterCommand(Class<? extends Object> c, FilterCommand f)
{
filterMap.put(c, f);
}
private static void _print(Class c, int level, String loc, String extra, String message, String[] lines) {
//TODO 1.5: FilterCommand f = filterMap.get(c);
FilterCommand f = (FilterCommand) filterMap.get(c);
if (null == f) {
debugout.println("[" + loc + "] " + extra + message);
if (null != lines)
for (String s : lines)
debugout.println(s);
} else
f.filter(debugout, level, loc, extra, message, lines);
}
}

View file

@ -0,0 +1,35 @@
/*
* Java Unix Sockets Library
*
* Copyright (c) Matthew Johnson 2004
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.unix;
import java.net.SocketException;
public class NotConnectedException extends SocketException {
public NotConnectedException() {
super("The Socket is Not Connected");
}
}

View file

@ -0,0 +1,94 @@
/*
* Java Unix Sockets Library
*
* Copyright (c) Matthew Johnson 2004
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.unix;
import java.io.IOException;
import java.io.InputStream;
public class USInputStream extends InputStream {
public static final int MSG_DONTWAIT = 0x40;
private native int native_recv(int sock, byte[] b, int off, int len, int flags, int timeout) throws IOException;
private int sock;
boolean closed = false;
private byte[] onebuf = new byte[1];
private UnixSocket us;
private boolean blocking = true;
private int flags = 0;
private int timeout = 0;
public USInputStream(int sock, UnixSocket us) {
this.sock = sock;
this.us = us;
}
public void close() throws IOException {
closed = true;
us.close();
}
public boolean markSupported() {
return false;
}
public int read() throws IOException {
int rv = 0;
while (0 >= rv) rv = read(onebuf);
if (-1 == rv) return -1;
return 0 > onebuf[0] ? -onebuf[0] : onebuf[0];
}
public int read(byte[] b, int off, int len) throws IOException {
if (closed) throw new NotConnectedException();
int count = native_recv(sock, b, off, len, flags, timeout);
/* Yes, I really want to do this. Recv returns 0 for 'connection shut down'.
* read() returns -1 for 'end of stream.
* Recv returns -1 for 'EAGAIN' (all other errors cause an exception to be raised)
* whereas read() returns 0 for '0 bytes read', so yes, I really want to swap them here.
*/
if (0 == count) return -1;
else if (-1 == count) return 0;
else return count;
}
public boolean isClosed() {
return closed;
}
public UnixSocket getSocket() {
return us;
}
public void setBlocking(boolean enable) {
flags = enable ? 0 : MSG_DONTWAIT;
}
public void setSoTimeout(int timeout) {
this.timeout = timeout;
}
}

View file

@ -0,0 +1,78 @@
/*
* Java Unix Sockets Library
*
* Copyright (c) Matthew Johnson 2004
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.unix;
import java.io.IOException;
import java.io.OutputStream;
public class USOutputStream extends OutputStream {
private native int native_send(int sock, byte[] b, int off, int len) throws IOException;
private native int native_send(int sock, byte[][] b) throws IOException;
private int sock;
boolean closed = false;
private byte[] onebuf = new byte[1];
private UnixSocket us;
public USOutputStream(int sock, UnixSocket us) {
this.sock = sock;
this.us = us;
}
public void close() throws IOException {
closed = true;
us.close();
}
public void flush() {
} // no-op, we do not buffer
public void write(byte[][] b) throws IOException {
if (closed) throw new NotConnectedException();
native_send(sock, b);
}
public void write(byte[] b, int off, int len) throws IOException {
if (closed) throw new NotConnectedException();
native_send(sock, b, off, len);
}
public void write(int b) throws IOException {
onebuf[0] = (byte) (b % 0x7F);
if (1 == (b % 0x80)) onebuf[0] = (byte) -onebuf[0];
write(onebuf);
}
public boolean isClosed() {
return closed;
}
public UnixSocket getSocket() {
return us;
}
}

View file

@ -0,0 +1,43 @@
/*
* Java Unix Sockets Library
*
* Copyright (c) Matthew Johnson 2004
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.unix;
import java.io.IOException;
/**
* An IO Exception which occurred during UNIX Socket IO
*/
public class UnixIOException extends IOException {
private int no;
private String message;
public UnixIOException(int no, String message) {
super(message);
this.message = message;
this.no = no;
}
}

View file

@ -0,0 +1,350 @@
/*
* Java Unix Sockets Library
*
* Copyright (c) Matthew Johnson 2004
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.unix;
import cx.ath.matthew.LibraryLoader;
import cx.ath.matthew.debug.Debug;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Represents a UnixSocket.
*/
public class UnixSocket {
static {
LibraryLoader.load();
}
private native void native_set_pass_cred(int sock, boolean passcred) throws IOException;
private native int native_connect(String address, boolean abs) throws IOException;
private native void native_close(int sock) throws IOException;
private native int native_getPID(int sock);
private native int native_getUID(int sock);
private native int native_getGID(int sock);
private native void native_send_creds(int sock, byte data) throws IOException;
private native byte native_recv_creds(int sock, int[] creds) throws IOException;
private UnixSocketAddress address = null;
private USOutputStream os = null;
private USInputStream is = null;
private boolean closed = false;
private boolean connected = false;
private boolean passcred = false;
private int sock = 0;
private boolean blocking = true;
private int uid = -1;
private int pid = -1;
private int gid = -1;
UnixSocket(int sock, UnixSocketAddress address) {
this.sock = sock;
this.address = address;
this.connected = true;
this.os = new USOutputStream(sock, this);
this.is = new USInputStream(sock, this);
}
/**
* Create an unconnected socket.
*/
public UnixSocket() {
}
/**
* Create a socket connected to the given address.
*
* @param address The Unix Socket address to connect to
*/
public UnixSocket(UnixSocketAddress address) throws IOException {
connect(address);
}
/**
* Create a socket connected to the given address.
*
* @param address The Unix Socket address to connect to
*/
public UnixSocket(String address) throws IOException {
this(new UnixSocketAddress(address));
}
/**
* Connect the socket to this address.
*
* @param address The Unix Socket address to connect to
*/
public void connect(UnixSocketAddress address) throws IOException {
if (connected) close();
this.sock = native_connect(address.path, address.abs);
this.os = new USOutputStream(this.sock, this);
this.is = new USInputStream(this.sock, this);
this.address = address;
this.connected = true;
this.closed = false;
this.is.setBlocking(blocking);
}
/**
* Connect the socket to this address.
*
* @param address The Unix Socket address to connect to
*/
public void connect(String address) throws IOException {
connect(new UnixSocketAddress(address));
}
public void finalize() {
try {
close();
} catch (IOException IOe) {
}
}
/**
* Closes the connection.
*/
public synchronized void close() throws IOException {
if (Debug.debug) Debug.print(Debug.INFO, "Closing socket");
native_close(sock);
sock = 0;
this.closed = true;
this.connected = false;
os = null;
is = null;
}
/**
* Returns an InputStream for reading from the socket.
*
* @return An InputStream connected to this socket.
*/
public InputStream getInputStream() {
return is;
}
/**
* Returns an OutputStream for writing to the socket.
*
* @return An OutputStream connected to this socket.
*/
public OutputStream getOutputStream() {
return os;
}
/**
* Returns the address this socket is connected to.
* Returns null if the socket is unconnected.
*
* @return The UnixSocketAddress the socket is connected to
*/
public UnixSocketAddress getAddress() {
return address;
}
/**
* Send a single byte of data with credentials.
* (Works on BSDs)
*
* @param data The byte of data to send.
*/
public void sendCredentialByte(byte data) throws IOException {
if (!connected) throw new NotConnectedException();
native_send_creds(sock, data);
}
/**
* Receive a single byte of data, with credentials.
* (Works on BSDs)
*
* @param data The byte of data to send.
* @see getPeerUID
* @see getPeerPID
* @see getPeerGID
*/
public byte recvCredentialByte() throws IOException {
if (!connected) throw new NotConnectedException();
int[] creds = new int[]{-1, -1, -1};
byte data = native_recv_creds(sock, creds);
pid = creds[0];
uid = creds[1];
gid = creds[2];
return data;
}
/**
* Get the credential passing status.
* (only effective on linux)
*
* @return The current status of credential passing.
* @see setPassCred
*/
public boolean getPassCred() {
return passcred;
}
/**
* Return the uid of the remote process.
* Some data must have been received on the socket to do this.
* Either setPassCred must be called on Linux first, or recvCredentialByte
* on BSD.
*
* @return the UID or -1 if it is not available
*/
public int getPeerUID() {
if (-1 == uid)
uid = native_getUID(sock);
return uid;
}
/**
* Return the gid of the remote process.
* Some data must have been received on the socket to do this.
* Either setPassCred must be called on Linux first, or recvCredentialByte
* on BSD.
*
* @return the GID or -1 if it is not available
*/
public int getPeerGID() {
if (-1 == gid)
gid = native_getGID(sock);
return gid;
}
/**
* Return the pid of the remote process.
* Some data must have been received on the socket to do this.
* Either setPassCred must be called on Linux first, or recvCredentialByte
* on BSD.
*
* @return the PID or -1 if it is not available
*/
public int getPeerPID() {
if (-1 == pid)
pid = native_getPID(sock);
return pid;
}
/**
* Set the credential passing status.
* (Only does anything on linux, for other OS, you need
* to use send/recv credentials)
*
* @param enable Set to true for credentials to be passed.
*/
public void setPassCred(boolean enable) throws IOException {
native_set_pass_cred(sock, enable);
passcred = enable;
}
/**
* Get the blocking mode.
*
* @return true if reads are blocking.
* @see setBlocking
*/
public boolean getBlocking() {
return blocking;
}
/**
* Set the blocking mode.
*
* @param enable Set to false for non-blocking reads.
*/
public void setBlocking(boolean enable) {
blocking = enable;
if (null != is) is.setBlocking(enable);
}
/**
* Check the socket status.
*
* @return true if closed.
*/
public boolean isClosed() {
return closed;
}
/**
* Check the socket status.
*
* @return true if connected.
*/
public boolean isConnected() {
return connected;
}
/**
* Check the socket status.
*
* @return true if the input stream has been shutdown
*/
public boolean isInputShutdown() {
return is.isClosed();
}
/**
* Check the socket status.
*
* @return true if the output stream has been shutdown
*/
public boolean isOutputShutdown() {
return os.isClosed();
}
/**
* Shuts down the input stream.
* Subsequent reads on the associated InputStream will fail.
*/
public void shutdownInput() {
is.closed = true;
}
/**
* Shuts down the output stream.
* Subsequent writes to the associated OutputStream will fail.
*/
public void shutdownOutput() {
os.closed = true;
}
/**
* Set timeout of read requests.
*/
public void setSoTimeout(int timeout) {
is.setSoTimeout(timeout);
}
}

View file

@ -0,0 +1,86 @@
/*
* Java Unix Sockets Library
*
* Copyright (c) Matthew Johnson 2004
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.unix;
/**
* Represents an address for a Unix Socket
*/
public class UnixSocketAddress {
String path;
boolean abs;
/**
* Create the address.
*
* @param path The path to the Unix Socket.
* @param abs True if this should be an abstract socket.
*/
public UnixSocketAddress(String path, boolean abs) {
this.path = path;
this.abs = abs;
}
/**
* Create the address.
*
* @param path The path to the Unix Socket.
*/
public UnixSocketAddress(String path) {
this.path = path;
this.abs = false;
}
/**
* Return the path.
*/
public String getPath() {
return path;
}
/**
* Returns true if this an address for an abstract socket.
*/
public boolean isAbstract() {
return abs;
}
/**
* Return the Address as a String.
*/
public String toString() {
return "unix" + (abs ? ":abstract" : "") + ":path=" + path;
}
public boolean equals(Object o) {
if (!(o instanceof UnixSocketAddress)) return false;
return ((UnixSocketAddress) o).path.equals(this.path);
}
public int hashCode() {
return path.hashCode();
}
}

View file

@ -0,0 +1,147 @@
/*
* Java Hexdump Library
*
* Copyright (c) Matthew Johnson 2005
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* To Contact the author, please email src@matthew.ath.cx
*
*/
package cx.ath.matthew.utils;
import java.io.PrintStream;
public class Hexdump {
public static final char[] hexchars = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public static String toHex(byte[] buf) {
return toHex(buf, 0, buf.length);
}
public static String toHex(byte[] buf, int ofs, int len) {
StringBuffer sb = new StringBuffer();
int j = ofs + len;
for (int i = ofs; i < j; i++) {
if (i < buf.length) {
sb.append(hexchars[(buf[i] & 0xF0) >> 4]);
sb.append(hexchars[buf[i] & 0x0F]);
sb.append(' ');
} else {
sb.append(' ');
sb.append(' ');
sb.append(' ');
}
}
return sb.toString();
}
public static String toAscii(byte[] buf) {
return toAscii(buf, 0, buf.length);
}
public static String toAscii(byte[] buf, int ofs, int len) {
StringBuffer sb = new StringBuffer();
int j = ofs + len;
for (int i = ofs; i < j; i++) {
if (i < buf.length) {
if (20 <= buf[i] && 126 >= buf[i])
sb.append((char) buf[i]);
else
sb.append('.');
} else
sb.append(' ');
}
return sb.toString();
}
public static String format(byte[] buf) {
return format(buf, 80);
}
public static String format(byte[] buf, int width) {
int bs = (width - 8) / 4;
int i = 0;
StringBuffer sb = new StringBuffer();
do {
for (int j = 0; j < 6; j++) {
sb.append(hexchars[(i << (j * 4) & 0xF00000) >> 20]);
}
sb.append('\t');
sb.append(toHex(buf, i, bs));
sb.append(' ');
sb.append(toAscii(buf, i, bs));
sb.append('\n');
i += bs;
} while (i < buf.length);
return sb.toString();
}
public static void print(byte[] buf) {
print(buf, System.err);
}
public static void print(byte[] buf, int width) {
print(buf, width, System.err);
}
public static void print(byte[] buf, int width, PrintStream out) {
out.print(format(buf, width));
}
public static void print(byte[] buf, PrintStream out) {
out.print(format(buf));
}
/**
* Returns a string which can be written to a Java source file as part
* of a static initializer for a byte array.
* Returns data in the format 0xAB, 0xCD, ....
* use like:
* javafile.print("byte[] data = {")
* javafile.print(Hexdump.toByteArray(data));
* javafile.println("};");
*/
public static String toByteArray(byte[] buf) {
return toByteArray(buf, 0, buf.length);
}
/**
* Returns a string which can be written to a Java source file as part
* of a static initializer for a byte array.
* Returns data in the format 0xAB, 0xCD, ....
* use like:
* javafile.print("byte[] data = {")
* javafile.print(Hexdump.toByteArray(data));
* javafile.println("};");
*/
public static String toByteArray(byte[] buf, int ofs, int len) {
StringBuffer sb = new StringBuffer();
for (int i = ofs; i < len && i < buf.length; i++) {
sb.append('0');
sb.append('x');
sb.append(hexchars[(buf[i] & 0xF0) >> 4]);
sb.append(hexchars[buf[i] & 0x0F]);
if ((i + 1) < len && (i + 1) < buf.length)
sb.append(',');
}
return sb.toString();
}
}

View file

@ -0,0 +1,530 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop;
import org.freedesktop.dbus.DBusInterface;
import org.freedesktop.dbus.DBusSignal;
import org.freedesktop.dbus.Position;
import org.freedesktop.dbus.Struct;
import org.freedesktop.dbus.Tuple;
import org.freedesktop.dbus.UInt16;
import org.freedesktop.dbus.UInt32;
import org.freedesktop.dbus.UInt64;
import org.freedesktop.dbus.Variant;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Map;
public interface DBus extends DBusInterface {
public static final int DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x01;
public static final int DBUS_NAME_FLAG_REPLACE_EXISTING = 0x02;
public static final int DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x04;
public static final int DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1;
public static final int DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2;
public static final int DBUS_REQUEST_NAME_REPLY_EXISTS = 3;
public static final int DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4;
public static final int DBUS_RELEASE_NAME_REPLY_RELEASED = 1;
public static final int DBUS_RELEASE_NAME_REPLY_NON_EXISTANT = 2;
public static final int DBUS_RELEASE_NAME_REPLY_NOT_OWNER = 3;
public static final int DBUS_START_REPLY_SUCCESS = 1;
public static final int DBUS_START_REPLY_ALREADY_RUNNING = 2;
/**
* All DBus Applications should respond to the Ping method on this interface
*/
public interface Peer extends DBusInterface {
public void Ping();
}
/**
* Objects can provide introspection data via this interface and method.
* See the <a href="http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format">Introspection Format</a>.
*/
public interface Introspectable extends DBusInterface {
/**
* @return The XML introspection data for this object
*/
public String Introspect();
}
/**
* A standard properties interface.
*/
public interface Properties extends DBusInterface {
/**
* Get the value for the given property.
*
* @param interface_name The interface this property is associated with.
* @param property_name The name of the property.
* @return The value of the property (may be any valid DBus type).
*/
public <A> A Get(String interface_name, String property_name);
/**
* Set the value for the given property.
*
* @param interface_name The interface this property is associated with.
* @param property_name The name of the property.
* @param value The new value of the property (may be any valid DBus type).
*/
public <A> void Set(String interface_name, String property_name, A value);
/**
* Get all properties and values.
*
* @param interface_name The interface the properties is associated with.
* @return The properties mapped to their values.
*/
public Map<String, Variant> GetAll(String interface_name);
}
/**
* Messages generated locally in the application.
*/
public interface Local extends DBusInterface {
public class Disconnected extends DBusSignal {
public Disconnected(String path) throws DBusException {
super(path);
}
}
}
/**
* Initial message to register ourselves on the Bus.
*
* @return The unique name of this connection to the Bus.
*/
public String Hello();
/**
* Lists all connected names on the Bus.
*
* @return An array of all connected names.
*/
public String[] ListNames();
/**
* Determine if a name has an owner.
*
* @param name The name to query.
* @return true if the name has an owner.
*/
public boolean NameHasOwner(String name);
/**
* Get the connection unique name that owns the given name.
*
* @param name The name to query.
* @return The connection which owns the name.
*/
public String GetNameOwner(String name);
/**
* Get the Unix UID that owns a connection name.
*
* @param connection_name The connection name.
* @return The Unix UID that owns it.
*/
public UInt32 GetConnectionUnixUser(String connection_name);
/**
* Start a service. If the given service is not provided
* by any application, it will be started according to the .service file
* for that service.
*
* @param name The service name to start.
* @param flags Unused.
* @return DBUS_START_REPLY constants.
*/
public UInt32 StartServiceByName(String name, UInt32 flags);
/**
* Request a name on the bus.
*
* @param name The name to request.
* @param flags DBUS_NAME flags.
* @return DBUS_REQUEST_NAME_REPLY constants.
*/
public UInt32 RequestName(String name, UInt32 flags);
/**
* Release a name on the bus.
*
* @param name The name to release.
* @return DBUS_RELEASE_NAME_REPLY constants.
*/
public UInt32 ReleaseName(String name);
/**
* Add a match rule.
* Will cause you to receive messages that aren't directed to you which
* match this rule.
*
* @param matchrule The Match rule as a string. Format Undocumented.
*/
public void AddMatch(String matchrule) throws Error.MatchRuleInvalid;
/**
* Remove a match rule.
* Will cause you to stop receiving messages that aren't directed to you which
* match this rule.
*
* @param matchrule The Match rule as a string. Format Undocumented.
*/
public void RemoveMatch(String matchrule) throws Error.MatchRuleInvalid;
/**
* List the connections currently queued for a name.
*
* @param name The name to query
* @return A list of unique connection IDs.
*/
public String[] ListQueuedOwners(String name);
/**
* Returns the proccess ID associated with a connection.
*
* @param connection_name The name of the connection
* @return The PID of the connection.
*/
public UInt32 GetConnectionUnixProcessID(String connection_name);
/**
* Does something undocumented.
*/
public Byte[] GetConnectionSELinuxSecurityContext(String a);
/**
* Does something undocumented.
*/
public void ReloadConfig();
/**
* Signal sent when the owner of a name changes
*/
public class NameOwnerChanged extends DBusSignal {
public final String name;
public final String old_owner;
public final String new_owner;
public NameOwnerChanged(String path, String name, String old_owner, String new_owner) throws DBusException {
super(path, new Object[]{name, old_owner, new_owner});
this.name = name;
this.old_owner = old_owner;
this.new_owner = new_owner;
}
}
/**
* Signal sent to a connection when it loses a name
*/
public class NameLost extends DBusSignal {
public final String name;
public NameLost(String path, String name) throws DBusException {
super(path, name);
this.name = name;
}
}
/**
* Signal sent to a connection when it aquires a name
*/
public class NameAcquired extends DBusSignal {
public final String name;
public NameAcquired(String path, String name) throws DBusException {
super(path, name);
this.name = name;
}
}
/**
* Contains standard errors that can be thrown from methods.
*/
public interface Error {
/**
* Thrown if the method called was unknown on the remote object
*/
@SuppressWarnings("serial")
public class UnknownMethod extends DBusExecutionException {
public UnknownMethod(String message) {
super(message);
}
}
/**
* Thrown if the object was unknown on a remote connection
*/
@SuppressWarnings("serial")
public class UnknownObject extends DBusExecutionException {
public UnknownObject(String message) {
super(message);
}
}
/**
* Thrown if the requested service was not available
*/
@SuppressWarnings("serial")
public class ServiceUnknown extends DBusExecutionException {
public ServiceUnknown(String message) {
super(message);
}
}
/**
* Thrown if the match rule is invalid
*/
@SuppressWarnings("serial")
public class MatchRuleInvalid extends DBusExecutionException {
public MatchRuleInvalid(String message) {
super(message);
}
}
/**
* Thrown if there is no reply to a method call
*/
@SuppressWarnings("serial")
public class NoReply extends DBusExecutionException {
public NoReply(String message) {
super(message);
}
}
/**
* Thrown if a message is denied due to a security policy
*/
@SuppressWarnings("serial")
public class AccessDenied extends DBusExecutionException {
public AccessDenied(String message) {
super(message);
}
}
}
/**
* Description of the interface or method, returned in the introspection data
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Description {
String value();
}
/**
* Indicates that a DBus interface or method is deprecated
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}
/**
* Contains method-specific annotations
*/
public interface Method {
/**
* Methods annotated with this do not send a reply
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoReply {
}
/**
* Give an error that the method can return
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Error {
String value();
}
}
/**
* Contains GLib-specific annotations
*/
public interface GLib {
/**
* Define a C symbol to map to this method. Used by GLib only
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CSymbol {
String value();
}
}
/**
* Contains Binding-test interfaces
*/
public interface Binding {
public interface SingleTests extends DBusInterface {
@Description("Returns the sum of the values in the input list")
public UInt32 Sum(byte[] a);
}
public interface TestClient extends DBusInterface {
@Description("when the trigger signal is received, this method should be called on the sending process/object.")
public void Response(UInt16 a, double b);
@Description("Causes a callback")
public static class Trigger extends DBusSignal {
public final UInt16 a;
public final double b;
public Trigger(String path, UInt16 a, double b) throws DBusException {
super(path, a, b);
this.a = a;
this.b = b;
}
}
}
public interface Tests extends DBusInterface {
@Description("Returns whatever it is passed")
public <T> Variant<T> Identity(Variant<T> input);
@Description("Returns whatever it is passed")
public byte IdentityByte(byte input);
@Description("Returns whatever it is passed")
public boolean IdentityBool(boolean input);
@Description("Returns whatever it is passed")
public short IdentityInt16(short input);
@Description("Returns whatever it is passed")
public UInt16 IdentityUInt16(UInt16 input);
@Description("Returns whatever it is passed")
public int IdentityInt32(int input);
@Description("Returns whatever it is passed")
public UInt32 IdentityUInt32(UInt32 input);
@Description("Returns whatever it is passed")
public long IdentityInt64(long input);
@Description("Returns whatever it is passed")
public UInt64 IdentityUInt64(UInt64 input);
@Description("Returns whatever it is passed")
public double IdentityDouble(double input);
@Description("Returns whatever it is passed")
public String IdentityString(String input);
@Description("Returns whatever it is passed")
public <T> Variant<T>[] IdentityArray(Variant<T>[] input);
@Description("Returns whatever it is passed")
public byte[] IdentityByteArray(byte[] input);
@Description("Returns whatever it is passed")
public boolean[] IdentityBoolArray(boolean[] input);
@Description("Returns whatever it is passed")
public short[] IdentityInt16Array(short[] input);
@Description("Returns whatever it is passed")
public UInt16[] IdentityUInt16Array(UInt16[] input);
@Description("Returns whatever it is passed")
public int[] IdentityInt32Array(int[] input);
@Description("Returns whatever it is passed")
public UInt32[] IdentityUInt32Array(UInt32[] input);
@Description("Returns whatever it is passed")
public long[] IdentityInt64Array(long[] input);
@Description("Returns whatever it is passed")
public UInt64[] IdentityUInt64Array(UInt64[] input);
@Description("Returns whatever it is passed")
public double[] IdentityDoubleArray(double[] input);
@Description("Returns whatever it is passed")
public String[] IdentityStringArray(String[] input);
@Description("Returns the sum of the values in the input list")
public long Sum(int[] a);
@Description("Given a map of A => B, should return a map of B => a list of all the As which mapped to B")
public Map<String, List<String>> InvertMapping(Map<String, String> a);
@Description("This method returns the contents of a struct as separate values")
public Triplet<String, UInt32, Short> DeStruct(TestStruct a);
@Description("Given any compound type as a variant, return all the primitive types recursively contained within as an array of variants")
public List<Variant<Object>> Primitize(Variant<Object> a);
@Description("inverts it's input")
public boolean Invert(boolean a);
@Description("triggers sending of a signal from the supplied object with the given parameter")
public void Trigger(String a, UInt64 b);
@Description("Causes the server to exit")
public void Exit();
}
public interface TestSignals extends DBusInterface {
@Description("Sent in response to a method call")
public static class Triggered extends DBusSignal {
public final UInt64 a;
public Triggered(String path, UInt64 a) throws DBusException {
super(path, a);
this.a = a;
}
}
}
public final class Triplet<A, B, C> extends Tuple {
@Position(0)
public final A a;
@Position(1)
public final B b;
@Position(2)
public final C c;
public Triplet(A a, B b, C c) {
this.a = a;
this.b = b;
this.c = c;
}
}
public final class TestStruct extends Struct {
@Position(0)
public final String a;
@Position(1)
public final UInt32 b;
@Position(2)
public final Short c;
public TestStruct(String a, UInt32 b, Short c) {
this.a = a;
this.b = b;
this.c = c;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,173 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import java.lang.reflect.Array;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import static org.freedesktop.dbus.Gettext.getString;
class ArrayFrob {
static Hashtable<Class<? extends Object>, Class<? extends Object>> primitiveToWrapper = new Hashtable<Class<? extends Object>, Class<? extends Object>>();
static Hashtable<Class<? extends Object>, Class<? extends Object>> wrapperToPrimitive = new Hashtable<Class<? extends Object>, Class<? extends Object>>();
static {
primitiveToWrapper.put(Boolean.TYPE, Boolean.class);
primitiveToWrapper.put(Byte.TYPE, Byte.class);
primitiveToWrapper.put(Short.TYPE, Short.class);
primitiveToWrapper.put(Character.TYPE, Character.class);
primitiveToWrapper.put(Integer.TYPE, Integer.class);
primitiveToWrapper.put(Long.TYPE, Long.class);
primitiveToWrapper.put(Float.TYPE, Float.class);
primitiveToWrapper.put(Double.TYPE, Double.class);
wrapperToPrimitive.put(Boolean.class, Boolean.TYPE);
wrapperToPrimitive.put(Byte.class, Byte.TYPE);
wrapperToPrimitive.put(Short.class, Short.TYPE);
wrapperToPrimitive.put(Character.class, Character.TYPE);
wrapperToPrimitive.put(Integer.class, Integer.TYPE);
wrapperToPrimitive.put(Long.class, Long.TYPE);
wrapperToPrimitive.put(Float.class, Float.TYPE);
wrapperToPrimitive.put(Double.class, Double.TYPE);
}
@SuppressWarnings("unchecked")
public static <T> T[] wrap(Object o) throws IllegalArgumentException {
Class<? extends Object> ac = o.getClass();
if (!ac.isArray()) throw new IllegalArgumentException(getString("invalidArray"));
Class<? extends Object> cc = ac.getComponentType();
Class<? extends Object> ncc = primitiveToWrapper.get(cc);
if (null == ncc) throw new IllegalArgumentException(getString("notPrimitiveType"));
T[] ns = (T[]) Array.newInstance(ncc, Array.getLength(o));
for (int i = 0; i < ns.length; i++)
ns[i] = (T) Array.get(o, i);
return ns;
}
@SuppressWarnings("unchecked")
public static <T> Object unwrap(T[] ns) throws IllegalArgumentException {
Class<? extends T[]> ac = (Class<? extends T[]>) ns.getClass();
Class<T> cc = (Class<T>) ac.getComponentType();
Class<? extends Object> ncc = wrapperToPrimitive.get(cc);
if (null == ncc) throw new IllegalArgumentException(getString("invalidWrapperType"));
Object o = Array.newInstance(ncc, ns.length);
for (int i = 0; i < ns.length; i++)
Array.set(o, i, ns[i]);
return o;
}
public static <T> List<T> listify(T[] ns) throws IllegalArgumentException {
return Arrays.asList(ns);
}
@SuppressWarnings("unchecked")
public static <T> List<T> listify(Object o) throws IllegalArgumentException {
if (o instanceof Object[]) return listify((T[]) o);
if (!o.getClass().isArray()) throw new IllegalArgumentException(getString("invalidArray"));
List<T> l = new ArrayList<T>(Array.getLength(o));
for (int i = 0; i < Array.getLength(o); i++)
l.add((T) Array.get(o, i));
return l;
}
@SuppressWarnings("unchecked")
public static <T> T[] delist(List<T> l, Class<T> c) throws IllegalArgumentException {
return l.toArray((T[]) Array.newInstance(c, 0));
}
public static <T> Object delistprimitive(List<T> l, Class<T> c) throws IllegalArgumentException {
Object o = Array.newInstance(c, l.size());
for (int i = 0; i < l.size(); i++)
Array.set(o, i, l.get(i));
return o;
}
@SuppressWarnings("unchecked")
public static Object convert(Object o, Class<? extends Object> c) throws IllegalArgumentException {
/* Possible Conversions:
*
** List<Integer> -> List<Integer>
** List<Integer> -> int[]
** List<Integer> -> Integer[]
** int[] -> int[]
** int[] -> List<Integer>
** int[] -> Integer[]
** Integer[] -> Integer[]
** Integer[] -> int[]
** Integer[] -> List<Integer>
*/
try {
// List<Integer> -> List<Integer>
if (List.class.equals(c)
&& o instanceof List)
return o;
// int[] -> List<Integer>
// Integer[] -> List<Integer>
if (List.class.equals(c)
&& o.getClass().isArray())
return listify(o);
// int[] -> int[]
// Integer[] -> Integer[]
if (o.getClass().isArray()
&& c.isArray()
&& o.getClass().getComponentType().equals(c.getComponentType()))
return o;
// int[] -> Integer[]
if (o.getClass().isArray()
&& c.isArray()
&& o.getClass().getComponentType().isPrimitive())
return wrap(o);
// Integer[] -> int[]
if (o.getClass().isArray()
&& c.isArray()
&& c.getComponentType().isPrimitive())
return unwrap((Object[]) o);
// List<Integer> -> int[]
if (o instanceof List
&& c.isArray()
&& c.getComponentType().isPrimitive())
return delistprimitive((List<Object>) o, (Class<Object>) c.getComponentType());
// List<Integer> -> Integer[]
if (o instanceof List
&& c.isArray())
return delist((List<Object>) o, (Class<Object>) c.getComponentType());
if (o.getClass().isArray()
&& c.isArray())
return type((Object[]) o, (Class<Object>) c.getComponentType());
} catch (Exception e) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new IllegalArgumentException(e);
}
throw new IllegalArgumentException(MessageFormat.format(getString("convertionTypeNotExpected"), new Object[]{o.getClass(), c}));
}
public static Object[] type(Object[] old, Class<Object> c) {
Object[] ns = (Object[]) Array.newInstance(c, old.length);
for (int i = 0; i < ns.length; i++)
ns[i] = old[i];
return ns;
}
}

View file

@ -0,0 +1,52 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import static org.freedesktop.dbus.Gettext.getString;
public class BusAddress {
private String type;
private Map<String, String> parameters;
public BusAddress(String address) throws ParseException {
if (null == address || "".equals(address)) throw new ParseException(getString("busAddressBlank"), 0);
if (Debug.debug) Debug.print(Debug.VERBOSE, "Parsing bus address: " + address);
String[] ss = address.split(":", 2);
if (ss.length < 2) throw new ParseException(getString("busAddressInvalid") + address, 0);
type = ss[0];
if (Debug.debug) Debug.print(Debug.VERBOSE, "Transport type: " + type);
String[] ps = ss[1].split(",");
parameters = new HashMap<String, String>();
for (String p : ps) {
String[] kv = p.split("=", 2);
parameters.put(kv[0], kv[1]);
}
if (Debug.debug) Debug.print(Debug.VERBOSE, "Transport options: " + parameters);
}
public String getType() {
return type;
}
public String getParameter(String key) {
return parameters.get(key);
}
public String toString() {
return type + ": " + parameters;
}
}

View file

@ -0,0 +1,22 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
/**
* Interface for callbacks in async mode
*/
public interface CallbackHandler<ReturnType> {
public void handle(ReturnType r);
public void handleError(DBusExecutionException e);
}

View file

@ -0,0 +1,93 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* This class is the super class of both Structs and Tuples
* and holds common methods.
*/
abstract class Container {
private static Map<Type, Type[]> typecache = new HashMap<Type, Type[]>();
static void putTypeCache(Type k, Type[] v) {
typecache.put(k, v);
}
static Type[] getTypeCache(Type k) {
return typecache.get(k);
}
private Object[] parameters = null;
public Container() {
}
private void setup() {
Field[] fs = getClass().getDeclaredFields();
Object[] args = new Object[fs.length];
int diff = 0;
for (Field f : fs) {
Position p = f.getAnnotation(Position.class);
if (null == p) {
diff++;
continue;
}
try {
args[p.value()] = f.get(this);
} catch (IllegalAccessException IAe) {
}
}
this.parameters = new Object[args.length - diff];
System.arraycopy(args, 0, parameters, 0, parameters.length);
}
/**
* Returns the struct contents in order.
*
* @throws DBusException If there is a problem doing this.
*/
public final Object[] getParameters() {
if (null != parameters) return parameters;
setup();
return parameters;
}
/**
* Returns this struct as a string.
*/
public final String toString() {
String s = getClass().getName() + "<";
if (null == parameters)
setup();
if (0 == parameters.length)
return s + ">";
for (Object o : parameters)
s += o + ", ";
return s.replaceAll(", $", ">");
}
public final boolean equals(Object other) {
if (other instanceof Container) {
Container that = (Container) other;
if (this.getClass().equals(that.getClass()))
return Arrays.equals(this.getParameters(), that.getParameters());
else return false;
} else return false;
}
}

View file

@ -0,0 +1,117 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import org.freedesktop.DBus.Error.NoReply;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import static org.freedesktop.dbus.Gettext.getString;
/**
* A handle to an asynchronous method call.
*/
public class DBusAsyncReply<ReturnType> {
/**
* Check if any of a set of asynchronous calls have had a reply.
*
* @param replies A Collection of handles to replies to check.
* @return A Collection only containing those calls which have had replies.
*/
public static Collection<DBusAsyncReply<? extends Object>> hasReply(Collection<DBusAsyncReply<? extends Object>> replies) {
Collection<DBusAsyncReply<? extends Object>> c = new ArrayList<DBusAsyncReply<? extends Object>>(replies);
Iterator<DBusAsyncReply<? extends Object>> i = c.iterator();
while (i.hasNext())
if (!i.next().hasReply()) i.remove();
return c;
}
private ReturnType rval = null;
private DBusExecutionException error = null;
private MethodCall mc;
private Method me;
private AbstractConnection conn;
DBusAsyncReply(MethodCall mc, Method me, AbstractConnection conn) {
this.mc = mc;
this.me = me;
this.conn = conn;
}
@SuppressWarnings("unchecked")
private synchronized void checkReply() {
if (mc.hasReply()) {
Message m = mc.getReply();
if (m instanceof Error)
error = ((Error) m).getException();
else if (m instanceof MethodReturn) {
try {
rval = (ReturnType) RemoteInvocationHandler.convertRV(m.getSig(), m.getParameters(), me, conn);
} catch (DBusExecutionException DBEe) {
error = DBEe;
} catch (DBusException DBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
error = new DBusExecutionException(DBe.getMessage());
}
}
}
}
/**
* Check if we've had a reply.
*
* @return True if we have a reply
*/
public boolean hasReply() {
if (null != rval || null != error) return true;
checkReply();
return null != rval || null != error;
}
/**
* Get the reply.
*
* @return The return value from the method.
* @throws DBusExecutionException if the reply to the method was an error.
* @throws NoReply if the method hasn't had a reply yet
*/
public ReturnType getReply() throws DBusExecutionException {
if (null != rval) return rval;
else if (null != error) throw error;
checkReply();
if (null != rval) return rval;
else if (null != error) throw error;
else throw new NoReply(getString("asyncCallNoReply"));
}
public String toString() {
return getString("waitingFor") + mc;
}
Method getMethod() {
return me;
}
AbstractConnection getConnection() {
return conn;
}
MethodCall getCall() {
return mc;
}
}

View file

@ -0,0 +1,79 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
/**
* Holds information on a method call
*/
public class DBusCallInfo {
/**
* Indicates the caller won't wait for a reply (and we won't send one).
*/
public static final int NO_REPLY = Message.Flags.NO_REPLY_EXPECTED;
public static final int ASYNC = 0x100;
private String source;
private String destination;
private String objectpath;
private String iface;
private String method;
private int flags;
DBusCallInfo(Message m) {
this.source = m.getSource();
this.destination = m.getDestination();
this.objectpath = m.getPath();
this.iface = m.getInterface();
this.method = m.getName();
this.flags = m.getFlags();
}
/**
* Returns the BusID which called the method
*/
public String getSource() {
return source;
}
/**
* Returns the name with which we were addressed on the Bus
*/
public String getDestination() {
return destination;
}
/**
* Returns the object path used to call this method
*/
public String getObjectPath() {
return objectpath;
}
/**
* Returns the interface this method was called with
*/
public String getInterface() {
return iface;
}
/**
* Returns the method name used to call this method
*/
public String getMethod() {
return method;
}
/**
* Returns any flags set on this method call
*/
public int getFlags() {
return flags;
}
}

View file

@ -0,0 +1,794 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import org.freedesktop.DBus;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import org.freedesktop.dbus.exceptions.NotConnected;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import static org.freedesktop.dbus.Gettext.getString;
/**
* Handles a connection to DBus.
* <p>
* This is a Singleton class, only 1 connection to the SYSTEM or SESSION busses can be made.
* Repeated calls to getConnection will return the same reference.
* </p>
* <p>
* Signal Handlers and method calls from remote objects are run in their own threads, you MUST handle the concurrency issues.
* </p>
*/
public class DBusConnection extends AbstractConnection {
/**
* Add addresses of peers to a set which will watch for them to
* disappear and automatically remove them from the set.
*/
public class PeerSet implements Set<String>, DBusSigHandler<DBus.NameOwnerChanged> {
private Set<String> addresses;
public PeerSet() {
addresses = new TreeSet<String>();
try {
addSigHandler(new DBusMatchRule(DBus.NameOwnerChanged.class, null, null), this);
} catch (DBusException DBe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
}
}
public void handle(DBus.NameOwnerChanged noc) {
if (Debug.debug)
Debug.print(Debug.DEBUG, "Received NameOwnerChanged(" + noc.name + "," + noc.old_owner + "," + noc.new_owner + ")");
if ("".equals(noc.new_owner) && addresses.contains(noc.name))
remove(noc.name);
}
public boolean add(String address) {
if (Debug.debug)
Debug.print(Debug.DEBUG, "Adding " + address);
synchronized (addresses) {
return addresses.add(address);
}
}
public boolean addAll(Collection<? extends String> addresses) {
synchronized (this.addresses) {
return this.addresses.addAll(addresses);
}
}
public void clear() {
synchronized (addresses) {
addresses.clear();
}
}
public boolean contains(Object o) {
return addresses.contains(o);
}
public boolean containsAll(Collection<?> os) {
return addresses.containsAll(os);
}
public boolean equals(Object o) {
if (o instanceof PeerSet)
return ((PeerSet) o).addresses.equals(addresses);
else return false;
}
public int hashCode() {
return addresses.hashCode();
}
public boolean isEmpty() {
return addresses.isEmpty();
}
public Iterator<String> iterator() {
return addresses.iterator();
}
public boolean remove(Object o) {
if (Debug.debug)
Debug.print(Debug.DEBUG, "Removing " + o);
synchronized (addresses) {
return addresses.remove(o);
}
}
public boolean removeAll(Collection<?> os) {
synchronized (addresses) {
return addresses.removeAll(os);
}
}
public boolean retainAll(Collection<?> os) {
synchronized (addresses) {
return addresses.retainAll(os);
}
}
public int size() {
return addresses.size();
}
public Object[] toArray() {
synchronized (addresses) {
return addresses.toArray();
}
}
public <T> T[] toArray(T[] a) {
synchronized (addresses) {
return addresses.toArray(a);
}
}
}
private class _sighandler implements DBusSigHandler<DBusSignal> {
public void handle(DBusSignal s) {
if (s instanceof org.freedesktop.DBus.Local.Disconnected) {
if (Debug.debug) Debug.print(Debug.WARN, "Handling disconnected signal from bus");
try {
Error err = new Error(
"org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")});
if (null != pendingCalls) synchronized (pendingCalls) {
long[] set = pendingCalls.getKeys();
for (long l : set)
if (-1 != l) {
MethodCall m = pendingCalls.remove(l);
if (null != m)
m.setReply(err);
}
}
synchronized (pendingErrors) {
pendingErrors.add(err);
}
} catch (DBusException DBe) {
}
} else if (s instanceof org.freedesktop.DBus.NameAcquired) {
busnames.add(((org.freedesktop.DBus.NameAcquired) s).name);
}
}
}
/**
* System Bus
*/
public static final int SYSTEM = 0;
/**
* Session Bus
*/
public static final int SESSION = 1;
public static final String DEFAULT_SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket";
private List<String> busnames;
private static final Map<Object, DBusConnection> conn = new HashMap<Object, DBusConnection>();
private int _refcount = 0;
private Object _reflock = new Object();
private DBus _dbus;
/**
* Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
*
* @param address The address of the bus to connect to
* @throws DBusException If there is a problem connecting to the Bus.
*/
public static DBusConnection getConnection(String address) throws DBusException {
synchronized (conn) {
DBusConnection c = conn.get(address);
if (null != c) {
synchronized (c._reflock) {
c._refcount++;
}
return c;
} else {
c = new DBusConnection(address);
conn.put(address, c);
return c;
}
}
}
/**
* Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
*
* @param bustype The Bus to connect to.
* @throws DBusException If there is a problem connecting to the Bus.
* @see #SYSTEM
* @see #SESSION
*/
public static DBusConnection getConnection(int bustype) throws DBusException {
synchronized (conn) {
String s = null;
switch (bustype) {
case SYSTEM:
s = System.getenv("DBUS_SYSTEM_BUS_ADDRESS");
if (null == s) s = DEFAULT_SYSTEM_BUS_ADDRESS;
break;
case SESSION:
s = System.getenv("DBUS_SESSION_BUS_ADDRESS");
if (null == s) {
// address gets stashed in $HOME/.dbus/session-bus/`dbus-uuidgen --get`-`sed 's/:\(.\)\..*/\1/' <<< $DISPLAY`
String display = System.getenv("DISPLAY");
if (null == display) throw new DBusException(getString("cannotResolveSessionBusAddress"));
File uuidfile = new File("/var/lib/dbus/machine-id");
if (!uuidfile.exists()) throw new DBusException(getString("cannotResolveSessionBusAddress"));
try {
BufferedReader r = new BufferedReader(new FileReader(uuidfile));
String uuid = r.readLine();
String homedir = System.getProperty("user.home");
File addressfile = new File(homedir + "/.dbus/session-bus",
uuid + "-" + display.replaceAll(":([0-9]*)\\..*", "$1"));
if (!addressfile.exists())
throw new DBusException(getString("cannotResolveSessionBusAddress"));
r = new BufferedReader(new FileReader(addressfile));
String l;
while (null != (l = r.readLine())) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Reading D-Bus session data: " + l);
if (l.matches("DBUS_SESSION_BUS_ADDRESS.*")) {
s = l.replaceAll("^[^=]*=", "");
if (Debug.debug) Debug.print(Debug.VERBOSE, "Parsing " + l + " to " + s);
}
}
if (null == s || "".equals(s))
throw new DBusException(getString("cannotResolveSessionBusAddress"));
if (Debug.debug)
Debug.print(Debug.INFO, "Read bus address " + s + " from file " + addressfile.toString());
} catch (Exception e) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new DBusException(getString("cannotResolveSessionBusAddress"));
}
}
break;
default:
throw new DBusException(getString("invalidBusType") + bustype);
}
DBusConnection c = conn.get(s);
if (Debug.debug) Debug.print(Debug.VERBOSE, "Getting bus connection for " + s + ": " + c);
if (null != c) {
synchronized (c._reflock) {
c._refcount++;
}
return c;
} else {
if (Debug.debug) Debug.print(Debug.DEBUG, "Creating new bus connection to: " + s);
c = new DBusConnection(s);
conn.put(s, c);
return c;
}
}
}
@SuppressWarnings("unchecked")
private DBusConnection(String address) throws DBusException {
super(address);
busnames = new Vector<String>();
synchronized (_reflock) {
_refcount = 1;
}
try {
transport = new Transport(addr, AbstractConnection.TIMEOUT);
connected = true;
} catch (IOException IOe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOe);
disconnect();
throw new DBusException(getString("connectionFailure") + IOe.getMessage());
} catch (ParseException Pe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, Pe);
disconnect();
throw new DBusException(getString("connectionFailure") + Pe.getMessage());
}
// start listening for calls
listen();
// register disconnect handlers
DBusSigHandler h = new _sighandler();
addSigHandlerWithoutMatch(org.freedesktop.DBus.Local.Disconnected.class, h);
addSigHandlerWithoutMatch(org.freedesktop.DBus.NameAcquired.class, h);
// register ourselves
_dbus = getRemoteObject("org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
try {
busnames.add(_dbus.Hello());
} catch (DBusExecutionException DBEe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
throw new DBusException(DBEe.getMessage());
}
}
@SuppressWarnings("unchecked")
DBusInterface dynamicProxy(String source, String path) throws DBusException {
if (Debug.debug)
Debug.print(Debug.INFO, "Introspecting " + path + " on " + source + " for dynamic proxy creation");
try {
DBus.Introspectable intro = getRemoteObject(source, path, DBus.Introspectable.class);
String data = intro.Introspect();
if (Debug.debug) Debug.print(Debug.VERBOSE, "Got introspection data: " + data);
String[] tags = data.split("[<>]");
Vector<String> ifaces = new Vector<String>();
for (String tag : tags) {
if (tag.startsWith("interface")) {
ifaces.add(tag.replaceAll("^interface *name *= *['\"]([^'\"]*)['\"].*$", "$1"));
}
}
Vector<Class<? extends Object>> ifcs = new Vector<Class<? extends Object>>();
for (String iface : ifaces) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Trying interface " + iface);
int j = 0;
while (j >= 0) {
try {
Class ifclass = Class.forName(iface);
if (!ifcs.contains(ifclass))
ifcs.add(ifclass);
break;
} catch (Exception e) {
}
j = iface.lastIndexOf(".");
char[] cs = iface.toCharArray();
if (j >= 0) {
cs[j] = '$';
iface = String.valueOf(cs);
}
}
}
if (ifcs.size() == 0) throw new DBusException(getString("interfaceToCastNotFound"));
RemoteObject ro = new RemoteObject(source, path, null, false);
DBusInterface newi = (DBusInterface)
Proxy.newProxyInstance(ifcs.get(0).getClassLoader(),
ifcs.toArray(new Class[0]),
new RemoteInvocationHandler(this, ro));
importedObjects.put(newi, ro);
return newi;
} catch (Exception e) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new DBusException(MessageFormat.format(getString("createProxyExportFailure"), new Object[]{path, source, e.getMessage()}));
}
}
DBusInterface getExportedObject(String source, String path) throws DBusException {
ExportedObject o = null;
synchronized (exportedObjects) {
o = exportedObjects.get(path);
}
if (null != o && null == o.object.get()) {
unExportObject(path);
o = null;
}
if (null != o) return o.object.get();
if (null == source) throw new DBusException(getString("objectNotExportedNoRemoteSpecified"));
return dynamicProxy(source, path);
}
/**
* Release a bus name.
* Releases the name so that other people can use it
*
* @param busname The name to release. MUST be in dot-notation like "org.freedesktop.local"
* @throws DBusException If the busname is incorrectly formatted.
*/
public void releaseBusName(String busname) throws DBusException {
if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName"));
synchronized (this.busnames) {
UInt32 rv;
try {
rv = _dbus.ReleaseName(busname);
} catch (DBusExecutionException DBEe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
throw new DBusException(DBEe.getMessage());
}
this.busnames.remove(busname);
}
}
/**
* Request a bus name.
* Request the well known name that this should respond to on the Bus.
*
* @param busname The name to respond to. MUST be in dot-notation like "org.freedesktop.local"
* @throws DBusException If the register name failed, or our name already exists on the bus.
* or if busname is incorrectly formatted.
*/
public void requestBusName(String busname) throws DBusException {
if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName"));
synchronized (this.busnames) {
UInt32 rv;
try {
rv = _dbus.RequestName(busname,
new UInt32(DBus.DBUS_NAME_FLAG_REPLACE_EXISTING |
DBus.DBUS_NAME_FLAG_DO_NOT_QUEUE));
} catch (DBusExecutionException DBEe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
throw new DBusException(DBEe.getMessage());
}
switch (rv.intValue()) {
case DBus.DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
break;
case DBus.DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
throw new DBusException(getString("dbusRegistrationFailure"));
case DBus.DBUS_REQUEST_NAME_REPLY_EXISTS:
throw new DBusException(getString("dbusRegistrationFailure"));
case DBus.DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
break;
default:
break;
}
this.busnames.add(busname);
}
}
/**
* Returns the unique name of this connection.
*/
public String getUniqueName() {
return busnames.get(0);
}
/**
* Returns all the names owned by this connection.
*/
public String[] getNames() {
Set<String> names = new TreeSet<String>();
names.addAll(busnames);
return names.toArray(new String[0]);
}
public <I extends DBusInterface> I getPeerRemoteObject(String busname, String objectpath, Class<I> type) throws DBusException {
return getPeerRemoteObject(busname, objectpath, type, true);
}
/**
* Return a reference to a remote object.
* This method will resolve the well known name (if given) to a unique bus name when you call it.
* This means that if a well known name is released by one process and acquired by another calls to
* objects gained from this method will continue to operate on the original process.
* <p>
* This method will use bus introspection to determine the interfaces on a remote object and so
* <b>may block</b> and <b>may fail</b>. The resulting proxy object will, however, be castable
* to any interface it implements. It will also autostart the process if applicable. Also note
* that the resulting proxy may fail to execute the correct method with overloaded methods
* and that complex types may fail in interesting ways. Basically, if something odd happens,
* try specifying the interface explicitly.
*
* @param busname The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
* or may be a DBus address such as ":1-16".
* @param objectpath The path on which the process is exporting the object.$
* @return A reference to a remote object.
* @throws ClassCastException If type is not a sub-type of DBusInterface
* @throws DBusException If busname or objectpath are incorrectly formatted.
*/
public DBusInterface getPeerRemoteObject(String busname, String objectpath) throws DBusException {
if (null == busname) throw new DBusException(getString("nullBusName"));
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
|| busname.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + busname);
String unique = _dbus.GetNameOwner(busname);
return dynamicProxy(unique, objectpath);
}
/**
* Return a reference to a remote object.
* This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
* In particular this means that if a process providing the well known name disappears and is taken over by another process
* proxy objects gained by this method will make calls on the new proccess.
* <p>
* This method will use bus introspection to determine the interfaces on a remote object and so
* <b>may block</b> and <b>may fail</b>. The resulting proxy object will, however, be castable
* to any interface it implements. It will also autostart the process if applicable. Also note
* that the resulting proxy may fail to execute the correct method with overloaded methods
* and that complex types may fail in interesting ways. Basically, if something odd happens,
* try specifying the interface explicitly.
*
* @param busname The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
* or may be a DBus address such as ":1-16".
* @param objectpath The path on which the process is exporting the object.
* @return A reference to a remote object.
* @throws ClassCastException If type is not a sub-type of DBusInterface
* @throws DBusException If busname or objectpath are incorrectly formatted.
*/
public DBusInterface getRemoteObject(String busname, String objectpath) throws DBusException {
if (null == busname) throw new DBusException(getString("nullBusName"));
if (null == objectpath) throw new DBusException(getString("nullObjectPath"));
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
|| busname.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + busname);
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidObjectPath") + objectpath);
return dynamicProxy(busname, objectpath);
}
/**
* Return a reference to a remote object.
* This method will resolve the well known name (if given) to a unique bus name when you call it.
* This means that if a well known name is released by one process and acquired by another calls to
* objects gained from this method will continue to operate on the original process.
*
* @param busname The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
* or may be a DBus address such as ":1-16".
* @param objectpath The path on which the process is exporting the object.$
* @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
* as the interface the remote object is exporting.
* @param autostart Disable/Enable auto-starting of services in response to calls on this object.
* Default is enabled; when calling a method with auto-start enabled, if the destination is a well-known name
* and is not owned the bus will attempt to start a process to take the name. When disabled an error is
* returned immediately.
* @return A reference to a remote object.
* @throws ClassCastException If type is not a sub-type of DBusInterface
* @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
*/
public <I extends DBusInterface> I getPeerRemoteObject(String busname, String objectpath, Class<I> type, boolean autostart) throws DBusException {
if (null == busname) throw new DBusException(getString("nullBusName"));
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
|| busname.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + busname);
String unique = _dbus.GetNameOwner(busname);
return getRemoteObject(unique, objectpath, type, autostart);
}
/**
* Return a reference to a remote object.
* This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
* In particular this means that if a process providing the well known name disappears and is taken over by another process
* proxy objects gained by this method will make calls on the new proccess.
*
* @param busname The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
* or may be a DBus address such as ":1-16".
* @param objectpath The path on which the process is exporting the object.
* @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
* as the interface the remote object is exporting.
* @return A reference to a remote object.
* @throws ClassCastException If type is not a sub-type of DBusInterface
* @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
*/
public <I extends DBusInterface> I getRemoteObject(String busname, String objectpath, Class<I> type) throws DBusException {
return getRemoteObject(busname, objectpath, type, true);
}
/**
* Return a reference to a remote object.
* This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
* In particular this means that if a process providing the well known name disappears and is taken over by another process
* proxy objects gained by this method will make calls on the new proccess.
*
* @param busname The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
* or may be a DBus address such as ":1-16".
* @param objectpath The path on which the process is exporting the object.
* @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
* as the interface the remote object is exporting.
* @param autostart Disable/Enable auto-starting of services in response to calls on this object.
* Default is enabled; when calling a method with auto-start enabled, if the destination is a well-known name
* and is not owned the bus will attempt to start a process to take the name. When disabled an error is
* returned immediately.
* @return A reference to a remote object.
* @throws ClassCastException If type is not a sub-type of DBusInterface
* @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
*/
@SuppressWarnings("unchecked")
public <I extends DBusInterface> I getRemoteObject(String busname, String objectpath, Class<I> type, boolean autostart) throws DBusException {
if (null == busname) throw new DBusException(getString("nullBusName"));
if (null == objectpath) throw new DBusException(getString("nullObjectPath"));
if (null == type) throw new ClassCastException(getString("notDBusInterface"));
if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
|| busname.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + busname);
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidObjectPath") + objectpath);
if (!DBusInterface.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusInterface"));
// don't let people import things which don't have a
// valid D-Bus interface name
if (type.getName().equals(type.getSimpleName()))
throw new DBusException(getString("interfaceNotAllowedOutsidePackage"));
RemoteObject ro = new RemoteObject(busname, objectpath, type, autostart);
I i = (I) Proxy.newProxyInstance(type.getClassLoader(),
new Class[]{type}, new RemoteInvocationHandler(this, ro));
importedObjects.put(i, ro);
return i;
}
/**
* Remove a Signal Handler.
* Stops listening for this signal.
*
* @param type The signal to watch for.
* @param source The source of the signal.
* @throws DBusException If listening for the signal on the bus failed.
* @throws ClassCastException If type is not a sub-type of DBusSignal.
*/
public <T extends DBusSignal> void removeSigHandler(Class<T> type, String source, DBusSigHandler<T> handler) throws DBusException {
if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + source);
removeSigHandler(new DBusMatchRule(type, source, null), handler);
}
/**
* Remove a Signal Handler.
* Stops listening for this signal.
*
* @param type The signal to watch for.
* @param source The source of the signal.
* @param object The object emitting the signal.
* @throws DBusException If listening for the signal on the bus failed.
* @throws ClassCastException If type is not a sub-type of DBusSignal.
*/
public <T extends DBusSignal> void removeSigHandler(Class<T> type, String source, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + source);
String objectpath = importedObjects.get(object).objectpath;
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidObjectPath") + objectpath);
removeSigHandler(new DBusMatchRule(type, source, objectpath), handler);
}
protected <T extends DBusSignal> void removeSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException {
SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
synchronized (handledSignals) {
Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
if (null != v) {
v.remove(handler);
if (0 == v.size()) {
handledSignals.remove(key);
try {
_dbus.RemoveMatch(rule.toString());
} catch (NotConnected NC) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, NC);
} catch (DBusExecutionException DBEe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
throw new DBusException(DBEe.getMessage());
}
}
}
}
}
/**
* Add a Signal Handler.
* Adds a signal handler to call when a signal is received which matches the specified type, name and source.
*
* @param type The signal to watch for.
* @param source The process which will send the signal. This <b>MUST</b> be a unique bus name and not a well known name.
* @param handler The handler to call when a signal is received.
* @throws DBusException If listening for the signal on the bus failed.
* @throws ClassCastException If type is not a sub-type of DBusSignal.
*/
@SuppressWarnings("unchecked")
public <T extends DBusSignal> void addSigHandler(Class<T> type, String source, DBusSigHandler<T> handler) throws DBusException {
if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + source);
addSigHandler(new DBusMatchRule(type, source, null), (DBusSigHandler<? extends DBusSignal>) handler);
}
/**
* Add a Signal Handler.
* Adds a signal handler to call when a signal is received which matches the specified type, name, source and object.
*
* @param type The signal to watch for.
* @param source The process which will send the signal. This <b>MUST</b> be a unique bus name and not a well known name.
* @param object The object from which the signal will be emitted
* @param handler The handler to call when a signal is received.
* @throws DBusException If listening for the signal on the bus failed.
* @throws ClassCastException If type is not a sub-type of DBusSignal.
*/
@SuppressWarnings("unchecked")
public <T extends DBusSignal> void addSigHandler(Class<T> type, String source, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidBusName") + source);
String objectpath = importedObjects.get(object).objectpath;
if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
throw new DBusException(getString("invalidObjectPath") + objectpath);
addSigHandler(new DBusMatchRule(type, source, objectpath), (DBusSigHandler<? extends DBusSignal>) handler);
}
protected <T extends DBusSignal> void addSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException {
try {
_dbus.AddMatch(rule.toString());
} catch (DBusExecutionException DBEe) {
if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
throw new DBusException(DBEe.getMessage());
}
SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
synchronized (handledSignals) {
Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
if (null == v) {
v = new Vector<DBusSigHandler<? extends DBusSignal>>();
v.add(handler);
handledSignals.put(key, v);
} else
v.add(handler);
}
}
/**
* Disconnect from the Bus.
* This only disconnects when the last reference to the bus has disconnect called on it
* or has been destroyed.
*/
public void disconnect() {
synchronized (conn) {
synchronized (_reflock) {
if (0 == --_refcount) {
if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting DBusConnection");
// Set all pending messages to have an error.
try {
Error err = new Error(
"org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")});
synchronized (pendingCalls) {
long[] set = pendingCalls.getKeys();
for (long l : set)
if (-1 != l) {
MethodCall m = pendingCalls.remove(l);
if (null != m)
m.setReply(err);
}
pendingCalls = null;
}
synchronized (pendingErrors) {
pendingErrors.add(err);
}
} catch (DBusException DBe) {
}
conn.remove(addr);
super.disconnect();
}
}
}
}
}

View file

@ -0,0 +1,31 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
/**
* Denotes a class as exportable or a remote interface which can be called.
* <p>
* Any interface which should be exported or imported should extend this
* interface. All public methods from that interface are exported/imported
* with the given method signatures.
* </p>
* <p>
* All method calls on exported objects are run in their own threads.
* Application writers are responsible for any concurrency issues.
* </p>
*/
public interface DBusInterface {
/**
* Returns true on remote objects.
* Local objects implementing this interface MUST return false.
*/
public boolean isRemote();
}

View file

@ -0,0 +1,28 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Force the interface name to be different to the Java class name.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DBusInterfaceName {
/**
* The replacement interface name.
*/
String value();
}

View file

@ -0,0 +1,150 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
class DBusMap<K, V> implements Map<K, V> {
Object[][] entries;
public DBusMap(Object[][] entries) {
this.entries = entries;
}
class Entry implements Map.Entry<K, V>, Comparable<Entry> {
private int entry;
public Entry(int i) {
this.entry = i;
}
public boolean equals(Object o) {
if (null == o) return false;
if (!(o instanceof DBusMap.Entry)) return false;
return this.entry == ((Entry) o).entry;
}
@SuppressWarnings("unchecked")
public K getKey() {
return (K) entries[entry][0];
}
@SuppressWarnings("unchecked")
public V getValue() {
return (V) entries[entry][1];
}
public int hashCode() {
return entries[entry][0].hashCode();
}
public V setValue(V value) {
throw new UnsupportedOperationException();
}
public int compareTo(Entry e) {
return entry - e.entry;
}
}
public void clear() {
throw new UnsupportedOperationException();
}
public boolean containsKey(Object key) {
for (int i = 0; i < entries.length; i++)
if (key == entries[i][0] || (key != null && key.equals(entries[i][0])))
return true;
return false;
}
public boolean containsValue(Object value) {
for (int i = 0; i < entries.length; i++)
if (value == entries[i][1] || (value != null && value.equals(entries[i][1])))
return true;
return false;
}
public Set<Map.Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> s = new TreeSet<Map.Entry<K, V>>();
for (int i = 0; i < entries.length; i++)
s.add(new Entry(i));
return s;
}
@SuppressWarnings("unchecked")
public V get(Object key) {
for (int i = 0; i < entries.length; i++)
if (key == entries[i][0] || (key != null && key.equals(entries[i][0])))
return (V) entries[i][1];
return null;
}
public boolean isEmpty() {
return entries.length == 0;
}
@SuppressWarnings("unchecked")
public Set<K> keySet() {
Set<K> s = new TreeSet<K>();
for (Object[] entry : entries)
s.add((K) entry[0]);
return s;
}
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
public void putAll(Map<? extends K, ? extends V> t) {
throw new UnsupportedOperationException();
}
public V remove(Object key) {
throw new UnsupportedOperationException();
}
public int size() {
return entries.length;
}
@SuppressWarnings("unchecked")
public Collection<V> values() {
List<V> l = new Vector<V>();
for (Object[] entry : entries)
l.add((V) entry[1]);
return l;
}
public int hashCode() {
return Arrays.deepHashCode(entries);
}
@SuppressWarnings("unchecked")
public boolean equals(Object o) {
if (null == o) return false;
if (!(o instanceof Map)) return false;
return ((Map<K, V>) o).entrySet().equals(entrySet());
}
public String toString() {
String s = "{ ";
for (int i = 0; i < entries.length; i++)
s += entries[i][0] + " => " + entries[i][1] + ",";
return s.replaceAll(".$", " }");
}
}

View file

@ -0,0 +1,151 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import java.util.HashMap;
import static org.freedesktop.dbus.Gettext.getString;
public class DBusMatchRule {
/* signal, error, method_call, method_reply */
private String type;
private String iface;
private String member;
private String object;
private String source;
private static HashMap<String, Class<? extends DBusSignal>> signalTypeMap =
new HashMap<String, Class<? extends DBusSignal>>();
static Class<? extends DBusSignal> getCachedSignalType(String type) {
return signalTypeMap.get(type);
}
public DBusMatchRule(String type, String iface, String member) {
this.type = type;
this.iface = iface;
this.member = member;
}
public DBusMatchRule(DBusExecutionException e) throws DBusException {
this(e.getClass());
member = null;
type = "error";
}
public DBusMatchRule(Message m) {
iface = m.getInterface();
member = m.getName();
if (m instanceof DBusSignal)
type = "signal";
else if (m instanceof Error) {
type = "error";
member = null;
} else if (m instanceof MethodCall)
type = "method_call";
else if (m instanceof MethodReturn)
type = "method_reply";
}
public DBusMatchRule(Class<? extends DBusInterface> c, String method) throws DBusException {
this(c);
member = method;
type = "method_call";
}
public DBusMatchRule(Class<? extends Object> c, String source, String object) throws DBusException {
this(c);
this.source = source;
this.object = object;
}
@SuppressWarnings("unchecked")
public DBusMatchRule(Class<? extends Object> c) throws DBusException {
if (DBusInterface.class.isAssignableFrom(c)) {
if (null != c.getAnnotation(DBusInterfaceName.class))
iface = c.getAnnotation(DBusInterfaceName.class).value();
else
iface = AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".");
if (!iface.matches(".*\\..*"))
throw new DBusException(getString("interfaceMustBeDefinedPackage"));
member = null;
type = null;
} else if (DBusSignal.class.isAssignableFrom(c)) {
if (null == c.getEnclosingClass())
throw new DBusException(getString("signalsMustBeMemberOfClass"));
else if (null != c.getEnclosingClass().getAnnotation(DBusInterfaceName.class))
iface = c.getEnclosingClass().getAnnotation(DBusInterfaceName.class).value();
else
iface = AbstractConnection.dollar_pattern.matcher(c.getEnclosingClass().getName()).replaceAll(".");
// Don't export things which are invalid D-Bus interfaces
if (!iface.matches(".*\\..*"))
throw new DBusException(getString("interfaceMustBeDefinedPackage"));
if (c.isAnnotationPresent(DBusMemberName.class))
member = c.getAnnotation(DBusMemberName.class).value();
else
member = c.getSimpleName();
signalTypeMap.put(iface + '$' + member, (Class<? extends DBusSignal>) c);
type = "signal";
} else if (Error.class.isAssignableFrom(c)) {
if (null != c.getAnnotation(DBusInterfaceName.class))
iface = c.getAnnotation(DBusInterfaceName.class).value();
else
iface = AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".");
if (!iface.matches(".*\\..*"))
throw new DBusException(getString("interfaceMustBeDefinedPackage"));
member = null;
type = "error";
} else if (DBusExecutionException.class.isAssignableFrom(c)) {
if (null != c.getClass().getAnnotation(DBusInterfaceName.class))
iface = c.getClass().getAnnotation(DBusInterfaceName.class).value();
else
iface = AbstractConnection.dollar_pattern.matcher(c.getClass().getName()).replaceAll(".");
if (!iface.matches(".*\\..*"))
throw new DBusException(getString("interfaceMustBeDefinedPackage"));
member = null;
type = "error";
} else
throw new DBusException(getString("invalidTypeMatchRule") + c);
}
public String toString() {
String s = null;
if (null != type) s = null == s ? "type='" + type + "'" : s + ",type='" + type + "'";
if (null != member) s = null == s ? "member='" + member + "'" : s + ",member='" + member + "'";
if (null != iface) s = null == s ? "interface='" + iface + "'" : s + ",interface='" + iface + "'";
if (null != source) s = null == s ? "sender='" + source + "'" : s + ",sender='" + source + "'";
if (null != object) s = null == s ? "path='" + object + "'" : s + ",path='" + object + "'";
return s;
}
public String getType() {
return type;
}
public String getInterface() {
return iface;
}
public String getMember() {
return member;
}
public String getSource() {
return source;
}
public String getObject() {
return object;
}
}

View file

@ -0,0 +1,29 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Force the member (method/signal) name on the bus to be different to the Java name.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DBusMemberName {
/**
* The replacement member name.
*/
String value();
}

View file

@ -0,0 +1,39 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import org.freedesktop.dbus.exceptions.DBusException;
/**
* Custom classes may be sent over DBus if they implement this interface.
* <p>
* In addition to the serialize method, classes <b>MUST</b> implement
* a deserialize method which returns null and takes as it's arguments
* all the DBus types the class will be serialied to <i>in order</i> and
* <i>with type parameterisation</i>. They <b>MUST</b> also provide a
* zero-argument constructor.
* </p>
* <p>
* The serialize method should return the class properties you wish to
* serialize, correctly formatted for the wire
* (DBusConnection.convertParameters() can help with this), in order in an
* Object array.
* </p>
* <p>
* The deserialize method will be called once after the zero-argument
* constructor. This should contain all the code to initialise the object
* from the types.
* </p>
*/
public interface DBusSerializable {
public Object[] serialize() throws DBusException;
}

View file

@ -0,0 +1,27 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
/**
* Handle a signal on DBus.
* All Signal handlers are run in their own Thread.
* Application writers are responsible for managing any concurrency issues.
*/
public interface DBusSigHandler<T extends DBusSignal> {
/**
* Handle a signal.
*
* @param s The signal to handle. If such a class exists, the
* signal will be an instance of the class with the correct type signature.
* Otherwise it will be an instance of DBusSignal
*/
public void handle(T s);
}

View file

@ -0,0 +1,259 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.MessageFormatException;
import java.lang.reflect.Constructor;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import static org.freedesktop.dbus.Gettext.getString;
public class DBusSignal extends Message {
DBusSignal() {
}
public DBusSignal(String source, String path, String iface, String member, String sig, Object... args) throws DBusException {
super(Message.Endian.BIG, Message.MessageType.SIGNAL, (byte) 0);
if (null == path || null == member || null == iface)
throw new MessageFormatException(getString("missingPathInterfaceSignal"));
headers.put(Message.HeaderField.PATH, path);
headers.put(Message.HeaderField.MEMBER, member);
headers.put(Message.HeaderField.INTERFACE, iface);
Vector<Object> hargs = new Vector<Object>();
hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, path}});
hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
if (null != source) {
headers.put(Message.HeaderField.SENDER, source);
hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
}
if (null != sig) {
hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
headers.put(Message.HeaderField.SIGNATURE, sig);
setArgs(args);
}
blen = new byte[4];
appendBytes(blen);
append("ua(yv)", ++serial, hargs.toArray());
pad((byte) 8);
long c = bytecounter;
if (null != sig) append(sig, args);
marshallint(bytecounter - c, blen, 0, 4);
bodydone = true;
}
static class internalsig extends DBusSignal {
public internalsig(String source, String objectpath, String type, String name, String sig, Object[] parameters, long serial) throws DBusException {
super(source, objectpath, type, name, sig, parameters, serial);
}
}
private static Map<Class<? extends DBusSignal>, Type[]> typeCache = new HashMap<Class<? extends DBusSignal>, Type[]>();
private static Map<String, Class<? extends DBusSignal>> classCache = new HashMap<String, Class<? extends DBusSignal>>();
private static Map<Class<? extends DBusSignal>, Constructor<? extends DBusSignal>> conCache = new HashMap<Class<? extends DBusSignal>, Constructor<? extends DBusSignal>>();
private static Map<String, String> signames = new HashMap<String, String>();
private static Map<String, String> intnames = new HashMap<String, String>();
private Class<? extends DBusSignal> c;
private boolean bodydone = false;
private byte[] blen;
static void addInterfaceMap(String java, String dbus) {
intnames.put(dbus, java);
}
static void addSignalMap(String java, String dbus) {
signames.put(dbus, java);
}
static DBusSignal createSignal(Class<? extends DBusSignal> c, String source, String objectpath, String sig, long serial, Object... parameters) throws DBusException {
String type = "";
if (null != c.getEnclosingClass()) {
if (null != c.getEnclosingClass().getAnnotation(DBusInterfaceName.class))
type = c.getEnclosingClass().getAnnotation(DBusInterfaceName.class).value();
else
type = AbstractConnection.dollar_pattern.matcher(c.getEnclosingClass().getName()).replaceAll(".");
} else
throw new DBusException(getString("signalsMustBeMemberOfClass"));
DBusSignal s = new internalsig(source, objectpath, type, c.getSimpleName(), sig, parameters, serial);
s.c = c;
return s;
}
@SuppressWarnings("unchecked")
private static Class<? extends DBusSignal> createSignalClass(String intname, String signame) throws DBusException {
String name = intname + '$' + signame;
Class<? extends DBusSignal> c = classCache.get(name);
if (null == c) c = DBusMatchRule.getCachedSignalType(name);
if (null != c) return c;
do {
try {
c = (Class<? extends DBusSignal>) Class.forName(name);
} catch (ClassNotFoundException CNFe) {
}
name = name.replaceAll("\\.([^\\.]*)$", "\\$$1");
} while (null == c && name.matches(".*\\..*"));
if (null == c)
throw new DBusException(getString("cannotCreateClassFromSignal") + intname + '.' + signame);
classCache.put(name, c);
return c;
}
@SuppressWarnings("unchecked")
DBusSignal createReal(AbstractConnection conn) throws DBusException {
String intname = intnames.get(getInterface());
String signame = signames.get(getName());
if (null == intname) intname = getInterface();
if (null == signame) signame = getName();
if (null == c)
c = createSignalClass(intname, signame);
if (Debug.debug) Debug.print(Debug.DEBUG, "Converting signal to type: " + c);
Type[] types = typeCache.get(c);
Constructor<? extends DBusSignal> con = conCache.get(c);
if (null == types) {
con = (Constructor<? extends DBusSignal>) c.getDeclaredConstructors()[0];
conCache.put(c, con);
Type[] ts = con.getGenericParameterTypes();
types = new Type[ts.length - 1];
for (int i = 1; i < ts.length; i++)
if (ts[i] instanceof TypeVariable)
for (Type b : ((TypeVariable<GenericDeclaration>) ts[i]).getBounds())
types[i - 1] = b;
else
types[i - 1] = ts[i];
typeCache.put(c, types);
}
try {
DBusSignal s;
Object[] args = Marshalling.deSerializeParameters(getParameters(), types, conn);
if (null == args) s = (DBusSignal) con.newInstance(getPath());
else {
Object[] params = new Object[args.length + 1];
params[0] = getPath();
System.arraycopy(args, 0, params, 1, args.length);
if (Debug.debug)
Debug.print(Debug.DEBUG, "Creating signal of type " + c + " with parameters " + Arrays.deepToString(params));
s = (DBusSignal) con.newInstance(params);
}
s.headers = headers;
s.wiredata = wiredata;
s.bytecounter = wiredata.length;
return s;
} catch (Exception e) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new DBusException(e.getMessage());
}
}
/**
* Create a new signal.
* This contructor MUST be called by all sub classes.
*
* @param objectpath The path to the object this is emitted from.
* @param args The parameters of the signal.
* @throws DBusException This is thrown if the subclass is incorrectly defined.
*/
@SuppressWarnings("unchecked")
protected DBusSignal(String objectpath, Object... args) throws DBusException {
super(Message.Endian.BIG, Message.MessageType.SIGNAL, (byte) 0);
if (!objectpath.matches(AbstractConnection.OBJECT_REGEX))
throw new DBusException(getString("invalidObjectPath") + objectpath);
Class<? extends DBusSignal> tc = getClass();
String member;
if (tc.isAnnotationPresent(DBusMemberName.class))
member = tc.getAnnotation(DBusMemberName.class).value();
else
member = tc.getSimpleName();
String iface = null;
Class<? extends Object> enc = tc.getEnclosingClass();
if (null == enc ||
!DBusInterface.class.isAssignableFrom(enc) ||
enc.getName().equals(enc.getSimpleName()))
throw new DBusException(getString("signalsMustBeMemberOfClass"));
else if (null != enc.getAnnotation(DBusInterfaceName.class))
iface = enc.getAnnotation(DBusInterfaceName.class).value();
else
iface = AbstractConnection.dollar_pattern.matcher(enc.getName()).replaceAll(".");
headers.put(Message.HeaderField.PATH, objectpath);
headers.put(Message.HeaderField.MEMBER, member);
headers.put(Message.HeaderField.INTERFACE, iface);
Vector<Object> hargs = new Vector<Object>();
hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, objectpath}});
hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
String sig = null;
if (0 < args.length) {
try {
Type[] types = typeCache.get(tc);
if (null == types) {
Constructor<? extends DBusSignal> con = (Constructor<? extends DBusSignal>) tc.getDeclaredConstructors()[0];
conCache.put(tc, con);
Type[] ts = con.getGenericParameterTypes();
types = new Type[ts.length - 1];
for (int i = 1; i <= types.length; i++)
if (ts[i] instanceof TypeVariable)
types[i - 1] = ((TypeVariable<GenericDeclaration>) ts[i]).getBounds()[0];
else
types[i - 1] = ts[i];
typeCache.put(tc, types);
}
sig = Marshalling.getDBusType(types);
hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
headers.put(Message.HeaderField.SIGNATURE, sig);
setArgs(args);
} catch (Exception e) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new DBusException(getString("errorAddSignalParameters") + e.getMessage());
}
}
blen = new byte[4];
appendBytes(blen);
append("ua(yv)", ++serial, hargs.toArray());
pad((byte) 8);
}
void appendbody(AbstractConnection conn) throws DBusException {
if (bodydone) return;
Type[] types = typeCache.get(getClass());
Object[] args = Marshalling.convertParameters(getParameters(), types, conn);
setArgs(args);
String sig = getSig();
long c = bytecounter;
if (null != args && 0 < args.length) append(sig, args);
marshallint(bytecounter - c, blen, 0, 4);
bodydone = true;
}
}

View file

@ -0,0 +1,122 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
/**
* Provides a long =&gt; MethodCall map which doesn't allocate objects
* on insertion/removal. Keys must be inserted in ascending order.
*/
class EfficientMap {
private long[] kv;
private MethodCall[] vv;
private int start;
private int end;
private int init_size;
public EfficientMap(int initial_size) {
init_size = initial_size;
shrink();
}
private void grow() {
// create new vectors twice as long
long[] oldkv = kv;
kv = new long[oldkv.length * 2];
MethodCall[] oldvv = vv;
vv = new MethodCall[oldvv.length * 2];
// copy start->length to the start of the new vector
System.arraycopy(oldkv, start, kv, 0, oldkv.length - start);
System.arraycopy(oldvv, start, vv, 0, oldvv.length - start);
// copy 0->end to the next part of the new vector
if (end != (oldkv.length - 1)) {
System.arraycopy(oldkv, 0, kv, oldkv.length - start, end + 1);
System.arraycopy(oldvv, 0, vv, oldvv.length - start, end + 1);
}
// reposition pointers
start = 0;
end = oldkv.length;
}
// create a new vector with just the valid keys in and return it
public long[] getKeys() {
int size;
if (start < end) size = end - start;
else size = kv.length - (start - end);
long[] lv = new long[size];
int copya;
if (size > kv.length - start) copya = kv.length - start;
else copya = size;
System.arraycopy(kv, start, lv, 0, copya);
if (copya < size) {
System.arraycopy(kv, 0, lv, copya, size - copya);
}
return lv;
}
private void shrink() {
if (null != kv && kv.length == init_size) return;
// reset to original size
kv = new long[init_size];
vv = new MethodCall[init_size];
start = 0;
end = 0;
}
public void put(long l, MethodCall m) {
// put this at the end
kv[end] = l;
vv[end] = m;
// move the end
if (end == (kv.length - 1)) end = 0;
else end++;
// if we are out of space, grow.
if (end == start) grow();
}
public MethodCall remove(long l) {
// find the item
int pos = find(l);
// if we don't have it return null
if (-1 == pos) return null;
// get the value
MethodCall m = vv[pos];
// set it as unused
vv[pos] = null;
kv[pos] = -1;
// move the pointer to the first full element
while (-1 == kv[start]) {
if (start == (kv.length - 1)) start = 0;
else start++;
// if we have emptied the list, shrink it
if (start == end) {
shrink();
break;
}
}
return m;
}
public boolean contains(long l) {
// check if find succeeds
return -1 != find(l);
}
/* could binary search, but it's probably the first one */
private int find(long l) {
int i = start;
while (i != end && kv[i] != l)
if (i == (kv.length - 1)) i = 0;
else i++;
if (i == end) return -1;
return i;
}
}

View file

@ -0,0 +1,109 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
/**
* Provides a Message queue which doesn't allocate objects
* on insertion/removal.
*/
class EfficientQueue {
private Message[] mv;
private int start;
private int end;
private int init_size;
public EfficientQueue(int initial_size) {
init_size = initial_size;
shrink();
}
private void grow() {
if (Debug.debug) Debug.print(Debug.DEBUG, "Growing");
// create new vectors twice as long
Message[] oldmv = mv;
mv = new Message[oldmv.length * 2];
// copy start->length to the start of the new vector
System.arraycopy(oldmv, start, mv, 0, oldmv.length - start);
// copy 0->end to the next part of the new vector
if (end != (oldmv.length - 1)) {
System.arraycopy(oldmv, 0, mv, oldmv.length - start, end + 1);
}
// reposition pointers
start = 0;
end = oldmv.length;
}
// create a new vector with just the valid keys in and return it
public Message[] getKeys() {
if (start == end) return new Message[0];
Message[] lv;
if (start < end) {
int size = end - start;
lv = new Message[size];
System.arraycopy(mv, start, lv, 0, size);
} else {
int size = mv.length - start + end;
lv = new Message[size];
System.arraycopy(mv, start, lv, 0, mv.length - start);
System.arraycopy(mv, 0, lv, mv.length - start, end);
}
return lv;
}
private void shrink() {
if (Debug.debug) Debug.print(Debug.DEBUG, "Shrinking");
if (null != mv && mv.length == init_size) return;
// reset to original size
mv = new Message[init_size];
start = 0;
end = 0;
}
public void add(Message m) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Enqueueing Message " + m);
// put this at the end
mv[end] = m;
// move the end
if (end == (mv.length - 1)) end = 0;
else end++;
// if we are out of space, grow.
if (end == start) grow();
}
public Message remove() {
if (start == end) return null;
// find the item
int pos = start;
// get the value
Message m = mv[pos];
// set it as unused
mv[pos] = null;
if (start == (mv.length - 1)) start = 0;
else start++;
if (Debug.debug) Debug.print(Debug.DEBUG, "Dequeueing " + m);
return m;
}
public boolean isEmpty() {
// check if find succeeds
return start == end;
}
public int size() {
if (end >= start)
return end - start;
else
return mv.length - start + end;
}
}

View file

@ -0,0 +1,144 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import org.freedesktop.dbus.exceptions.MessageFormatException;
import org.freedesktop.dbus.exceptions.NotConnected;
import java.lang.reflect.Constructor;
import java.util.Vector;
import static org.freedesktop.dbus.Gettext.getString;
/**
* Error messages which can be sent over the bus.
*/
public class Error extends Message {
Error() {
}
public Error(String dest, String errorName, long replyserial, String sig, Object... args) throws DBusException {
this(null, dest, errorName, replyserial, sig, args);
}
public Error(String source, String dest, String errorName, long replyserial, String sig, Object... args) throws DBusException {
super(Message.Endian.BIG, Message.MessageType.ERROR, (byte) 0);
if (null == errorName)
throw new MessageFormatException(getString("missingErrorName"));
headers.put(Message.HeaderField.REPLY_SERIAL, replyserial);
headers.put(Message.HeaderField.ERROR_NAME, errorName);
Vector<Object> hargs = new Vector<Object>();
hargs.add(new Object[]{Message.HeaderField.ERROR_NAME, new Object[]{ArgumentType.STRING_STRING, errorName}});
hargs.add(new Object[]{Message.HeaderField.REPLY_SERIAL, new Object[]{ArgumentType.UINT32_STRING, replyserial}});
if (null != source) {
headers.put(Message.HeaderField.SENDER, source);
hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
}
if (null != dest) {
headers.put(Message.HeaderField.DESTINATION, dest);
hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
}
if (null != sig) {
hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
headers.put(Message.HeaderField.SIGNATURE, sig);
setArgs(args);
}
byte[] blen = new byte[4];
appendBytes(blen);
append("ua(yv)", serial, hargs.toArray());
pad((byte) 8);
long c = bytecounter;
if (null != sig) append(sig, args);
marshallint(bytecounter - c, blen, 0, 4);
}
public Error(String source, Message m, Throwable e) throws DBusException {
this(source, m.getSource(), AbstractConnection.dollar_pattern.matcher(e.getClass().getName()).replaceAll("."), m.getSerial(), "s", e.getMessage());
}
public Error(Message m, Throwable e) throws DBusException {
this(m.getSource(), AbstractConnection.dollar_pattern.matcher(e.getClass().getName()).replaceAll("."), m.getSerial(), "s", e.getMessage());
}
@SuppressWarnings("unchecked")
private static Class<? extends DBusExecutionException> createExceptionClass(String name) {
if (name == "org.freedesktop.DBus.Local.disconnected") return NotConnected.class;
Class<? extends DBusExecutionException> c = null;
do {
try {
c = (Class<? extends org.freedesktop.dbus.exceptions.DBusExecutionException>) Class.forName(name);
} catch (ClassNotFoundException CNFe) {
}
name = name.replaceAll("\\.([^\\.]*)$", "\\$$1");
} while (null == c && name.matches(".*\\..*"));
return c;
}
/**
* Turns this into an exception of the correct type
*/
public DBusExecutionException getException() {
try {
Class<? extends DBusExecutionException> c = createExceptionClass(getName());
if (null == c || !DBusExecutionException.class.isAssignableFrom(c)) c = DBusExecutionException.class;
Constructor<? extends DBusExecutionException> con = c.getConstructor(String.class);
DBusExecutionException ex;
Object[] args = getParameters();
if (null == args || 0 == args.length)
ex = con.newInstance("");
else {
String s = "";
for (Object o : args)
s += o + " ";
ex = con.newInstance(s.trim());
}
ex.setType(getName());
return ex;
} catch (Exception e) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug && null != e.getCause())
Debug.print(Debug.ERR, e.getCause());
DBusExecutionException ex;
Object[] args = null;
try {
args = getParameters();
} catch (Exception ee) {
}
if (null == args || 0 == args.length)
ex = new DBusExecutionException("");
else {
String s = "";
for (Object o : args)
s += o + " ";
ex = new DBusExecutionException(s.trim());
}
ex.setType(getName());
return ex;
}
}
/**
* Throw this as an exception of the correct type
*/
public void throwException() throws DBusExecutionException {
throw getException();
}
}

View file

@ -0,0 +1,165 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import java.lang.annotation.Annotation;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import static org.freedesktop.dbus.Gettext.getString;
class ExportedObject {
@SuppressWarnings("unchecked")
private String getAnnotations(AnnotatedElement c) {
String ans = "";
for (Annotation a : c.getDeclaredAnnotations()) {
Class t = a.annotationType();
String value = "";
try {
Method m = t.getMethod("value");
value = m.invoke(a).toString();
} catch (NoSuchMethodException NSMe) {
} catch (InvocationTargetException ITe) {
} catch (IllegalAccessException IAe) {
}
ans += " <annotation name=\"" + AbstractConnection.dollar_pattern.matcher(t.getName()).replaceAll(".") + "\" value=\"" + value + "\" />\n";
}
return ans;
}
@SuppressWarnings("unchecked")
private Map<MethodTuple, Method> getExportedMethods(Class c) throws DBusException {
if (DBusInterface.class.equals(c)) return new HashMap<MethodTuple, Method>();
Map<MethodTuple, Method> m = new HashMap<MethodTuple, Method>();
for (Class i : c.getInterfaces())
if (DBusInterface.class.equals(i)) {
// add this class's public methods
if (null != c.getAnnotation(DBusInterfaceName.class)) {
String name = ((DBusInterfaceName) c.getAnnotation(DBusInterfaceName.class)).value();
introspectiondata += " <interface name=\"" + name + "\">\n";
DBusSignal.addInterfaceMap(c.getName(), name);
} else {
// don't let people export things which don't have a
// valid D-Bus interface name
if (c.getName().equals(c.getSimpleName()))
throw new DBusException(getString("interfaceNotAllowedOutsidePackage"));
if (c.getName().length() > DBusConnection.MAX_NAME_LENGTH)
throw new DBusException(getString("introspectInterfaceExceedCharacters") + c.getName());
else
introspectiondata += " <interface name=\"" + AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".") + "\">\n";
}
introspectiondata += getAnnotations(c);
for (Method meth : c.getDeclaredMethods())
if (Modifier.isPublic(meth.getModifiers())) {
String ms = "";
String name;
if (meth.isAnnotationPresent(DBusMemberName.class))
name = meth.getAnnotation(DBusMemberName.class).value();
else
name = meth.getName();
if (name.length() > DBusConnection.MAX_NAME_LENGTH)
throw new DBusException(getString("introspectMethodExceedCharacters") + name);
introspectiondata += " <method name=\"" + name + "\" >\n";
introspectiondata += getAnnotations(meth);
for (Class ex : meth.getExceptionTypes())
if (DBusExecutionException.class.isAssignableFrom(ex))
introspectiondata +=
" <annotation name=\"org.freedesktop.DBus.Method.Error\" value=\"" + AbstractConnection.dollar_pattern.matcher(ex.getName()).replaceAll(".") + "\" />\n";
for (Type pt : meth.getGenericParameterTypes())
for (String s : Marshalling.getDBusType(pt)) {
introspectiondata += " <arg type=\"" + s + "\" direction=\"in\"/>\n";
ms += s;
}
if (!Void.TYPE.equals(meth.getGenericReturnType())) {
if (Tuple.class.isAssignableFrom((Class) meth.getReturnType())) {
ParameterizedType tc = (ParameterizedType) meth.getGenericReturnType();
Type[] ts = tc.getActualTypeArguments();
for (Type t : ts)
if (t != null)
for (String s : Marshalling.getDBusType(t))
introspectiondata += " <arg type=\"" + s + "\" direction=\"out\"/>\n";
} else if (Object[].class.equals(meth.getGenericReturnType())) {
throw new DBusException(getString("cannotIntrospectReturnType"));
} else
for (String s : Marshalling.getDBusType(meth.getGenericReturnType()))
introspectiondata += " <arg type=\"" + s + "\" direction=\"out\"/>\n";
}
introspectiondata += " </method>\n";
m.put(new MethodTuple(name, ms), meth);
}
for (Class sig : c.getDeclaredClasses())
if (DBusSignal.class.isAssignableFrom(sig)) {
String name;
if (sig.isAnnotationPresent(DBusMemberName.class)) {
name = ((DBusMemberName) sig.getAnnotation(DBusMemberName.class)).value();
DBusSignal.addSignalMap(sig.getSimpleName(), name);
} else
name = sig.getSimpleName();
if (name.length() > DBusConnection.MAX_NAME_LENGTH)
throw new DBusException(getString("introspectSignalExceedCharacters") + name);
introspectiondata += " <signal name=\"" + name + "\">\n";
Constructor con = sig.getConstructors()[0];
Type[] ts = con.getGenericParameterTypes();
for (int j = 1; j < ts.length; j++)
for (String s : Marshalling.getDBusType(ts[j]))
introspectiondata += " <arg type=\"" + s + "\" direction=\"out\" />\n";
introspectiondata += getAnnotations(sig);
introspectiondata += " </signal>\n";
}
introspectiondata += " </interface>\n";
} else {
// recurse
m.putAll(getExportedMethods(i));
}
return m;
}
Map<MethodTuple, Method> methods;
Reference<DBusInterface> object;
String introspectiondata;
public ExportedObject(DBusInterface object, boolean weakreferences) throws DBusException {
if (weakreferences)
this.object = new WeakReference<DBusInterface>(object);
else
this.object = new StrongReference<DBusInterface>(object);
introspectiondata = "";
methods = getExportedMethods(object.getClass());
introspectiondata +=
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n" +
" <method name=\"Introspect\">\n" +
" <arg type=\"s\" direction=\"out\"/>\n" +
" </method>\n" +
" </interface>\n";
introspectiondata +=
" <interface name=\"org.freedesktop.DBus.Peer\">\n" +
" <method name=\"Ping\">\n" +
" </method>\n" +
" </interface>\n";
}
}

View file

@ -0,0 +1,30 @@
/*
* Pescetti Pseudo-Duplimate Generator
*
* Copyright (C) 2007 Matthew Johnson
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License Version 2 as published by
* the Free Software Foundation. This program is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should have received a
* copy of the GNU Lesser General Public License along with this program; if not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* To Contact me, please email src@matthew.ath.cx
*
*/
package org.freedesktop.dbus;
import java.util.ResourceBundle;
public class Gettext {
private static ResourceBundle myResources =
ResourceBundle.getBundle("en_US");
public static String getString(String s) {
return myResources.getString(s);
}
}

View file

@ -0,0 +1,20 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import org.freedesktop.dbus.exceptions.DBusException;
class InternalSignal extends DBusSignal {
public InternalSignal(String source, String objectpath, String name, String iface, String sig, long serial, Object... parameters) throws DBusException {
super(objectpath, iface, name, sig, parameters);
this.serial = serial;
}
}

View file

@ -0,0 +1,629 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.types.DBusListType;
import org.freedesktop.dbus.types.DBusMapType;
import org.freedesktop.dbus.types.DBusStructType;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import static org.freedesktop.dbus.Gettext.getString;
/**
* Contains static methods for marshalling values.
*/
public class Marshalling {
private static Map<Type, String[]> typeCache = new HashMap<Type, String[]>();
/**
* Will return the DBus type corresponding to the given Java type.
* Note, container type should have their ParameterizedType not their
* Class passed in here.
*
* @param c The Java types.
* @return The DBus types.
* @throws DBusException If the given type cannot be converted to a DBus type.
*/
public static String getDBusType(Type[] c) throws DBusException {
StringBuffer sb = new StringBuffer();
for (Type t : c)
for (String s : getDBusType(t))
sb.append(s);
return sb.toString();
}
/**
* Will return the DBus type corresponding to the given Java type.
* Note, container type should have their ParameterizedType not their
* Class passed in here.
*
* @param c The Java type.
* @return The DBus type.
* @throws DBusException If the given type cannot be converted to a DBus type.
*/
public static String[] getDBusType(Type c) throws DBusException {
String[] cached = typeCache.get(c);
if (null != cached) return cached;
cached = getDBusType(c, false);
typeCache.put(c, cached);
return cached;
}
/**
* Will return the DBus type corresponding to the given Java type.
* Note, container type should have their ParameterizedType not their
* Class passed in here.
*
* @param c The Java type.
* @param basic If true enforces this to be a non-compound type. (compound types are Maps, Structs and Lists/arrays).
* @return The DBus type.
* @throws DBusException If the given type cannot be converted to a DBus type.
*/
public static String[] getDBusType(Type c, boolean basic) throws DBusException {
return recursiveGetDBusType(c, basic, 0);
}
private static StringBuffer[] out = new StringBuffer[10];
@SuppressWarnings("unchecked")
public static String[] recursiveGetDBusType(Type c, boolean basic, int level) throws DBusException {
if (out.length <= level) {
StringBuffer[] newout = new StringBuffer[out.length];
System.arraycopy(out, 0, newout, 0, out.length);
out = newout;
}
if (null == out[level]) out[level] = new StringBuffer();
else out[level].delete(0, out[level].length());
if (basic && !(c instanceof Class))
throw new DBusException(c + getString("notBasicType"));
if (c instanceof TypeVariable) out[level].append((char) Message.ArgumentType.VARIANT);
else if (c instanceof GenericArrayType) {
out[level].append((char) Message.ArgumentType.ARRAY);
String[] s = recursiveGetDBusType(((GenericArrayType) c).getGenericComponentType(), false, level + 1);
if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
out[level].append(s[0]);
} else if ((c instanceof Class &&
DBusSerializable.class.isAssignableFrom((Class<? extends Object>) c)) ||
(c instanceof ParameterizedType &&
DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) c).getRawType()))) {
// it's a custom serializable type
Type[] newtypes = null;
if (c instanceof Class) {
for (Method m : ((Class<? extends Object>) c).getDeclaredMethods())
if (m.getName().equals("deserialize"))
newtypes = m.getGenericParameterTypes();
} else
for (Method m : ((Class<? extends Object>) ((ParameterizedType) c).getRawType()).getDeclaredMethods())
if (m.getName().equals("deserialize"))
newtypes = m.getGenericParameterTypes();
if (null == newtypes) throw new DBusException(getString("mustImplementDeserializeMethod"));
String[] sigs = new String[newtypes.length];
for (int j = 0; j < sigs.length; j++) {
String[] ss = recursiveGetDBusType(newtypes[j], false, level + 1);
if (1 != ss.length) throw new DBusException(getString("mustSerializeNativeDBusTypes"));
sigs[j] = ss[0];
}
return sigs;
} else if (c instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) c;
if (p.getRawType().equals(Map.class)) {
out[level].append("a{");
Type[] t = p.getActualTypeArguments();
try {
String[] s = recursiveGetDBusType(t[0], true, level + 1);
if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
out[level].append(s[0]);
s = recursiveGetDBusType(t[1], false, level + 1);
if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
out[level].append(s[0]);
} catch (ArrayIndexOutOfBoundsException AIOOBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
throw new DBusException(getString("mapParameters"));
}
out[level].append('}');
} else if (List.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
for (Type t : p.getActualTypeArguments()) {
if (Type.class.equals(t))
out[level].append((char) Message.ArgumentType.SIGNATURE);
else {
String[] s = recursiveGetDBusType(t, false, level + 1);
if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
out[level].append((char) Message.ArgumentType.ARRAY);
out[level].append(s[0]);
}
}
} else if (p.getRawType().equals(Variant.class)) {
out[level].append((char) Message.ArgumentType.VARIANT);
} else if (DBusInterface.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
out[level].append((char) Message.ArgumentType.OBJECT_PATH);
} else if (Tuple.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
Type[] ts = p.getActualTypeArguments();
Vector<String> vs = new Vector<String>();
for (Type t : ts)
for (String s : recursiveGetDBusType(t, false, level + 1))
vs.add(s);
return vs.toArray(new String[0]);
} else
throw new DBusException(getString("nonExportableParameterizedType") + c);
} else if (c.equals(Byte.class)) out[level].append((char) Message.ArgumentType.BYTE);
else if (c.equals(Byte.TYPE)) out[level].append((char) Message.ArgumentType.BYTE);
else if (c.equals(Boolean.class)) out[level].append((char) Message.ArgumentType.BOOLEAN);
else if (c.equals(Boolean.TYPE)) out[level].append((char) Message.ArgumentType.BOOLEAN);
else if (c.equals(Short.class)) out[level].append((char) Message.ArgumentType.INT16);
else if (c.equals(Short.TYPE)) out[level].append((char) Message.ArgumentType.INT16);
else if (c.equals(UInt16.class)) out[level].append((char) Message.ArgumentType.UINT16);
else if (c.equals(Integer.class)) out[level].append((char) Message.ArgumentType.INT32);
else if (c.equals(Integer.TYPE)) out[level].append((char) Message.ArgumentType.INT32);
else if (c.equals(UInt32.class)) out[level].append((char) Message.ArgumentType.UINT32);
else if (c.equals(Long.class)) out[level].append((char) Message.ArgumentType.INT64);
else if (c.equals(Long.TYPE)) out[level].append((char) Message.ArgumentType.INT64);
else if (c.equals(UInt64.class)) out[level].append((char) Message.ArgumentType.UINT64);
else if (c.equals(Double.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
else if (c.equals(Double.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
else if (c.equals(Float.class) && AbstractConnection.FLOAT_SUPPORT)
out[level].append((char) Message.ArgumentType.FLOAT);
else if (c.equals(Float.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
else if (c.equals(Float.TYPE) && AbstractConnection.FLOAT_SUPPORT)
out[level].append((char) Message.ArgumentType.FLOAT);
else if (c.equals(Float.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
else if (c.equals(String.class)) out[level].append((char) Message.ArgumentType.STRING);
else if (c.equals(Variant.class)) out[level].append((char) Message.ArgumentType.VARIANT);
else if (c instanceof Class &&
DBusInterface.class.isAssignableFrom((Class<? extends Object>) c))
out[level].append((char) Message.ArgumentType.OBJECT_PATH);
else if (c instanceof Class &&
Path.class.equals((Class<? extends Object>) c))
out[level].append((char) Message.ArgumentType.OBJECT_PATH);
else if (c instanceof Class &&
ObjectPath.class.equals((Class<? extends Object>) c))
out[level].append((char) Message.ArgumentType.OBJECT_PATH);
else if (c instanceof Class &&
((Class<? extends Object>) c).isArray()) {
if (Type.class.equals(((Class<? extends Object>) c).getComponentType()))
out[level].append((char) Message.ArgumentType.SIGNATURE);
else {
out[level].append((char) Message.ArgumentType.ARRAY);
String[] s = recursiveGetDBusType(((Class<? extends Object>) c).getComponentType(), false, level + 1);
if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
out[level].append(s[0]);
}
} else if (c instanceof Class &&
Struct.class.isAssignableFrom((Class<? extends Object>) c)) {
out[level].append((char) Message.ArgumentType.STRUCT1);
Type[] ts = Container.getTypeCache(c);
if (null == ts) {
Field[] fs = ((Class<? extends Object>) c).getDeclaredFields();
ts = new Type[fs.length];
for (Field f : fs) {
Position p = f.getAnnotation(Position.class);
if (null == p) continue;
ts[p.value()] = f.getGenericType();
}
Container.putTypeCache(c, ts);
}
for (Type t : ts)
if (t != null)
for (String s : recursiveGetDBusType(t, false, level + 1))
out[level].append(s);
out[level].append(')');
} else {
throw new DBusException(getString("nonExportableType") + c);
}
if (Debug.debug) Debug.print(Debug.VERBOSE, "Converted Java type: " + c + " to D-Bus Type: " + out[level]);
return new String[]{out[level].toString()};
}
/**
* Converts a dbus type string into Java Type objects,
*
* @param dbus The DBus type or types.
* @param rv Vector to return the types in.
* @param limit Maximum number of types to parse (-1 == nolimit).
* @return number of characters parsed from the type string.
*/
public static int getJavaType(String dbus, List<Type> rv, int limit) throws DBusException {
if (null == dbus || "".equals(dbus) || 0 == limit) return 0;
try {
int i = 0;
for (; i < dbus.length() && (-1 == limit || limit > rv.size()); i++)
switch (dbus.charAt(i)) {
case Message.ArgumentType.STRUCT1:
int j = i + 1;
for (int c = 1; c > 0; j++) {
if (')' == dbus.charAt(j)) c--;
else if (Message.ArgumentType.STRUCT1 == dbus.charAt(j)) c++;
}
Vector<Type> contained = new Vector<Type>();
int c = getJavaType(dbus.substring(i + 1, j - 1), contained, -1);
rv.add(new DBusStructType(contained.toArray(new Type[0])));
i = j;
break;
case Message.ArgumentType.ARRAY:
if (Message.ArgumentType.DICT_ENTRY1 == dbus.charAt(i + 1)) {
contained = new Vector<Type>();
c = getJavaType(dbus.substring(i + 2), contained, 2);
rv.add(new DBusMapType(contained.get(0), contained.get(1)));
i += (c + 2);
} else {
contained = new Vector<Type>();
c = getJavaType(dbus.substring(i + 1), contained, 1);
rv.add(new DBusListType(contained.get(0)));
i += c;
}
break;
case Message.ArgumentType.VARIANT:
rv.add(Variant.class);
break;
case Message.ArgumentType.BOOLEAN:
rv.add(Boolean.class);
break;
case Message.ArgumentType.INT16:
rv.add(Short.class);
break;
case Message.ArgumentType.BYTE:
rv.add(Byte.class);
break;
case Message.ArgumentType.OBJECT_PATH:
rv.add(DBusInterface.class);
break;
case Message.ArgumentType.UINT16:
rv.add(UInt16.class);
break;
case Message.ArgumentType.INT32:
rv.add(Integer.class);
break;
case Message.ArgumentType.UINT32:
rv.add(UInt32.class);
break;
case Message.ArgumentType.INT64:
rv.add(Long.class);
break;
case Message.ArgumentType.UINT64:
rv.add(UInt64.class);
break;
case Message.ArgumentType.DOUBLE:
rv.add(Double.class);
break;
case Message.ArgumentType.FLOAT:
rv.add(Float.class);
break;
case Message.ArgumentType.STRING:
rv.add(String.class);
break;
case Message.ArgumentType.SIGNATURE:
rv.add(Type[].class);
break;
case Message.ArgumentType.DICT_ENTRY1:
rv.add(Map.Entry.class);
contained = new Vector<Type>();
c = getJavaType(dbus.substring(i + 1), contained, 2);
i += c + 1;
break;
default:
throw new DBusException(MessageFormat.format(getString("parseDBusSignatureFailure"), new Object[]{dbus, dbus.charAt(i)}));
}
return i;
} catch (IndexOutOfBoundsException IOOBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOOBe);
throw new DBusException(getString("parseDBusTypeSignatureFailure") + dbus);
}
}
/**
* Recursively converts types for serialization onto DBus.
*
* @param parameters The parameters to convert.
* @param types The (possibly generic) types of the parameters.
* @return The converted parameters.
* @throws DBusException Thrown if there is an error in converting the objects.
*/
@SuppressWarnings("unchecked")
public static Object[] convertParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws DBusException {
if (null == parameters) return null;
for (int i = 0; i < parameters.length; i++) {
if (Debug.debug)
Debug.print(Debug.VERBOSE, "Converting " + i + " from " + parameters[i] + " to " + types[i]);
if (null == parameters[i]) continue;
if (parameters[i] instanceof DBusSerializable) {
for (Method m : parameters[i].getClass().getDeclaredMethods())
if (m.getName().equals("deserialize")) {
Type[] newtypes = m.getParameterTypes();
Type[] expand = new Type[types.length + newtypes.length - 1];
System.arraycopy(types, 0, expand, 0, i);
System.arraycopy(newtypes, 0, expand, i, newtypes.length);
System.arraycopy(types, i + 1, expand, i + newtypes.length, types.length - i - 1);
types = expand;
Object[] newparams = ((DBusSerializable) parameters[i]).serialize();
Object[] exparams = new Object[parameters.length + newparams.length - 1];
System.arraycopy(parameters, 0, exparams, 0, i);
System.arraycopy(newparams, 0, exparams, i, newparams.length);
System.arraycopy(parameters, i + 1, exparams, i + newparams.length, parameters.length - i - 1);
parameters = exparams;
}
i--;
} else if (parameters[i] instanceof Tuple) {
Type[] newtypes = ((ParameterizedType) types[i]).getActualTypeArguments();
Type[] expand = new Type[types.length + newtypes.length - 1];
System.arraycopy(types, 0, expand, 0, i);
System.arraycopy(newtypes, 0, expand, i, newtypes.length);
System.arraycopy(types, i + 1, expand, i + newtypes.length, types.length - i - 1);
types = expand;
Object[] newparams = ((Tuple) parameters[i]).getParameters();
Object[] exparams = new Object[parameters.length + newparams.length - 1];
System.arraycopy(parameters, 0, exparams, 0, i);
System.arraycopy(newparams, 0, exparams, i, newparams.length);
System.arraycopy(parameters, i + 1, exparams, i + newparams.length, parameters.length - i - 1);
parameters = exparams;
if (Debug.debug)
Debug.print(Debug.VERBOSE, "New params: " + Arrays.deepToString(parameters) + " new types: " + Arrays.deepToString(types));
i--;
} else if (types[i] instanceof TypeVariable &&
!(parameters[i] instanceof Variant))
// its an unwrapped variant, wrap it
parameters[i] = new Variant<Object>(parameters[i]);
else if (parameters[i] instanceof DBusInterface)
parameters[i] = conn.getExportedObject((DBusInterface) parameters[i]);
}
return parameters;
}
@SuppressWarnings("unchecked")
static Object deSerializeParameter(Object parameter, Type type, AbstractConnection conn) throws Exception {
if (Debug.debug)
Debug.print(Debug.VERBOSE, "Deserializing from " + parameter.getClass() + " to " + type.getClass());
if (null == parameter)
return null;
// its a wrapped variant, unwrap it
if (type instanceof TypeVariable
&& parameter instanceof Variant) {
parameter = ((Variant) parameter).getValue();
}
// Turn a signature into a Type[]
if (type instanceof Class
&& ((Class) type).isArray()
&& ((Class) type).getComponentType().equals(Type.class)
&& parameter instanceof String) {
Vector<Type> rv = new Vector<Type>();
getJavaType((String) parameter, rv, -1);
parameter = rv.toArray(new Type[0]);
}
// its an object path, get/create the proxy
if (parameter instanceof ObjectPath) {
if (type instanceof Class && DBusInterface.class.isAssignableFrom((Class) type))
parameter = conn.getExportedObject(
((ObjectPath) parameter).source,
((ObjectPath) parameter).path);
else
parameter = new Path(((ObjectPath) parameter).path);
}
// it should be a struct. create it
if (parameter instanceof Object[] &&
type instanceof Class &&
Struct.class.isAssignableFrom((Class) type)) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Creating Struct " + type + " from " + parameter);
Type[] ts = Container.getTypeCache(type);
if (null == ts) {
Field[] fs = ((Class) type).getDeclaredFields();
ts = new Type[fs.length];
for (Field f : fs) {
Position p = f.getAnnotation(Position.class);
if (null == p) continue;
ts[p.value()] = f.getGenericType();
}
Container.putTypeCache(type, ts);
}
// recurse over struct contents
parameter = deSerializeParameters((Object[]) parameter, ts, conn);
for (Constructor con : ((Class) type).getDeclaredConstructors()) {
try {
parameter = con.newInstance((Object[]) parameter);
break;
} catch (IllegalArgumentException IAe) {
}
}
}
// recurse over arrays
if (parameter instanceof Object[]) {
Type[] ts = new Type[((Object[]) parameter).length];
Arrays.fill(ts, parameter.getClass().getComponentType());
parameter = deSerializeParameters((Object[]) parameter,
ts, conn);
}
if (parameter instanceof List) {
Type type2;
if (type instanceof ParameterizedType)
type2 = ((ParameterizedType) type).getActualTypeArguments()[0];
else if (type instanceof GenericArrayType)
type2 = ((GenericArrayType) type).getGenericComponentType();
else if (type instanceof Class && ((Class) type).isArray())
type2 = ((Class) type).getComponentType();
else
type2 = null;
if (null != type2)
parameter = deSerializeParameters((List) parameter, type2, conn);
}
// correct floats if appropriate
if (type.equals(Float.class) || type.equals(Float.TYPE))
if (!(parameter instanceof Float))
parameter = ((Number) parameter).floatValue();
// make sure arrays are in the correct format
if (parameter instanceof Object[] ||
parameter instanceof List ||
parameter.getClass().isArray()) {
if (type instanceof ParameterizedType)
parameter = ArrayFrob.convert(parameter,
(Class<? extends Object>) ((ParameterizedType) type).getRawType());
else if (type instanceof GenericArrayType) {
Type ct = ((GenericArrayType) type).getGenericComponentType();
Class cc = null;
if (ct instanceof Class)
cc = (Class) ct;
if (ct instanceof ParameterizedType)
cc = (Class) ((ParameterizedType) ct).getRawType();
Object o = Array.newInstance(cc, 0);
parameter = ArrayFrob.convert(parameter,
o.getClass());
} else if (type instanceof Class &&
((Class) type).isArray()) {
Class cc = ((Class) type).getComponentType();
if ((cc.equals(Float.class) || cc.equals(Float.TYPE))
&& (parameter instanceof double[])) {
double[] tmp1 = (double[]) parameter;
float[] tmp2 = new float[tmp1.length];
for (int i = 0; i < tmp1.length; i++)
tmp2[i] = (float) tmp1[i];
parameter = tmp2;
}
Object o = Array.newInstance(cc, 0);
parameter = ArrayFrob.convert(parameter,
o.getClass());
}
}
if (parameter instanceof DBusMap) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing a Map");
DBusMap dmap = (DBusMap) parameter;
Type[] maptypes = ((ParameterizedType) type).getActualTypeArguments();
for (int i = 0; i < dmap.entries.length; i++) {
dmap.entries[i][0] = deSerializeParameter(dmap.entries[i][0], maptypes[0], conn);
dmap.entries[i][1] = deSerializeParameter(dmap.entries[i][1], maptypes[1], conn);
}
}
return parameter;
}
static List<Object> deSerializeParameters(List<Object> parameters, Type type, AbstractConnection conn) throws Exception {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing from " + parameters + " to " + type);
if (null == parameters) return null;
for (int i = 0; i < parameters.size(); i++) {
if (null == parameters.get(i)) continue;
/* DO NOT DO THIS! IT'S REALLY NOT SUPPORTED!
* if (type instanceof Class &&
DBusSerializable.class.isAssignableFrom((Class) types[i])) {
for (Method m: ((Class) types[i]).getDeclaredMethods())
if (m.getName().equals("deserialize")) {
Type[] newtypes = m.getGenericParameterTypes();
try {
Object[] sub = new Object[newtypes.length];
System.arraycopy(parameters, i, sub, 0, newtypes.length);
sub = deSerializeParameters(sub, newtypes, conn);
DBusSerializable sz = (DBusSerializable) ((Class) types[i]).newInstance();
m.invoke(sz, sub);
Object[] compress = new Object[parameters.length - newtypes.length + 1];
System.arraycopy(parameters, 0, compress, 0, i);
compress[i] = sz;
System.arraycopy(parameters, i + newtypes.length, compress, i+1, parameters.length - i - newtypes.length);
parameters = compress;
} catch (ArrayIndexOutOfBoundsException AIOOBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
throw new DBusException("Not enough elements to create custom object from serialized data ("+(parameters.size()-i)+" < "+(newtypes.length)+")");
}
}
} else*/
parameters.set(i, deSerializeParameter(parameters.get(i), type, conn));
}
return parameters;
}
@SuppressWarnings("unchecked")
static Object[] deSerializeParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws Exception {
if (Debug.debug)
Debug.print(Debug.VERBOSE, "Deserializing from " + Arrays.deepToString(parameters) + " to " + Arrays.deepToString(types));
if (null == parameters) return null;
if (types.length == 1 && types[0] instanceof ParameterizedType
&& Tuple.class.isAssignableFrom((Class) ((ParameterizedType) types[0]).getRawType())) {
types = ((ParameterizedType) types[0]).getActualTypeArguments();
}
for (int i = 0; i < parameters.length; i++) {
// CHECK IF ARRAYS HAVE THE SAME LENGTH <-- has to happen after expanding parameters
if (i >= types.length) {
if (Debug.debug) {
for (int j = 0; j < parameters.length; j++) {
Debug.print(Debug.ERR, String.format("Error, Parameters difference (%1d, '%2s')", j, parameters[j].toString()));
}
}
throw new DBusException(getString("errorDeserializingMessage"));
}
if (null == parameters[i]) continue;
if ((types[i] instanceof Class &&
DBusSerializable.class.isAssignableFrom((Class<? extends Object>) types[i])) ||
(types[i] instanceof ParameterizedType &&
DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) types[i]).getRawType()))) {
Class<? extends DBusSerializable> dsc;
if (types[i] instanceof Class)
dsc = (Class<? extends DBusSerializable>) types[i];
else
dsc = (Class<? extends DBusSerializable>) ((ParameterizedType) types[i]).getRawType();
for (Method m : dsc.getDeclaredMethods())
if (m.getName().equals("deserialize")) {
Type[] newtypes = m.getGenericParameterTypes();
try {
Object[] sub = new Object[newtypes.length];
System.arraycopy(parameters, i, sub, 0, newtypes.length);
sub = deSerializeParameters(sub, newtypes, conn);
DBusSerializable sz = dsc.newInstance();
m.invoke(sz, sub);
Object[] compress = new Object[parameters.length - newtypes.length + 1];
System.arraycopy(parameters, 0, compress, 0, i);
compress[i] = sz;
System.arraycopy(parameters, i + newtypes.length, compress, i + 1, parameters.length - i - newtypes.length);
parameters = compress;
} catch (ArrayIndexOutOfBoundsException AIOOBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
throw new DBusException(MessageFormat.format(getString("notEnoughElementsToCreateCustomObject"),
new Object[]{parameters.length - i, newtypes.length}));
}
}
} else
parameters[i] = deSerializeParameter(parameters[i], types[i], conn);
}
return parameters;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,194 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import cx.ath.matthew.utils.Hexdump;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.MessageProtocolVersionException;
import org.freedesktop.dbus.exceptions.MessageTypeException;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.text.MessageFormat;
import static org.freedesktop.dbus.Gettext.getString;
public class MessageReader {
private InputStream in;
private byte[] buf = null;
private byte[] tbuf = null;
private byte[] header = null;
private byte[] body = null;
private int[] len = new int[4];
public MessageReader(InputStream in) {
this.in = new BufferedInputStream(in);
}
public Message readMessage() throws IOException, DBusException {
int rv;
/* Read the 12 byte fixed header, retrying as neccessary */
if (null == buf) {
buf = new byte[12];
len[0] = 0;
}
if (len[0] < 12) {
try {
rv = in.read(buf, len[0], 12 - len[0]);
} catch (SocketTimeoutException STe) {
return null;
}
if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
len[0] += rv;
}
if (len[0] == 0) return null;
if (len[0] < 12) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[0] + " of 12 bytes of header");
return null;
}
/* Parse the details from the header */
byte endian = buf[0];
byte type = buf[1];
byte protover = buf[3];
if (protover > Message.PROTOCOL) {
buf = null;
throw new MessageProtocolVersionException(MessageFormat.format(getString("protocolVersionUnsupported"), new Object[]{protover}));
}
/* Read the length of the variable header */
if (null == tbuf) {
tbuf = new byte[4];
len[1] = 0;
}
if (len[1] < 4) {
try {
rv = in.read(tbuf, len[1], 4 - len[1]);
} catch (SocketTimeoutException STe) {
return null;
}
if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
len[1] += rv;
}
if (len[1] < 4) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[1] + " of 4 bytes of header");
return null;
}
/* Parse the variable header length */
int headerlen = 0;
if (null == header) {
headerlen = (int) Message.demarshallint(tbuf, 0, endian, 4);
if (0 != headerlen % 8)
headerlen += 8 - (headerlen % 8);
} else
headerlen = header.length - 8;
/* Read the variable header */
if (null == header) {
header = new byte[headerlen + 8];
System.arraycopy(tbuf, 0, header, 0, 4);
len[2] = 0;
}
if (len[2] < headerlen) {
try {
rv = in.read(header, 8 + len[2], headerlen - len[2]);
} catch (SocketTimeoutException STe) {
return null;
}
if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
len[2] += rv;
}
if (len[2] < headerlen) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[2] + " of " + headerlen + " bytes of header");
return null;
}
/* Read the body */
int bodylen = 0;
if (null == body) bodylen = (int) Message.demarshallint(buf, 4, endian, 4);
if (null == body) {
body = new byte[bodylen];
len[3] = 0;
}
if (len[3] < body.length) {
try {
rv = in.read(body, len[3], body.length - len[3]);
} catch (SocketTimeoutException STe) {
return null;
}
if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
len[3] += rv;
}
if (len[3] < body.length) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[3] + " of " + body.length + " bytes of body");
return null;
}
Message m;
switch (type) {
case Message.MessageType.METHOD_CALL:
m = new MethodCall();
break;
case Message.MessageType.METHOD_RETURN:
m = new MethodReturn();
break;
case Message.MessageType.SIGNAL:
m = new DBusSignal();
break;
case Message.MessageType.ERROR:
m = new Error();
break;
default:
throw new MessageTypeException(MessageFormat.format(getString("messageTypeUnsupported"), new Object[]{type}));
}
if (Debug.debug) {
Debug.print(Debug.VERBOSE, Hexdump.format(buf));
Debug.print(Debug.VERBOSE, Hexdump.format(tbuf));
Debug.print(Debug.VERBOSE, Hexdump.format(header));
Debug.print(Debug.VERBOSE, Hexdump.format(body));
}
try {
m.populate(buf, header, body);
} catch (DBusException DBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
buf = null;
tbuf = null;
body = null;
header = null;
throw DBe;
} catch (RuntimeException Re) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, Re);
buf = null;
tbuf = null;
body = null;
header = null;
throw Re;
}
if (Debug.debug) {
Debug.print(Debug.INFO, "=> " + m);
}
buf = null;
tbuf = null;
body = null;
header = null;
return m;
}
public void close() throws IOException {
if (Debug.debug) Debug.print(Debug.INFO, "Closing Message Reader");
in.close();
}
}

View file

@ -0,0 +1,67 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import cx.ath.matthew.unix.USOutputStream;
import cx.ath.matthew.utils.Hexdump;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class MessageWriter {
private OutputStream out;
private boolean isunix;
public MessageWriter(OutputStream out) {
this.out = out;
this.isunix = false;
try {
if (out instanceof USOutputStream)
this.isunix = true;
} catch (Throwable t) {
}
if (!this.isunix)
this.out = new BufferedOutputStream(this.out);
}
public void writeMessage(Message m) throws IOException {
if (Debug.debug) {
Debug.print(Debug.INFO, "<= " + m);
}
if (null == m) return;
if (null == m.getWireData()) {
if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!");
return;
}
if (isunix) {
if (Debug.debug) {
Debug.print(Debug.DEBUG, "Writing all " + m.getWireData().length + " buffers simultaneously to Unix Socket");
for (byte[] buf : m.getWireData())
Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
}
((USOutputStream) out).write(m.getWireData());
} else
for (byte[] buf : m.getWireData()) {
if (Debug.debug)
Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
if (null == buf) break;
out.write(buf);
}
out.flush();
}
public void close() throws IOException {
if (Debug.debug) Debug.print(Debug.INFO, "Closing Message Writer");
out.close();
}
}

View file

@ -0,0 +1,137 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import cx.ath.matthew.utils.Hexdump;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.MessageFormatException;
import java.util.Vector;
import static org.freedesktop.dbus.Gettext.getString;
public class MethodCall extends Message {
MethodCall() {
}
public MethodCall(String dest, String path, String iface, String member, byte flags, String sig, Object... args) throws DBusException {
this(null, dest, path, iface, member, flags, sig, args);
}
public MethodCall(String source, String dest, String path, String iface, String member, byte flags, String sig, Object... args) throws DBusException {
super(Message.Endian.BIG, Message.MessageType.METHOD_CALL, flags);
if (null == member || null == path)
throw new MessageFormatException(getString("missingDestinationPathFunction"));
headers.put(Message.HeaderField.PATH, path);
headers.put(Message.HeaderField.MEMBER, member);
Vector<Object> hargs = new Vector<Object>();
hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, path}});
if (null != source) {
headers.put(Message.HeaderField.SENDER, source);
hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
}
if (null != dest) {
headers.put(Message.HeaderField.DESTINATION, dest);
hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
}
if (null != iface) {
hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
headers.put(Message.HeaderField.INTERFACE, iface);
}
hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
if (null != sig) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Appending arguments with signature: " + sig);
hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
headers.put(Message.HeaderField.SIGNATURE, sig);
setArgs(args);
}
byte[] blen = new byte[4];
appendBytes(blen);
append("ua(yv)", serial, hargs.toArray());
pad((byte) 8);
long c = bytecounter;
if (null != sig) append(sig, args);
if (Debug.debug)
Debug.print(Debug.DEBUG, "Appended body, type: " + sig + " start: " + c + " end: " + bytecounter + " size: " + (bytecounter - c));
marshallint(bytecounter - c, blen, 0, 4);
if (Debug.debug) Debug.print("marshalled size (" + blen + "): " + Hexdump.format(blen));
}
private static long REPLY_WAIT_TIMEOUT = 20000;
/**
* Set the default timeout for method calls.
* Default is 20s.
*
* @param timeout New timeout in ms.
*/
public static void setDefaultTimeout(long timeout) {
REPLY_WAIT_TIMEOUT = timeout;
}
Message reply = null;
public synchronized boolean hasReply() {
return null != reply;
}
/**
* Block (if neccessary) for a reply.
*
* @param timeout The length of time to block before timing out (ms).
* @return The reply to this MethodCall, or null if a timeout happens.
*/
public synchronized Message getReply(long timeout) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking on " + this);
if (null != reply) return reply;
try {
wait(timeout);
return reply;
} catch (InterruptedException Ie) {
return reply;
}
}
/**
* Block (if neccessary) for a reply.
* Default timeout is 20s, or can be configured with setDefaultTimeout()
*
* @return The reply to this MethodCall, or null if a timeout happens.
*/
public synchronized Message getReply() {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking on " + this);
if (null != reply) return reply;
try {
wait(REPLY_WAIT_TIMEOUT);
return reply;
} catch (InterruptedException Ie) {
return reply;
}
}
protected synchronized void setReply(Message reply) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting reply to " + this + " to " + reply);
this.reply = reply;
notifyAll();
}
}

View file

@ -0,0 +1,77 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import org.freedesktop.dbus.exceptions.DBusException;
import java.util.Vector;
public class MethodReturn extends Message {
MethodReturn() {
}
public MethodReturn(String dest, long replyserial, String sig, Object... args) throws DBusException {
this(null, dest, replyserial, sig, args);
}
public MethodReturn(String source, String dest, long replyserial, String sig, Object... args) throws DBusException {
super(Message.Endian.BIG, Message.MessageType.METHOD_RETURN, (byte) 0);
headers.put(Message.HeaderField.REPLY_SERIAL, replyserial);
Vector<Object> hargs = new Vector<Object>();
hargs.add(new Object[]{Message.HeaderField.REPLY_SERIAL, new Object[]{ArgumentType.UINT32_STRING, replyserial}});
if (null != source) {
headers.put(Message.HeaderField.SENDER, source);
hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
}
if (null != dest) {
headers.put(Message.HeaderField.DESTINATION, dest);
hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
}
if (null != sig) {
hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
headers.put(Message.HeaderField.SIGNATURE, sig);
setArgs(args);
}
byte[] blen = new byte[4];
appendBytes(blen);
append("ua(yv)", serial, hargs.toArray());
pad((byte) 8);
long c = bytecounter;
if (null != sig) append(sig, args);
marshallint(bytecounter - c, blen, 0, 4);
}
public MethodReturn(MethodCall mc, String sig, Object... args) throws DBusException {
this(null, mc, sig, args);
}
public MethodReturn(String source, MethodCall mc, String sig, Object... args) throws DBusException {
this(source, mc.getSource(), mc.getSerial(), sig, args);
this.call = mc;
}
MethodCall call;
public MethodCall getCall() {
return call;
}
protected void setCall(MethodCall call) {
this.call = call;
}
}

View file

@ -0,0 +1,37 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
class MethodTuple {
String name;
String sig;
public MethodTuple(String name, String sig) {
this.name = name;
if (null != sig)
this.sig = sig;
else
this.sig = "";
if (Debug.debug) Debug.print(Debug.VERBOSE, "new MethodTuple(" + this.name + ", " + this.sig + ")");
}
public boolean equals(Object o) {
return o.getClass().equals(MethodTuple.class)
&& ((MethodTuple) o).name.equals(this.name)
&& ((MethodTuple) o).sig.equals(this.sig);
}
public int hashCode() {
return name.hashCode() + sig.hashCode();
}
}

View file

@ -0,0 +1,22 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
class ObjectPath extends Path {
public String source;
// public DBusConnection conn;
public ObjectPath(String source, String path/*, DBusConnection conn*/) {
super(path);
this.source = source;
// this.conn = conn;
}
}

View file

@ -0,0 +1,158 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import java.util.regex.Pattern;
/**
* Keeps track of the exported objects for introspection data
*/
class ObjectTree {
class TreeNode {
String name;
ExportedObject object;
String data;
TreeNode right;
TreeNode down;
public TreeNode(String name) {
this.name = name;
}
public TreeNode(String name, ExportedObject object, String data) {
this.name = name;
this.object = object;
this.data = data;
}
}
private TreeNode root;
public ObjectTree() {
root = new TreeNode("");
}
public static final Pattern slashpattern = Pattern.compile("/");
private TreeNode recursiveFind(TreeNode current, String path) {
if ("/".equals(path)) return current;
String[] elements = path.split("/", 2);
// this is us or a parent node
if (path.startsWith(current.name)) {
// this is us
if (path.equals(current.name)) {
return current;
}
// recurse down
else {
if (current.down == null)
return null;
else return recursiveFind(current.down, elements[1]);
}
} else if (current.right == null) {
return null;
} else if (0 > current.right.name.compareTo(elements[0])) {
return null;
}
// recurse right
else {
return recursiveFind(current.right, path);
}
}
private TreeNode recursiveAdd(TreeNode current, String path, ExportedObject object, String data) {
String[] elements = slashpattern.split(path, 2);
// this is us or a parent node
if (path.startsWith(current.name)) {
// this is us
if (1 == elements.length || "".equals(elements[1])) {
current.object = object;
current.data = data;
}
// recurse down
else {
if (current.down == null) {
String[] el = elements[1].split("/", 2);
current.down = new TreeNode(el[0]);
}
current.down = recursiveAdd(current.down, elements[1], object, data);
}
}
// need to create a new sub-tree on the end
else if (current.right == null) {
current.right = new TreeNode(elements[0]);
current.right = recursiveAdd(current.right, path, object, data);
}
// need to insert here
else if (0 > current.right.name.compareTo(elements[0])) {
TreeNode t = new TreeNode(elements[0]);
t.right = current.right;
current.right = t;
current.right = recursiveAdd(current.right, path, object, data);
}
// recurse right
else {
current.right = recursiveAdd(current.right, path, object, data);
}
return current;
}
public void add(String path, ExportedObject object, String data) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Adding " + path + " to object tree");
root = recursiveAdd(root, path, object, data);
}
public void remove(String path) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Removing " + path + " from object tree");
TreeNode t = recursiveFind(root, path);
t.object = null;
t.data = null;
}
public String Introspect(String path) {
TreeNode t = recursiveFind(root, path);
if (null == t) return null;
StringBuilder sb = new StringBuilder();
sb.append("<node name=\"");
sb.append(path);
sb.append("\">\n");
if (null != t.data) sb.append(t.data);
t = t.down;
while (null != t) {
sb.append("<node name=\"");
sb.append(t.name);
sb.append("\"/>\n");
t = t.right;
}
sb.append("</node>");
return sb.toString();
}
private String recursivePrint(TreeNode current) {
String s = "";
if (null != current) {
s += current.name;
if (null != current.object)
s += "*";
if (null != current.down)
s += "/{" + recursivePrint(current.down) + "}";
if (null != current.right)
s += ", " + recursivePrint(current.right);
}
return s;
}
public String toString() {
return recursivePrint(root);
}
}

View file

@ -0,0 +1,39 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
public class Path implements Comparable<Path> {
protected String path;
public Path(String path) {
this.path = path;
}
public String getPath() {
return path;
}
public String toString() {
return path;
}
public boolean equals(Object other) {
return (other instanceof Path) && path.equals(((Path) other).path);
}
public int hashCode() {
return path.hashCode();
}
public int compareTo(Path that) {
return path.compareTo(that.path);
}
}

View file

@ -0,0 +1,29 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Position annotation, to annotate Struct fields
* to be sent over DBus.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Position {
/**
* The order of this field in the Struct.
*/
int value();
}

View file

@ -0,0 +1,187 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import org.freedesktop.DBus;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import org.freedesktop.dbus.exceptions.NotConnected;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.text.MessageFormat;
import java.util.Arrays;
import static org.freedesktop.dbus.Gettext.getString;
class RemoteInvocationHandler implements InvocationHandler {
public static final int CALL_TYPE_SYNC = 0;
public static final int CALL_TYPE_ASYNC = 1;
public static final int CALL_TYPE_CALLBACK = 2;
public static Object convertRV(String sig, Object[] rp, Method m, AbstractConnection conn) throws DBusException {
Class<? extends Object> c = m.getReturnType();
if (null == rp) {
if (null == c || Void.TYPE.equals(c)) return null;
else throw new DBusExecutionException(getString("voidReturnType"));
} else {
try {
if (Debug.debug)
Debug.print(Debug.VERBOSE, "Converting return parameters from " + Arrays.deepToString(rp) + " to type " + m.getGenericReturnType());
rp = Marshalling.deSerializeParameters(rp,
new Type[]{m.getGenericReturnType()}, conn);
} catch (Exception e) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new DBusExecutionException(MessageFormat.format(getString("invalidReturnType"), new Object[]{e.getMessage()}));
}
}
switch (rp.length) {
case 0:
if (null == c || Void.TYPE.equals(c))
return null;
else throw new DBusExecutionException(getString("voidReturnType"));
case 1:
return rp[0];
default:
// check we are meant to return multiple values
if (!Tuple.class.isAssignableFrom(c))
throw new DBusExecutionException(getString("tupleReturnType"));
Constructor<? extends Object> cons = c.getConstructors()[0];
try {
return cons.newInstance(rp);
} catch (Exception e) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new DBusException(e.getMessage());
}
}
}
@SuppressWarnings("unchecked")
public static Object executeRemoteMethod(RemoteObject ro, Method m, AbstractConnection conn, int syncmethod, CallbackHandler callback, Object... args) throws DBusExecutionException {
Type[] ts = m.getGenericParameterTypes();
String sig = null;
if (ts.length > 0) try {
sig = Marshalling.getDBusType(ts);
args = Marshalling.convertParameters(args, ts, conn);
} catch (DBusException DBe) {
throw new DBusExecutionException(getString("contructDBusTypeFailure") + DBe.getMessage());
}
MethodCall call;
byte flags = 0;
if (!ro.autostart) flags |= Message.Flags.NO_AUTO_START;
if (syncmethod == CALL_TYPE_ASYNC) flags |= Message.Flags.ASYNC;
if (m.isAnnotationPresent(DBus.Method.NoReply.class)) flags |= Message.Flags.NO_REPLY_EXPECTED;
try {
String name;
if (m.isAnnotationPresent(DBusMemberName.class))
name = m.getAnnotation(DBusMemberName.class).value();
else
name = m.getName();
if (null == ro.iface)
call = new MethodCall(ro.busname, ro.objectpath, null, name, flags, sig, args);
else {
if (null != ro.iface.getAnnotation(DBusInterfaceName.class)) {
call = new MethodCall(ro.busname, ro.objectpath, ro.iface.getAnnotation(DBusInterfaceName.class).value(), name, flags, sig, args);
} else
call = new MethodCall(ro.busname, ro.objectpath, AbstractConnection.dollar_pattern.matcher(ro.iface.getName()).replaceAll("."), name, flags, sig, args);
}
} catch (DBusException DBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
throw new DBusExecutionException(getString("constructOutgoingMethodCallFailure") + DBe.getMessage());
}
if (null == conn.outgoing) throw new NotConnected(getString("notConnected"));
switch (syncmethod) {
case CALL_TYPE_ASYNC:
conn.queueOutgoing(call);
return new DBusAsyncReply(call, m, conn);
case CALL_TYPE_CALLBACK:
synchronized (conn.pendingCallbacks) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Queueing Callback " + callback + " for " + call);
conn.pendingCallbacks.put(call, callback);
conn.pendingCallbackReplys.put(call, new DBusAsyncReply(call, m, conn));
}
conn.queueOutgoing(call);
return null;
case CALL_TYPE_SYNC:
conn.queueOutgoing(call);
break;
}
// get reply
if (m.isAnnotationPresent(DBus.Method.NoReply.class)) return null;
Message reply = call.getReply();
if (null == reply) throw new DBus.Error.NoReply(getString("notReplyWithSpecifiedTime"));
if (reply instanceof Error)
((Error) reply).throwException();
try {
return convertRV(reply.getSig(), reply.getParameters(), m, conn);
} catch (DBusException e) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
throw new DBusExecutionException(e.getMessage());
}
}
AbstractConnection conn;
RemoteObject remote;
public RemoteInvocationHandler(AbstractConnection conn, RemoteObject remote) {
this.remote = remote;
this.conn = conn;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("isRemote")) return true;
else if (method.getName().equals("clone")) return null;
else if (method.getName().equals("equals")) {
try {
if (1 == args.length)
return new Boolean(remote.equals(((RemoteInvocationHandler) Proxy.getInvocationHandler(args[0])).remote));
} catch (IllegalArgumentException IAe) {
return Boolean.FALSE;
}
} else if (method.getName().equals("finalize")) return null;
else if (method.getName().equals("getClass")) return DBusInterface.class;
else if (method.getName().equals("hashCode")) return remote.hashCode();
else if (method.getName().equals("notify")) {
remote.notify();
return null;
} else if (method.getName().equals("notifyAll")) {
remote.notifyAll();
return null;
} else if (method.getName().equals("wait")) {
if (0 == args.length) remote.wait();
else if (1 == args.length
&& args[0] instanceof Long) remote.wait((Long) args[0]);
else if (2 == args.length
&& args[0] instanceof Long
&& args[1] instanceof Integer)
remote.wait((Long) args[0], (Integer) args[1]);
if (args.length <= 2)
return null;
} else if (method.getName().equals("toString"))
return remote.toString();
return executeRemoteMethod(remote, method, conn, CALL_TYPE_SYNC, null, args);
}
}

View file

@ -0,0 +1,67 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
class RemoteObject {
String busname;
String objectpath;
Class<? extends DBusInterface> iface;
boolean autostart;
public RemoteObject(String busname, String objectpath, Class<? extends DBusInterface> iface, boolean autostart) {
this.busname = busname;
this.objectpath = objectpath;
this.iface = iface;
this.autostart = autostart;
}
public boolean equals(Object o) {
if (!(o instanceof RemoteObject)) return false;
RemoteObject them = (RemoteObject) o;
if (!them.objectpath.equals(this.objectpath)) return false;
if (null == this.busname && null != them.busname) return false;
if (null != this.busname && null == them.busname) return false;
if (null != them.busname && !them.busname.equals(this.busname)) return false;
if (null == this.iface && null != them.iface) return false;
if (null != this.iface && null == them.iface) return false;
if (null != them.iface && !them.iface.equals(this.iface)) return false;
return true;
}
public int hashCode() {
return (null == busname ? 0 : busname.hashCode()) + objectpath.hashCode() +
(null == iface ? 0 : iface.hashCode());
}
public boolean autoStarting() {
return autostart;
}
public String getBusName() {
return busname;
}
public String getObjectPath() {
return objectpath;
}
public Class<? extends DBusInterface> getInterface() {
return iface;
}
public String toString() {
return busname + ":" + objectpath + ":" + iface;
}
}

View file

@ -0,0 +1,51 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
class SignalTuple {
String type;
String name;
String object;
String source;
public SignalTuple(String type, String name, String object, String source) {
this.type = type;
this.name = name;
this.object = object;
this.source = source;
}
public boolean equals(Object o) {
if (!(o instanceof SignalTuple)) return false;
SignalTuple other = (SignalTuple) o;
if (null == this.type && null != other.type) return false;
if (null != this.type && !this.type.equals(other.type)) return false;
if (null == this.name && null != other.name) return false;
if (null != this.name && !this.name.equals(other.name)) return false;
if (null == this.object && null != other.object) return false;
if (null != this.object && !this.object.equals(other.object)) return false;
if (null == this.source && null != other.source) return false;
if (null != this.source && !this.source.equals(other.source)) return false;
return true;
}
public int hashCode() {
return (null == type ? 0 : type.hashCode())
+ (null == name ? 0 : name.hashCode())
+ (null == source ? 0 : source.hashCode())
+ (null == object ? 0 : object.hashCode());
}
public String toString() {
return "SignalTuple(" + type + "," + name + "," + object + "," + source + ")";
}
}

View file

@ -0,0 +1,42 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.lang.ref.WeakReference;
/**
* An alternative to a WeakReference when you don't want
* that behaviour.
*/
public class StrongReference<T> extends WeakReference<T> {
T referant;
public StrongReference(T referant) {
super(referant);
this.referant = referant;
}
public void clear() {
referant = null;
}
public boolean enqueue() {
return false;
}
public T get() {
return referant;
}
public boolean isEnqueued() {
return false;
}
}

View file

@ -0,0 +1,23 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
/**
* This class should be extended to create Structs.
* Any such class may be sent over DBus to a method which takes a Struct.
* All fields in the Struct which you wish to be serialized and sent to the
* remote method should be annotated with the org.freedesktop.dbus.Position
* annotation, in the order they should appear in to Struct to DBus.
*/
public abstract class Struct extends Container {
public Struct() {
}
}

View file

@ -0,0 +1,835 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import cx.ath.matthew.unix.UnixSocket;
import cx.ath.matthew.unix.UnixSocketAddress;
import cx.ath.matthew.utils.Hexdump;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.Collator;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Random;
import java.util.Vector;
import static org.freedesktop.dbus.Gettext.getString;
public class Transport {
public static class SASL {
public static class Command {
private int command;
private int mechs;
private String data;
private String response;
public Command() {
}
public Command(String s) throws IOException {
String[] ss = s.split(" ");
if (Debug.debug) Debug.print(Debug.VERBOSE, "Creating command from: " + Arrays.toString(ss));
if (0 == col.compare(ss[0], "OK")) {
command = COMMAND_OK;
data = ss[1];
} else if (0 == col.compare(ss[0], "AUTH")) {
command = COMMAND_AUTH;
if (ss.length > 1) {
if (0 == col.compare(ss[1], "EXTERNAL"))
mechs = AUTH_EXTERNAL;
else if (0 == col.compare(ss[1], "DBUS_COOKIE_SHA1"))
mechs = AUTH_SHA;
else if (0 == col.compare(ss[1], "ANONYMOUS"))
mechs = AUTH_ANON;
}
if (ss.length > 2)
data = ss[2];
} else if (0 == col.compare(ss[0], "DATA")) {
command = COMMAND_DATA;
data = ss[1];
} else if (0 == col.compare(ss[0], "REJECTED")) {
command = COMMAND_REJECTED;
for (int i = 1; i < ss.length; i++)
if (0 == col.compare(ss[i], "EXTERNAL"))
mechs |= AUTH_EXTERNAL;
else if (0 == col.compare(ss[i], "DBUS_COOKIE_SHA1"))
mechs |= AUTH_SHA;
else if (0 == col.compare(ss[i], "ANONYMOUS"))
mechs |= AUTH_ANON;
} else if (0 == col.compare(ss[0], "BEGIN")) {
command = COMMAND_BEGIN;
} else if (0 == col.compare(ss[0], "CANCEL")) {
command = COMMAND_CANCEL;
} else if (0 == col.compare(ss[0], "ERROR")) {
command = COMMAND_ERROR;
data = ss[1];
} else {
throw new IOException(getString("invalidCommand") + ss[0]);
}
if (Debug.debug) Debug.print(Debug.VERBOSE, "Created command: " + this);
}
public int getCommand() {
return command;
}
public int getMechs() {
return mechs;
}
public String getData() {
return data;
}
public String getResponse() {
return response;
}
public void setResponse(String s) {
response = s;
}
public String toString() {
return "Command(" + command + ", " + mechs + ", " + data + ", " + null + ")";
}
}
private static Collator col = Collator.getInstance();
static {
col.setDecomposition(Collator.FULL_DECOMPOSITION);
col.setStrength(Collator.PRIMARY);
}
public static final int LOCK_TIMEOUT = 1000;
public static final int NEW_KEY_TIMEOUT_SECONDS = 60 * 5;
public static final int EXPIRE_KEYS_TIMEOUT_SECONDS = NEW_KEY_TIMEOUT_SECONDS + (60 * 2);
public static final int MAX_TIME_TRAVEL_SECONDS = 60 * 5;
public static final int COOKIE_TIMEOUT = 240;
public static final String COOKIE_CONTEXT = "org_freedesktop_java";
private String findCookie(String context, String ID) throws IOException {
String homedir = System.getProperty("user.home");
File f = new File(homedir + "/.dbus-keyrings/" + context);
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
String s = null;
String cookie = null;
long now = System.currentTimeMillis() / 1000;
while (null != (s = r.readLine())) {
String[] line = s.split(" ");
long timestamp = Long.parseLong(line[1]);
if (line[0].equals(ID) && (!(timestamp < 0 ||
(now + MAX_TIME_TRAVEL_SECONDS) < timestamp ||
(now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp))) {
cookie = line[2];
break;
}
}
r.close();
return cookie;
}
private void addCookie(String context, String ID, long timestamp, String cookie) throws IOException {
String homedir = System.getProperty("user.home");
File keydir = new File(homedir + "/.dbus-keyrings/");
File cookiefile = new File(homedir + "/.dbus-keyrings/" + context);
File lock = new File(homedir + "/.dbus-keyrings/" + context + ".lock");
File temp = new File(homedir + "/.dbus-keyrings/" + context + ".temp");
// ensure directory exists
if (!keydir.exists()) keydir.mkdirs();
// acquire lock
long start = System.currentTimeMillis();
while (!lock.createNewFile() && LOCK_TIMEOUT > (System.currentTimeMillis() - start)) ;
// read old file
Vector<String> lines = new Vector<String>();
if (cookiefile.exists()) {
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(cookiefile)));
String s = null;
while (null != (s = r.readLine())) {
String[] line = s.split(" ");
long time = Long.parseLong(line[1]);
// expire stale cookies
if ((timestamp - time) < COOKIE_TIMEOUT)
lines.add(s);
}
r.close();
}
// add cookie
lines.add(ID + " " + timestamp + " " + cookie);
// write temp file
PrintWriter w = new PrintWriter(new FileOutputStream(temp));
for (String l : lines)
w.println(l);
w.close();
// atomically move to old file
if (!temp.renameTo(cookiefile)) {
cookiefile.delete();
temp.renameTo(cookiefile);
}
// remove lock
lock.delete();
}
/**
* Takes the string, encodes it as hex and then turns it into a string again.
* No, I don't know why either.
*/
private String stupidlyEncode(String data) {
return Hexdump.toHex(data.getBytes()).replaceAll(" ", "");
}
private String stupidlyEncode(byte[] data) {
return Hexdump.toHex(data).replaceAll(" ", "");
}
private byte getNibble(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return (byte) (c - '0');
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return (byte) (c - 'A' + 10);
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
return (byte) (c - 'a' + 10);
default:
return 0;
}
}
private String stupidlyDecode(String data) {
char[] cs = new char[data.length()];
char[] res = new char[cs.length / 2];
data.getChars(0, data.length(), cs, 0);
for (int i = 0, j = 0; j < res.length; i += 2, j++) {
int b = 0;
b |= getNibble(cs[i]) << 4;
b |= getNibble(cs[i + 1]);
res[j] = (char) b;
}
return new String(res);
}
public static final int MODE_SERVER = 1;
public static final int MODE_CLIENT = 2;
public static final int AUTH_NONE = 0;
public static final int AUTH_EXTERNAL = 1;
public static final int AUTH_SHA = 2;
public static final int AUTH_ANON = 4;
public static final int COMMAND_AUTH = 1;
public static final int COMMAND_DATA = 2;
public static final int COMMAND_REJECTED = 3;
public static final int COMMAND_OK = 4;
public static final int COMMAND_BEGIN = 5;
public static final int COMMAND_CANCEL = 6;
public static final int COMMAND_ERROR = 7;
public static final int INITIAL_STATE = 0;
public static final int WAIT_DATA = 1;
public static final int WAIT_OK = 2;
public static final int WAIT_REJECT = 3;
public static final int WAIT_AUTH = 4;
public static final int WAIT_BEGIN = 5;
public static final int AUTHENTICATED = 6;
public static final int FAILED = 7;
public static final int OK = 1;
public static final int CONTINUE = 2;
public static final int ERROR = 3;
public static final int REJECT = 4;
public Command receive(InputStream s) throws IOException {
StringBuffer sb = new StringBuffer();
top:
while (true) {
int c = s.read();
switch (c) {
case -1:
throw new IOException("Stream unexpectedly short (broken pipe)");
case 0:
case '\r':
continue;
case '\n':
break top;
default:
sb.append((char) c);
}
}
if (Debug.debug) Debug.print(Debug.VERBOSE, "received: " + sb);
try {
return new Command(sb.toString());
} catch (Exception e) {
if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, e);
return new Command();
}
}
public void send(OutputStream out, int command, String... data) throws IOException {
StringBuffer sb = new StringBuffer();
switch (command) {
case COMMAND_AUTH:
sb.append("AUTH");
break;
case COMMAND_DATA:
sb.append("DATA");
break;
case COMMAND_REJECTED:
sb.append("REJECTED");
break;
case COMMAND_OK:
sb.append("OK");
break;
case COMMAND_BEGIN:
sb.append("BEGIN");
break;
case COMMAND_CANCEL:
sb.append("CANCEL");
break;
case COMMAND_ERROR:
sb.append("ERROR");
break;
default:
return;
}
for (String s : data) {
sb.append(' ');
sb.append(s);
}
sb.append('\r');
sb.append('\n');
if (Debug.debug) Debug.print(Debug.VERBOSE, "sending: " + sb);
out.write(sb.toString().getBytes());
}
public int do_challenge(int auth, Command c) throws IOException {
switch (auth) {
case AUTH_SHA:
String[] reply = stupidlyDecode(c.getData()).split(" ");
if (Debug.debug) Debug.print(Debug.VERBOSE, Arrays.toString(reply));
if (3 != reply.length) {
if (Debug.debug) Debug.print(Debug.DEBUG, "Reply is not length 3");
return ERROR;
}
String context = reply[0];
String ID = reply[1];
String serverchallenge = reply[2];
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException NSAe) {
if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe);
return ERROR;
}
byte[] buf = new byte[8];
Message.marshallintBig(System.currentTimeMillis(), buf, 0, 8);
String clientchallenge = stupidlyEncode(md.digest(buf));
md.reset();
long start = System.currentTimeMillis();
String cookie = null;
while (null == cookie && (System.currentTimeMillis() - start) < LOCK_TIMEOUT)
cookie = findCookie(context, ID);
if (null == cookie) {
if (Debug.debug)
Debug.print(Debug.DEBUG, "Did not find a cookie in context " + context + " with ID " + ID);
return ERROR;
}
String response = serverchallenge + ":" + clientchallenge + ":" + cookie;
buf = md.digest(response.getBytes());
if (Debug.debug)
Debug.print(Debug.VERBOSE, "Response: " + response + " hash: " + Hexdump.format(buf));
response = stupidlyEncode(buf);
c.setResponse(stupidlyEncode(clientchallenge + " " + response));
return OK;
default:
if (Debug.debug) Debug.print(Debug.DEBUG, "Not DBUS_COOKIE_SHA1 authtype.");
return ERROR;
}
}
public String challenge = "";
public String cookie = "";
public int do_response(int auth, String Uid, String kernelUid, Command c) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException NSAe) {
if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe);
return ERROR;
}
switch (auth) {
case AUTH_NONE:
switch (c.getMechs()) {
case AUTH_ANON:
return OK;
case AUTH_EXTERNAL:
if (0 == col.compare(Uid, c.getData()) &&
(null == kernelUid || 0 == col.compare(Uid, kernelUid)))
return OK;
else
return ERROR;
case AUTH_SHA:
String context = COOKIE_CONTEXT;
long id = System.currentTimeMillis();
byte[] buf = new byte[8];
Message.marshallintBig(id, buf, 0, 8);
challenge = stupidlyEncode(md.digest(buf));
Random r = new Random();
r.nextBytes(buf);
cookie = stupidlyEncode(md.digest(buf));
try {
addCookie(context, "" + id, id / 1000, cookie);
} catch (IOException IOe) {
if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, IOe);
}
if (Debug.debug)
Debug.print(Debug.DEBUG, "Sending challenge: " + context + ' ' + id + ' ' + challenge);
c.setResponse(stupidlyEncode(context + ' ' + id + ' ' + challenge));
return CONTINUE;
default:
return ERROR;
}
case AUTH_SHA:
String[] response = stupidlyDecode(c.getData()).split(" ");
if (response.length < 2) return ERROR;
String cchal = response[0];
String hash = response[1];
String prehash = challenge + ":" + cchal + ":" + cookie;
byte[] buf = md.digest(prehash.getBytes());
String posthash = stupidlyEncode(buf);
if (Debug.debug)
Debug.print(Debug.DEBUG, "Authenticating Hash; data=" + prehash + " remote hash=" + hash + " local hash=" + posthash);
if (0 == col.compare(posthash, hash))
return OK;
else
return ERROR;
default:
return ERROR;
}
}
public String[] getTypes(int types) {
switch (types) {
case AUTH_EXTERNAL:
return new String[]{"EXTERNAL"};
case AUTH_SHA:
return new String[]{"DBUS_COOKIE_SHA1"};
case AUTH_ANON:
return new String[]{"ANONYMOUS"};
case AUTH_SHA + AUTH_EXTERNAL:
return new String[]{"EXTERNAL", "DBUS_COOKIE_SHA1"};
case AUTH_SHA + AUTH_ANON:
return new String[]{"ANONYMOUS", "DBUS_COOKIE_SHA1"};
case AUTH_EXTERNAL + AUTH_ANON:
return new String[]{"ANONYMOUS", "EXTERNAL"};
case AUTH_EXTERNAL + AUTH_ANON + AUTH_SHA:
return new String[]{"ANONYMOUS", "EXTERNAL", "DBUS_COOKIE_SHA1"};
default:
return new String[]{};
}
}
/**
* performs SASL auth on the given streams.
* Mode selects whether to run as a SASL server or client.
* Types is a bitmask of the available auth types.
* Returns true if the auth was successful and false if it failed.
*/
@SuppressWarnings("unchecked")
public boolean auth(int mode, int types, String guid, OutputStream out, InputStream in, UnixSocket us) throws IOException {
String username = System.getProperty("user.name");
String Uid = null;
String kernelUid = null;
try {
Class c = Class.forName("com.sun.security.auth.module.UnixSystem");
Method m = c.getMethod("getUid");
Object o = c.newInstance();
long uid = (Long) m.invoke(o);
Uid = stupidlyEncode("" + uid);
} catch (Exception e) {
Uid = stupidlyEncode(username);
}
Command c;
int failed = 0;
int current = 0;
int state = INITIAL_STATE;
while (state != AUTHENTICATED && state != FAILED) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "AUTH state: " + state);
switch (mode) {
case MODE_CLIENT:
switch (state) {
case INITIAL_STATE:
if (null == us)
out.write(new byte[]{0});
else
us.sendCredentialByte((byte) 0);
send(out, COMMAND_AUTH);
state = WAIT_DATA;
break;
case WAIT_DATA:
c = receive(in);
switch (c.getCommand()) {
case COMMAND_DATA:
switch (do_challenge(current, c)) {
case CONTINUE:
send(out, COMMAND_DATA, c.getResponse());
break;
case OK:
send(out, COMMAND_DATA, c.getResponse());
state = WAIT_OK;
break;
case ERROR:
send(out, COMMAND_ERROR, c.getResponse());
break;
}
break;
case COMMAND_REJECTED:
failed |= current;
int available = c.getMechs() & (~failed);
if (0 != (available & AUTH_EXTERNAL)) {
send(out, COMMAND_AUTH, "EXTERNAL", Uid);
current = AUTH_EXTERNAL;
} else if (0 != (available & AUTH_SHA)) {
send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
current = AUTH_SHA;
} else if (0 != (available & AUTH_ANON)) {
send(out, COMMAND_AUTH, "ANONYMOUS");
current = AUTH_ANON;
} else state = FAILED;
break;
case COMMAND_ERROR:
send(out, COMMAND_CANCEL);
state = WAIT_REJECT;
break;
case COMMAND_OK:
send(out, COMMAND_BEGIN);
state = AUTHENTICATED;
break;
default:
send(out, COMMAND_ERROR, "Got invalid command");
break;
}
break;
case WAIT_OK:
c = receive(in);
switch (c.getCommand()) {
case COMMAND_OK:
send(out, COMMAND_BEGIN);
state = AUTHENTICATED;
break;
case COMMAND_ERROR:
case COMMAND_DATA:
send(out, COMMAND_CANCEL);
state = WAIT_REJECT;
break;
case COMMAND_REJECTED:
failed |= current;
int available = c.getMechs() & (~failed);
state = WAIT_DATA;
if (0 != (available & AUTH_EXTERNAL)) {
send(out, COMMAND_AUTH, "EXTERNAL", Uid);
current = AUTH_EXTERNAL;
} else if (0 != (available & AUTH_SHA)) {
send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
current = AUTH_SHA;
} else if (0 != (available & AUTH_ANON)) {
send(out, COMMAND_AUTH, "ANONYMOUS");
current = AUTH_ANON;
} else state = FAILED;
break;
default:
send(out, COMMAND_ERROR, "Got invalid command");
break;
}
break;
case WAIT_REJECT:
c = receive(in);
switch (c.getCommand()) {
case COMMAND_REJECTED:
failed |= current;
int available = c.getMechs() & (~failed);
if (0 != (available & AUTH_EXTERNAL)) {
send(out, COMMAND_AUTH, "EXTERNAL", Uid);
current = AUTH_EXTERNAL;
} else if (0 != (available & AUTH_SHA)) {
send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
current = AUTH_SHA;
} else if (0 != (available & AUTH_ANON)) {
send(out, COMMAND_AUTH, "ANONYMOUS");
current = AUTH_ANON;
} else state = FAILED;
break;
default:
state = FAILED;
break;
}
break;
default:
state = FAILED;
}
break;
case MODE_SERVER:
switch (state) {
case INITIAL_STATE:
byte[] buf = new byte[1];
if (null == us) {
in.read(buf);
} else {
buf[0] = us.recvCredentialByte();
int kuid = us.getPeerUID();
if (kuid >= 0)
kernelUid = stupidlyEncode("" + kuid);
}
if (0 != buf[0]) state = FAILED;
else state = WAIT_AUTH;
break;
case WAIT_AUTH:
c = receive(in);
switch (c.getCommand()) {
case COMMAND_AUTH:
if (null == c.getData()) {
send(out, COMMAND_REJECTED, getTypes(types));
} else {
switch (do_response(current, Uid, kernelUid, c)) {
case CONTINUE:
send(out, COMMAND_DATA, c.getResponse());
current = c.getMechs();
state = WAIT_DATA;
break;
case OK:
send(out, COMMAND_OK, guid);
state = WAIT_BEGIN;
current = 0;
break;
case REJECT:
send(out, COMMAND_REJECTED, getTypes(types));
current = 0;
break;
}
}
break;
case COMMAND_ERROR:
send(out, COMMAND_REJECTED, getTypes(types));
break;
case COMMAND_BEGIN:
state = FAILED;
break;
default:
send(out, COMMAND_ERROR, "Got invalid command");
break;
}
break;
case WAIT_DATA:
c = receive(in);
switch (c.getCommand()) {
case COMMAND_DATA:
switch (do_response(current, Uid, kernelUid, c)) {
case CONTINUE:
send(out, COMMAND_DATA, c.getResponse());
state = WAIT_DATA;
break;
case OK:
send(out, COMMAND_OK, guid);
state = WAIT_BEGIN;
current = 0;
break;
case REJECT:
send(out, COMMAND_REJECTED, getTypes(types));
current = 0;
break;
}
break;
case COMMAND_ERROR:
case COMMAND_CANCEL:
send(out, COMMAND_REJECTED, getTypes(types));
state = WAIT_AUTH;
break;
case COMMAND_BEGIN:
state = FAILED;
break;
default:
send(out, COMMAND_ERROR, "Got invalid command");
break;
}
break;
case WAIT_BEGIN:
c = receive(in);
switch (c.getCommand()) {
case COMMAND_ERROR:
case COMMAND_CANCEL:
send(out, COMMAND_REJECTED, getTypes(types));
state = WAIT_AUTH;
break;
case COMMAND_BEGIN:
state = AUTHENTICATED;
break;
default:
send(out, COMMAND_ERROR, "Got invalid command");
break;
}
break;
default:
state = FAILED;
}
break;
default:
return false;
}
}
return state == AUTHENTICATED;
}
}
public MessageReader min;
public MessageWriter mout;
public Transport() {
}
public static String genGUID() {
Random r = new Random();
byte[] buf = new byte[16];
r.nextBytes(buf);
String guid = Hexdump.toHex(buf);
return guid.replaceAll(" ", "");
}
public Transport(BusAddress address) throws IOException {
connect(address);
}
public Transport(String address) throws IOException, ParseException {
connect(new BusAddress(address));
}
public Transport(String address, int timeout) throws IOException, ParseException {
connect(new BusAddress(address), timeout);
}
public void connect(String address) throws IOException, ParseException {
connect(new BusAddress(address), 0);
}
public void connect(String address, int timeout) throws IOException, ParseException {
connect(new BusAddress(address), timeout);
}
public void connect(BusAddress address) throws IOException {
connect(address, 0);
}
public void connect(BusAddress address, int timeout) throws IOException {
if (Debug.debug) Debug.print(Debug.INFO, "Connecting to " + address);
OutputStream out = null;
InputStream in = null;
UnixSocket us = null;
Socket s = null;
int mode = 0;
int types = 0;
if ("unix".equals(address.getType())) {
types = SASL.AUTH_EXTERNAL;
mode = SASL.MODE_CLIENT;
us = new UnixSocket();
if (null != address.getParameter("abstract"))
us.connect(new UnixSocketAddress(address.getParameter("abstract"), true));
else if (null != address.getParameter("path"))
us.connect(new UnixSocketAddress(address.getParameter("path"), false));
us.setPassCred(true);
in = us.getInputStream();
out = us.getOutputStream();
} else if ("tcp".equals(address.getType())) {
types = SASL.AUTH_SHA;
if (null != address.getParameter("listen")) {
mode = SASL.MODE_SERVER;
ServerSocket ss = new ServerSocket();
ss.bind(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
s = ss.accept();
} else {
mode = SASL.MODE_CLIENT;
s = new Socket();
s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
}
in = s.getInputStream();
out = s.getOutputStream();
} else {
throw new IOException(getString("unknownAddress") + address.getType());
}
if (!(new SASL()).auth(mode, types, address.getParameter("guid"), out, in, us)) {
out.close();
throw new IOException(getString("errorAuth"));
}
if (null != us) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting timeout to " + timeout + " on Socket");
if (timeout == 1)
us.setBlocking(false);
else
us.setSoTimeout(timeout);
}
if (null != s) {
if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting timeout to " + timeout + " on Socket");
s.setSoTimeout(timeout);
}
mout = new MessageWriter(out);
min = new MessageReader(in);
}
public void disconnect() throws IOException {
if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting Transport");
min.close();
mout.close();
}
}

View file

@ -0,0 +1,24 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
/**
* This class should be extended to create Tuples.
* Any such class may be used as the return type for a method
* which returns multiple values.
* All fields in the Tuple which you wish to be serialized and sent to the
* remote method should be annotated with the org.freedesktop.dbus.Position
* annotation, in the order they should appear to DBus.
*/
public abstract class Tuple extends Container {
public Tuple() {
}
}

View file

@ -0,0 +1,37 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import org.freedesktop.dbus.exceptions.DBusException;
import java.lang.reflect.Type;
public class TypeSignature {
String sig;
public TypeSignature(String sig) {
this.sig = sig;
}
public TypeSignature(Type[] types) throws DBusException {
StringBuffer sb = new StringBuffer();
for (Type t : types) {
String[] ts = Marshalling.getDBusType(t);
for (String s : ts)
sb.append(s);
}
this.sig = sb.toString();
}
public String getSig() {
return sig;
}
}

View file

@ -0,0 +1,122 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.text.MessageFormat;
import static org.freedesktop.dbus.Gettext.getString;
/**
* Class to represent 16-bit unsigned integers.
*/
@SuppressWarnings("serial")
public class UInt16 extends Number implements Comparable<UInt16> {
/**
* Maximum possible value.
*/
public static final int MAX_VALUE = 65535;
/**
* Minimum possible value.
*/
public static final int MIN_VALUE = 0;
private int value;
/**
* Create a UInt16 from an int.
*
* @param value Must be within MIN_VALUE&ndash;MAX_VALUE
* @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
*/
public UInt16(int value) {
if (value < MIN_VALUE || value > MAX_VALUE)
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_VALUE}));
this.value = value;
}
/**
* Create a UInt16 from a String.
*
* @param value Must parse to a valid integer within MIN_VALUE&ndash;MAX_VALUE
* @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_VALUE
*/
public UInt16(String value) {
this(Integer.parseInt(value));
}
/**
* The value of this as a byte.
*/
public byte byteValue() {
return (byte) value;
}
/**
* The value of this as a double.
*/
public double doubleValue() {
return (double) value;
}
/**
* The value of this as a float.
*/
public float floatValue() {
return (float) value;
}
/**
* The value of this as a int.
*/
public int intValue() {
return /*(int)*/ value;
}
/**
* The value of this as a long.
*/
public long longValue() {
return (long) value;
}
/**
* The value of this as a short.
*/
public short shortValue() {
return (short) value;
}
/**
* Test two UInt16s for equality.
*/
public boolean equals(Object o) {
return o instanceof UInt16 && ((UInt16) o).value == this.value;
}
public int hashCode() {
return /*(int)*/ value;
}
/**
* Compare two UInt16s.
*
* @return 0 if equal, -ve or +ve if they are different.
*/
public int compareTo(UInt16 other) {
return /*(int)*/ (this.value - other.value);
}
/**
* The value of this as a string.
*/
public String toString() {
return "" + value;
}
}

View file

@ -0,0 +1,122 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.text.MessageFormat;
import static org.freedesktop.dbus.Gettext.getString;
/**
* Class to represent unsigned 32-bit numbers.
*/
@SuppressWarnings("serial")
public class UInt32 extends Number implements Comparable<UInt32> {
/**
* Maximum allowed value
*/
public static final long MAX_VALUE = 4294967295L;
/**
* Minimum allowed value
*/
public static final long MIN_VALUE = 0;
private long value;
/**
* Create a UInt32 from a long.
*
* @param value Must be a valid integer within MIN_VALUE&ndash;MAX_VALUE
* @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
*/
public UInt32(long value) {
if (value < MIN_VALUE || value > MAX_VALUE)
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_VALUE}));
this.value = value;
}
/**
* Create a UInt32 from a String.
*
* @param value Must parse to a valid integer within MIN_VALUE&ndash;MAX_VALUE
* @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_VALUE
*/
public UInt32(String value) {
this(Long.parseLong(value));
}
/**
* The value of this as a byte.
*/
public byte byteValue() {
return (byte) value;
}
/**
* The value of this as a double.
*/
public double doubleValue() {
return (double) value;
}
/**
* The value of this as a float.
*/
public float floatValue() {
return (float) value;
}
/**
* The value of this as a int.
*/
public int intValue() {
return (int) value;
}
/**
* The value of this as a long.
*/
public long longValue() {
return /*(long)*/ value;
}
/**
* The value of this as a short.
*/
public short shortValue() {
return (short) value;
}
/**
* Test two UInt32s for equality.
*/
public boolean equals(Object o) {
return o instanceof UInt32 && ((UInt32) o).value == this.value;
}
public int hashCode() {
return (int) value;
}
/**
* Compare two UInt32s.
*
* @return 0 if equal, -ve or +ve if they are different.
*/
public int compareTo(UInt32 other) {
return (int) (this.value - other.value);
}
/**
* The value of this as a string
*/
public String toString() {
return "" + value;
}
}

View file

@ -0,0 +1,203 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import java.math.BigInteger;
import java.text.MessageFormat;
import static org.freedesktop.dbus.Gettext.getString;
/**
* Class to represent unsigned 64-bit numbers.
* Warning: Any functions which take or return a <tt>long</tt>
* are restricted to the range of a signed 64bit number.
* Use the BigInteger methods if you wish access to the full
* range.
*/
@SuppressWarnings("serial")
public class UInt64 extends Number implements Comparable<UInt64> {
/**
* Maximum allowed value (when accessed as a long)
*/
public static final long MAX_LONG_VALUE = Long.MAX_VALUE;
/**
* Maximum allowed value (when accessed as a BigInteger)
*/
public static final BigInteger MAX_BIG_VALUE = new BigInteger("18446744073709551615");
/**
* Minimum allowed value
*/
public static final long MIN_VALUE = 0;
private BigInteger value;
private long top;
private long bottom;
/**
* Create a UInt64 from a long.
*
* @param value Must be a valid integer within MIN_VALUE&ndash;MAX_VALUE
* @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
*/
public UInt64(long value) {
if (value < MIN_VALUE || value > MAX_LONG_VALUE)
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_LONG_VALUE}));
this.value = new BigInteger("" + value);
this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
}
/**
* Create a UInt64 from two longs.
*
* @param top Most significant 4 bytes.
* @param bottom Least significant 4 bytes.
*/
public UInt64(long top, long bottom) {
BigInteger a = new BigInteger("" + top);
a = a.shiftLeft(32);
a = a.add(new BigInteger("" + bottom));
if (0 > a.compareTo(BigInteger.ZERO))
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{a, MIN_VALUE, MAX_BIG_VALUE}));
if (0 < a.compareTo(MAX_BIG_VALUE))
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{a, MIN_VALUE, MAX_BIG_VALUE}));
this.value = a;
this.top = top;
this.bottom = bottom;
}
/**
* Create a UInt64 from a BigInteger
*
* @param value Must be a valid BigInteger between MIN_VALUE&ndash;MAX_BIG_VALUE
* @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_BIG_VALUE
*/
public UInt64(BigInteger value) {
if (null == value)
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
if (0 > value.compareTo(BigInteger.ZERO))
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
if (0 < value.compareTo(MAX_BIG_VALUE))
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
this.value = value;
this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
}
/**
* Create a UInt64 from a String.
*
* @param value Must parse to a valid integer within MIN_VALUE&ndash;MAX_BIG_VALUE
* @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_BIG_VALUE
*/
public UInt64(String value) {
if (null == value)
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
BigInteger a = new BigInteger(value);
if (0 > a.compareTo(BigInteger.ZERO))
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
if (0 < a.compareTo(MAX_BIG_VALUE))
throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
this.value = a;
this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
}
/**
* The value of this as a BigInteger.
*/
public BigInteger value() {
return value;
}
/**
* The value of this as a byte.
*/
public byte byteValue() {
return value.byteValue();
}
/**
* The value of this as a double.
*/
public double doubleValue() {
return value.doubleValue();
}
/**
* The value of this as a float.
*/
public float floatValue() {
return value.floatValue();
}
/**
* The value of this as a int.
*/
public int intValue() {
return value.intValue();
}
/**
* The value of this as a long.
*/
public long longValue() {
return value.longValue();
}
/**
* The value of this as a short.
*/
public short shortValue() {
return value.shortValue();
}
/**
* Test two UInt64s for equality.
*/
public boolean equals(Object o) {
return o instanceof UInt64 && this.value.equals(((UInt64) o).value);
}
public int hashCode() {
return value.hashCode();
}
/**
* Compare two UInt32s.
*
* @return 0 if equal, -ve or +ve if they are different.
*/
public int compareTo(UInt64 other) {
return this.value.compareTo(other.value);
}
/**
* The value of this as a string.
*/
public String toString() {
return value.toString();
}
/**
* Most significant 4 bytes.
*/
public long top() {
return top;
}
/**
* Least significant 4 bytes.
*/
public long bottom() {
return bottom;
}
}

View file

@ -0,0 +1,136 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug;
import org.freedesktop.dbus.exceptions.DBusException;
import java.lang.reflect.Type;
import java.text.MessageFormat;
import java.util.Vector;
import static org.freedesktop.dbus.Gettext.getString;
/**
* A Wrapper class for Variant values.
* A method on DBus can send or receive a Variant.
* This will wrap another value whose type is determined at runtime.
* The Variant may be parameterized to restrict the types it may accept.
*/
public class Variant<T> {
private final T o;
private final Type type;
private final String sig;
/**
* Create a Variant from a basic type object.
*
* @param o The wrapped value.
* @throws IllegalArugmentException If you try and wrap Null or an object of a non-basic type.
*/
public Variant(T o) throws IllegalArgumentException {
if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
type = o.getClass();
try {
String[] ss = Marshalling.getDBusType(o.getClass(), true);
if (ss.length != 1)
throw new IllegalArgumentException(getString("cannotWrapMultiValuedInVariant") + type);
this.sig = ss[0];
} catch (DBusException DBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{o.getClass(), DBe.getMessage()}));
}
this.o = o;
}
/**
* Create a Variant.
*
* @param o The wrapped value.
* @param type The explicit type of the value.
* @throws IllegalArugmentException If you try and wrap Null or an object which cannot be sent over DBus.
*/
public Variant(T o, Type type) throws IllegalArgumentException {
if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
this.type = type;
try {
String[] ss = Marshalling.getDBusType(type);
if (ss.length != 1)
throw new IllegalArgumentException(getString("cannotWrapMultiValuedInVariant") + type);
this.sig = ss[0];
} catch (DBusException DBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{type, DBe.getMessage()}));
}
this.o = o;
}
/**
* Create a Variant.
*
* @param o The wrapped value.
* @param sig The explicit type of the value, as a dbus type string.
* @throws IllegalArugmentException If you try and wrap Null or an object which cannot be sent over DBus.
*/
public Variant(T o, String sig) throws IllegalArgumentException {
if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
this.sig = sig;
try {
Vector<Type> ts = new Vector<Type>();
Marshalling.getJavaType(sig, ts, 1);
if (ts.size() != 1)
throw new IllegalArgumentException(getString("cannotWrapNoTypesInVariant") + sig);
this.type = ts.get(0);
} catch (DBusException DBe) {
if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{sig, DBe.getMessage()}));
}
this.o = o;
}
/**
* Return the wrapped value.
*/
public T getValue() {
return o;
}
/**
* Return the type of the wrapped value.
*/
public Type getType() {
return type;
}
/**
* Return the dbus signature of the wrapped value.
*/
public String getSig() {
return sig;
}
/**
* Format the Variant as a string.
*/
public String toString() {
return "[" + o + "]";
}
/**
* Compare this Variant with another by comparing contents
*/
@SuppressWarnings("unchecked")
public boolean equals(Object other) {
if (null == other) return false;
if (!(other instanceof Variant)) return false;
return this.o.equals(((Variant<? extends Object>) other).o);
}
}

View file

@ -0,0 +1,24 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
/**
* An exception within DBus.
*/
@SuppressWarnings("serial")
public class DBusException extends Exception {
/**
* Create an exception with the specified message
*/
public DBusException(String message) {
super(message);
}
}

View file

@ -0,0 +1,39 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
/**
* An exception while running a remote method within DBus.
*/
@SuppressWarnings("serial")
public class DBusExecutionException extends RuntimeException {
private String type;
/**
* Create an exception with the specified message
*/
public DBusExecutionException(String message) {
super(message);
}
public void setType(String type) {
this.type = type;
}
/**
* Get the DBus type of this exception. Use if this
* was an exception we don't have a class file for.
*/
public String getType() {
if (null == type) return getClass().getName();
else return type;
}
}

View file

@ -0,0 +1,18 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
@SuppressWarnings("serial")
public class FatalDBusException extends DBusException implements FatalException {
public FatalDBusException(String message) {
super(message);
}
}

View file

@ -0,0 +1,14 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
public interface FatalException {
}

View file

@ -0,0 +1,18 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
@SuppressWarnings("serial")
public class InternalMessageException extends DBusExecutionException implements NonFatalException {
public InternalMessageException(String message) {
super(message);
}
}

View file

@ -0,0 +1,18 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
@SuppressWarnings("serial")
public class MarshallingException extends DBusException implements NonFatalException {
public MarshallingException(String message) {
super(message);
}
}

View file

@ -0,0 +1,21 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
/**
* Thrown if a message is formatted incorrectly.
*/
@SuppressWarnings("serial")
public class MessageFormatException extends DBusException implements NonFatalException {
public MessageFormatException(String message) {
super(message);
}
}

View file

@ -0,0 +1,20 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
import java.io.IOException;
@SuppressWarnings("serial")
public class MessageProtocolVersionException extends IOException implements FatalException {
public MessageProtocolVersionException(String message) {
super(message);
}
}

View file

@ -0,0 +1,20 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
import java.io.IOException;
@SuppressWarnings("serial")
public class MessageTypeException extends IOException implements NonFatalException {
public MessageTypeException(String message) {
super(message);
}
}

View file

@ -0,0 +1,14 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
public interface NonFatalException {
}

View file

@ -0,0 +1,21 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
/**
* Thrown if a DBus action is called when not connected to the Bus.
*/
@SuppressWarnings("serial")
public class NotConnected extends DBusExecutionException implements FatalException {
public NotConnected(String message) {
super(message);
}
}

View file

@ -0,0 +1,20 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.exceptions;
import static org.freedesktop.dbus.Gettext.getString;
@SuppressWarnings("serial")
public class UnknownTypeCodeException extends DBusException implements NonFatalException {
public UnknownTypeCodeException(byte code) {
super(getString("invalidDBusCode") + code);
}
}

View file

@ -0,0 +1,44 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.types;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
/**
* The type of a list.
* Should be used whenever you need a Type variable for a list.
*/
public class DBusListType implements ParameterizedType {
private Type v;
/**
* Create a List type.
*
* @param v Type of the list contents.
*/
public DBusListType(Type v) {
this.v = v;
}
public Type[] getActualTypeArguments() {
return new Type[]{v};
}
public Type getRawType() {
return List.class;
}
public Type getOwnerType() {
return null;
}
}

View file

@ -0,0 +1,47 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.types;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
/**
* The type of a map.
* Should be used whenever you need a Type variable for a map.
*/
public class DBusMapType implements ParameterizedType {
private Type k;
private Type v;
/**
* Create a map type.
*
* @param k The type of the keys.
* @param v The type of the values.
*/
public DBusMapType(Type k, Type v) {
this.k = k;
this.v = v;
}
public Type[] getActualTypeArguments() {
return new Type[]{k, v};
}
public Type getRawType() {
return Map.class;
}
public Type getOwnerType() {
return null;
}
}

View file

@ -0,0 +1,45 @@
/*
D-Bus Java Implementation
Copyright (c) 2005-2006 Matthew Johnson
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.types;
import org.freedesktop.dbus.Struct;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* The type of a struct.
* Should be used whenever you need a Type variable for a struct.
*/
public class DBusStructType implements ParameterizedType {
private Type[] contents;
/**
* Create a struct type.
*
* @param contents The types contained in this struct.
*/
public DBusStructType(Type... contents) {
this.contents = contents;
}
public Type[] getActualTypeArguments() {
return contents;
}
public Type getRawType() {
return Struct.class;
}
public Type getOwnerType() {
return null;
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.freedesktop.sssd.infopipe;
import org.freedesktop.dbus.DBusInterface;
import java.util.List;
/**
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
*/
public interface Cache extends DBusInterface {
List<DBusInterface> List();
List<DBusInterface> ListByDomain(String domain_name);
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.freedesktop.sssd.infopipe;
import org.freedesktop.dbus.DBusInterface;
import org.freedesktop.dbus.DBusInterfaceName;
import org.freedesktop.dbus.DBusMemberName;
import org.freedesktop.dbus.Variant;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
*/
@DBusInterfaceName("org.freedesktop.sssd.infopipe")
public interface InfoPipe extends DBusInterface {
String OBJECTPATH = "/org/freedesktop/sssd/infopipe";
@DBusMemberName("GetUserAttr")
Map<String, Variant> getUserAttributes(String user, List<String> attr);
@DBusMemberName("GetUserGroups")
List<String> getUserGroups(String user);
}

View file

@ -0,0 +1,35 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.freedesktop.sssd.infopipe;
import org.freedesktop.dbus.DBusInterface;
import org.freedesktop.dbus.DBusInterfaceName;
import org.freedesktop.dbus.DBusMemberName;
/**
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
*/
@DBusInterfaceName("org.freedesktop.sssd.infopipe.Users")
public interface User extends DBusInterface {
String OBJECTPATH = "/org/freedesktop/sssd/infopipe/Users";
@DBusMemberName("FindByCertificate")
DBusInterface findByCertificate(String pem_cert);
}

View file

@ -0,0 +1,188 @@
/*
* The MIT License
*
* Copyright (c) 2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import org.jboss.logging.Logger;
import org.jvnet.libpam.impl.CLibrary.passwd;
import org.jvnet.libpam.impl.PAMLibrary.pam_conv;
import org.jvnet.libpam.impl.PAMLibrary.pam_conv.PamCallback;
import org.jvnet.libpam.impl.PAMLibrary.pam_handle_t;
import org.jvnet.libpam.impl.PAMLibrary.pam_message;
import org.jvnet.libpam.impl.PAMLibrary.pam_response;
import java.util.Set;
import static com.sun.jna.Native.POINTER_SIZE;
import static org.jvnet.libpam.impl.CLibrary.libc;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_CONV_ERR;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_PROMPT_ECHO_OFF;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_SUCCESS;
import static org.jvnet.libpam.impl.PAMLibrary.PAM_USER;
import static org.jvnet.libpam.impl.PAMLibrary.libpam;
/**
* PAM authenticator.
* <p>
* <p>
* Instances are thread unsafe and non reentrant. An instace cannot be reused
* to authenticate multiple users.
* <p>
* <p>
* For an overview of PAM programming, refer to the following resources:
* <p>
* <ul>
* <li><a href="http://www.netbsd.org/docs/guide/en/chap-pam.html">NetBSD PAM programming guide</a>
* <li><a href="http://www.kernel.org/pub/linux/libs/pam/">Linux PAM</a>
* </ul>
*
* @author Kohsuke Kawaguchi
*/
public class PAM {
private pam_handle_t pht;
private int ret;
/**
* Temporarily stored to pass a value from {@link #authenticate(String, String...)}
* to {@link pam_conv}.
*/
private String[] factors;
/**
* Creates a new authenticator.
*
* @param serviceName PAM service name. This corresponds to the service name that shows up
* in the PAM configuration,
*/
public PAM(String serviceName) throws PAMException {
pam_conv conv = new pam_conv(new PamCallback() {
public int callback(int num_msg, Pointer msg, Pointer resp, Pointer _) {
LOGGER.debug("pam_conv num_msg=" + num_msg);
if (factors == null)
return PAM_CONV_ERR;
// allocates pam_response[num_msg]. the caller will free this
Pointer m = libc.calloc(pam_response.SIZE, num_msg);
resp.setPointer(0, m);
for (int i = 0; i < factors.length; i++) {
pam_message pm = new pam_message(msg.getPointer(POINTER_SIZE * i));
LOGGER.debug(pm.msg_style + ":" + pm.msg);
if (pm.msg_style == PAM_PROMPT_ECHO_OFF) {
pam_response r = new pam_response(m.share(pam_response.SIZE * i));
r.setResp(factors[i]);
r.write(); // write to (*resp)[i]
}
}
return PAM_SUCCESS;
}
});
PointerByReference phtr = new PointerByReference();
check(libpam.pam_start(serviceName, null, conv, phtr), "pam_start failed");
pht = new pam_handle_t(phtr.getValue());
}
private void check(int ret, String msg) throws PAMException {
this.ret = ret;
if (ret != 0) {
if (pht != null)
throw new PAMException(msg + " : " + libpam.pam_strerror(pht, ret));
else
throw new PAMException(msg);
}
}
/**
* Authenticate the user with a password.
*
* @return Upon a successful authentication, return information about the user.
* @throws PAMException If the authentication fails.
*/
public UnixUser authenticate(String username, String... factors) throws PAMException {
this.factors = factors;
try {
check(libpam.pam_set_item(pht, PAM_USER, username), "pam_set_item failed");
check(libpam.pam_authenticate(pht, 0), "pam_authenticate failed");
check(libpam.pam_setcred(pht, 0), "pam_setcred failed");
// several different error code seem to be used to represent authentication failures
// check(libpam.pam_acct_mgmt(pht,0),"pam_acct_mgmt failed");
PointerByReference r = new PointerByReference();
check(libpam.pam_get_item(pht, PAM_USER, r), "pam_get_item failed");
String userName = r.getValue().getString(0);
passwd pwd = libc.getpwnam(userName);
if (pwd == null)
throw new PAMException("Authentication succeeded but no user information is available");
return new UnixUser(userName, pwd);
} finally {
this.factors = null;
}
}
/**
* Returns the groups a user belongs to
*
* @param username
* @return Set of group names
* @throws PAMException
* @deprecated Pointless and ugly convenience method.
*/
public Set<String> getGroupsOfUser(String username) throws PAMException {
return new UnixUser(username).getGroups();
}
/**
* After a successful authentication, call this method to obtain the effective user name.
* This can be different from the user name that you passed to the {@link #authenticate(String, String)}
* method.
*/
/**
* Performs an early disposal of the object, instead of letting this GC-ed.
* Since PAM may hold on to native resources that don't put pressure on Java GC,
* doing this is a good idea.
* <p>
* <p>
* This method is called by {@link #finalize()}, too, so it's not required
* to call this method explicitly, however.
*/
public void dispose() {
if (pht != null) {
libpam.pam_end(pht, ret);
pht = null;
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
dispose();
}
private static final Logger LOGGER = Logger.getLogger(PAM.class.getName());
}

View file

@ -0,0 +1,48 @@
/*
* The MIT License
*
* Copyright (c) 2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam;
/**
* Exception in PAM invoactions.
*
* @author Kohsuke Kawaguchi
*/
public class PAMException extends Exception {
public PAMException() {
}
public PAMException(String message) {
super(message);
}
public PAMException(String message, Throwable cause) {
super(message, cause);
}
public PAMException(Throwable cause) {
super(cause);
}
private static final long serialVersionUID = 1L;
}

View file

@ -0,0 +1,159 @@
/*
* The MIT License
*
* Copyright (c) 2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam;
import com.sun.jna.Memory;
import com.sun.jna.ptr.IntByReference;
import org.jvnet.libpam.impl.CLibrary.group;
import org.jvnet.libpam.impl.CLibrary.passwd;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static org.jvnet.libpam.impl.CLibrary.libc;
/**
* Represents an Unix user. Immutable.
*
* @author Kohsuke Kawaguchi
*/
public class UnixUser {
private final String userName, gecos, dir, shell;
private final int uid, gid;
private final Set<String> groups;
/*package*/ UnixUser(String userName, passwd pwd) throws PAMException {
this.userName = userName;
this.gecos = pwd.getPwGecos();
this.dir = pwd.getPwDir();
this.shell = pwd.getPwShell();
this.uid = pwd.getPwUid();
this.gid = pwd.getPwGid();
int sz = 4; /*sizeof(gid_t)*/
int ngroups = 64;
Memory m = new Memory(ngroups * sz);
IntByReference pngroups = new IntByReference(ngroups);
try {
if (libc.getgrouplist(userName, pwd.getPwGid(), m, pngroups) < 0) {
// allocate a bigger memory
m = new Memory(pngroups.getValue() * sz);
if (libc.getgrouplist(userName, pwd.getPwGid(), m, pngroups) < 0)
// shouldn't happen, but just in case.
throw new PAMException("getgrouplist failed");
}
ngroups = pngroups.getValue();
} catch (LinkageError e) {
// some platform, notably Solaris, doesn't have the getgrouplist function
ngroups = libc._getgroupsbymember(userName, m, ngroups, 0);
if (ngroups < 0)
throw new PAMException("_getgroupsbymember failed");
}
groups = new HashSet<String>();
for (int i = 0; i < ngroups; i++) {
int gid = m.getInt(i * sz);
group grp = libc.getgrgid(gid);
if (grp == null) {
continue;
}
groups.add(grp.gr_name);
}
}
public UnixUser(String userName) throws PAMException {
this(userName, passwd.loadPasswd(userName));
}
/**
* Copy constructor for mocking. Not intended for regular use. Only for testing.
* This signature may change in the future.
*/
protected UnixUser(String userName, String gecos, String dir, String shell, int uid, int gid, Set<String> groups) {
this.userName = userName;
this.gecos = gecos;
this.dir = dir;
this.shell = shell;
this.uid = uid;
this.gid = gid;
this.groups = groups;
}
/**
* Gets the unix account name. Never null.
*/
public String getUserName() {
return userName;
}
/**
* Gets the UID of this user.
*/
public int getUID() {
return uid;
}
/**
* Gets the GID of this user.
*/
public int getGID() {
return gid;
}
/**
* Gets the gecos (the real name) of this user.
*/
public String getGecos() {
return gecos;
}
/**
* Gets the home directory of this user.
*/
public String getDir() {
return dir;
}
/**
* Gets the shell of this user.
*/
public String getShell() {
return shell;
}
/**
* Gets the groups that this user belongs to.
*
* @return never null.
*/
public Set<String> getGroups() {
return Collections.unmodifiableSet(groups);
}
public static boolean exists(String name) {
return libc.getpwnam(name) != null;
}
}

View file

@ -0,0 +1,34 @@
/*
* The MIT License
*
* Copyright 2011, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
/**
* @author Sebastian Sdorra
*/
public interface BSDCLibrary extends CLibrary {
BSDPasswd getpwnam(String username);
}

View file

@ -0,0 +1,93 @@
/*
* The MIT License
*
* Copyright 2011, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
import org.jvnet.libpam.impl.CLibrary.passwd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* FreeeBSD, OpenBSD and MacOS passwd
* <p>
* struct passwd {
* char *pw_name;
* char *pw_passwd;
* uid_t pw_uid;
* gid_t pw_gid;
* time_t pw_change;
* char *pw_class;
* char *pw_gecos;
* char *pw_dir;
* char *pw_shell;
* time_t pw_expire;
* };
*
* @author Sebastian Sdorra
*/
public class BSDPasswd extends passwd {
/* password change time */
public long pw_change;
/* user access class */
public String pw_class;
/* Honeywell login info */
public String pw_gecos;
/* home directory */
public String pw_dir;
/* default shell */
public String pw_shell;
/* account expiration */
public long pw_expire;
@Override
public String getPwGecos() {
return pw_gecos;
}
@Override
public String getPwDir() {
return pw_dir;
}
@Override
public String getPwShell() {
return pw_shell;
}
@Override
protected List getFieldOrder() {
List fieldOrder = new ArrayList(super.getFieldOrder());
fieldOrder.addAll(Arrays.asList("pw_change", "pw_class", "pw_gecos",
"pw_dir", "pw_shell", "pw_expire"));
return fieldOrder;
}
}

View file

@ -0,0 +1,154 @@
/*
* The MIT License
*
* Copyright (c) 2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
import org.jvnet.libpam.PAMException;
import java.util.Arrays;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
public interface CLibrary extends Library {
/**
* Comparing http://linux.die.net/man/3/getpwnam
* and my Mac OS X reveals that the structure of this field isn't very portable.
* In particular, we cannot read the real name reliably.
*/
public class passwd extends Structure {
/**
* User name.
*/
public String pw_name;
/**
* Encrypted password.
*/
public String pw_passwd;
public int pw_uid;
public int pw_gid;
// ... there are a lot more fields
public static passwd loadPasswd(String userName) throws PAMException {
passwd pwd = libc.getpwnam(userName);
if (pwd == null) {
throw new PAMException("No user information is available");
}
return pwd;
}
public String getPwName() {
return pw_name;
}
public String getPwPasswd() {
return pw_passwd;
}
public int getPwUid() {
return pw_uid;
}
public int getPwGid() {
return pw_gid;
}
public String getPwGecos() {
return null;
}
public String getPwDir() {
return null;
}
public String getPwShell() {
return null;
}
protected List getFieldOrder() {
return Arrays.asList("pw_name", "pw_passwd", "pw_uid", "pw_gid");
}
}
public class group extends Structure {
public String gr_name;
// ... the rest of the field is not interesting for us
protected List getFieldOrder() {
return Arrays.asList("gr_name");
}
}
Pointer calloc(int count, int size);
Pointer strdup(String s);
passwd getpwnam(String username);
/**
* Lists up group IDs of the given user. On Linux and most BSDs, but not on Solaris.
* See http://www.gnu.org/software/hello/manual/gnulib/getgrouplist.html
*/
int getgrouplist(String user, int/*gid_t*/ group, Memory groups, IntByReference ngroups);
/**
* getgrouplist equivalent on Solaris.
* See http://mail.opensolaris.org/pipermail/sparks-discuss/2008-September/000528.html
*/
int _getgroupsbymember(String user, Memory groups, int maxgids, int numgids);
group getgrgid(int/*gid_t*/ gid);
group getgrnam(String name);
// other user/group related functions that are likely useful
// see http://www.gnu.org/software/libc/manual/html_node/Users-and-Groups.html#Users-and-Groups
public static final CLibrary libc = Instance.init();
static class Instance {
private static CLibrary init() {
if (Platform.isMac() || Platform.isOpenBSD()) {
return (CLibrary) Native.loadLibrary("c", BSDCLibrary.class);
} else if (Platform.isFreeBSD()) {
return (CLibrary) Native.loadLibrary("c", FreeBSDCLibrary.class);
} else if (Platform.isSolaris()) {
return (CLibrary) Native.loadLibrary("c", SolarisCLibrary.class);
} else if (Platform.isLinux()) {
return (CLibrary) Native.loadLibrary("c", LinuxCLibrary.class);
} else {
return (CLibrary) Native.loadLibrary("c", CLibrary.class);
}
}
}
}

View file

@ -0,0 +1,34 @@
/*
* The MIT License
*
* Copyright 2014, R. Tyler Croy, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
/**
* @author R. Tyler Croy
*/
public interface FreeBSDCLibrary extends CLibrary {
FreeBSDPasswd getpwnam(String username);
}

View file

@ -0,0 +1,98 @@
/*
* The MIT License
*
* Copyright 2014, R. Tyler Croy, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
import org.jvnet.libpam.impl.CLibrary.passwd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* FreeeBSD
* <p>
* struct passwd {
* char *pw_name;
* char *pw_passwd;
* uid_t pw_uid;
* gid_t pw_gid;
* time_t pw_change;
* char *pw_class;
* char *pw_gecos;
* char *pw_dir;
* char *pw_shell;
* time_t pw_expire;
* int pw_fields;
* };
*
* @author R. Tyler Croy
*/
public class FreeBSDPasswd extends passwd {
/* password change time */
public long pw_change;
/* user access class */
public String pw_class;
/* Honeywell login info */
public String pw_gecos;
/* home directory */
public String pw_dir;
/* default shell */
public String pw_shell;
/* account expiration */
public long pw_expire;
/* internal on FreeBSD? */
public int pw_fields;
@Override
public String getPwGecos() {
return pw_gecos;
}
@Override
public String getPwDir() {
return pw_dir;
}
@Override
public String getPwShell() {
return pw_shell;
}
@Override
protected List getFieldOrder() {
List fieldOrder = new ArrayList(super.getFieldOrder());
fieldOrder.addAll(Arrays.asList("pw_change", "pw_class", "pw_gecos",
"pw_dir", "pw_shell", "pw_expire", "pw_fields"));
return fieldOrder;
}
}

View file

@ -0,0 +1,34 @@
/*
* The MIT License
*
* Copyright 2011, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
/**
* @author Sebastian Sdorra
*/
public interface LinuxCLibrary extends CLibrary {
LinuxPasswd getpwnam(String username);
}

View file

@ -0,0 +1,81 @@
/*
* The MIT License
*
* Copyright 2011, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
import org.jvnet.libpam.impl.CLibrary.passwd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Linux passwd
* <p>
* ?struct passwd
* {
* char *pw_name;
* char *pw_passwd;
* __uid_t pw_uid;
* __gid_t pw_gid;
* char *pw_gecos;
* char *pw_dir;
* char *pw_shell;
* };
*
* @author Sebastian Sdorra
*/
public class LinuxPasswd extends passwd {
/* Honeywell login info */
public String pw_gecos;
/* home directory */
public String pw_dir;
/* default shell */
public String pw_shell;
public String getPwGecos() {
return pw_gecos;
}
@Override
public String getPwDir() {
return pw_dir;
}
@Override
public String getPwShell() {
return pw_shell;
}
@Override
protected List getFieldOrder() {
List fieldOrder = new ArrayList(super.getFieldOrder());
fieldOrder.addAll(Arrays.asList("pw_gecos", "pw_dir", "pw_shell"));
return fieldOrder;
}
}

View file

@ -0,0 +1,163 @@
/*
* The MIT License
*
* Copyright (c) 2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.Structure;
import com.sun.jna.ptr.PointerByReference;
import java.util.Arrays;
import java.util.List;
import static org.jvnet.libpam.impl.CLibrary.libc;
/**
* libpam.so binding.
* <p>
* See http://www.opengroup.org/onlinepubs/008329799/apdxa.htm
* for the online reference of pam_appl.h
*
* @author Kohsuke Kawaguchi
*/
public interface PAMLibrary extends Library {
class pam_handle_t extends PointerType {
public pam_handle_t() {
}
public pam_handle_t(Pointer pointer) {
super(pointer);
}
}
class pam_message extends Structure {
public int msg_style;
public String msg;
/**
* Attach to the memory region pointed by the given pointer.
*/
public pam_message(Pointer src) {
useMemory(src);
read();
}
protected List getFieldOrder() {
return Arrays.asList("msg_style", "msg");
}
}
class pam_response extends Structure {
/**
* This is really a string, but this field needs to be malloc-ed by the conversation
* method, and to be freed by the caler, so I bind it to {@link Pointer} here.
* <p>
* The man page doesn't say that, but see
* http://www.netbsd.org/docs/guide/en/chap-pam.html#pam-sample-conv
* This behavior is confirmed with a test, too; if I don't do strdup,
* libpam crashes.
*/
public Pointer resp;
public int resp_retcode;
/**
* Attach to the memory region pointed by the given memory.
*/
public pam_response(Pointer src) {
useMemory(src);
read();
}
public pam_response() {
}
/**
* Sets the response code.
*/
public void setResp(String msg) {
this.resp = libc.strdup(msg);
}
protected List getFieldOrder() {
return Arrays.asList("resp", "resp_retcode");
}
public static final int SIZE = new pam_response().size();
}
class pam_conv extends Structure {
public interface PamCallback extends Callback {
/**
* According to http://www.netbsd.org/docs/guide/en/chap-pam.html#pam-sample-conv,
* resp and its member string both needs to be allocated by malloc,
* to be freed by the caller.
*/
int callback(int num_msg, Pointer msg, Pointer resp, Pointer _);
}
public PamCallback conv;
public Pointer _;
public pam_conv(PamCallback conv) {
this.conv = conv;
}
protected List getFieldOrder() {
return Arrays.asList("conv", "_");
}
}
int pam_start(String service, String user, pam_conv conv, PointerByReference/* pam_handle_t** */ pamh_p);
int pam_end(pam_handle_t handle, int pam_status);
int pam_set_item(pam_handle_t handle, int item_type, String item);
int pam_get_item(pam_handle_t handle, int item_type, PointerByReference item);
int pam_authenticate(pam_handle_t handle, int flags);
int pam_setcred(pam_handle_t handle, int flags);
int pam_acct_mgmt(pam_handle_t handle, int flags);
String pam_strerror(pam_handle_t handle, int pam_error);
final int PAM_USER = 2;
// error code
final int PAM_SUCCESS = 0;
final int PAM_CONV_ERR = 6;
final int PAM_PROMPT_ECHO_OFF = 1; /* Echo off when getting response */
final int PAM_PROMPT_ECHO_ON = 2; /* Echo on when getting response */
final int PAM_ERROR_MSG = 3; /* Error message */
final int PAM_TEXT_INFO = 4; /* Textual information */
public static final PAMLibrary libpam = (PAMLibrary) Native.loadLibrary("pam", PAMLibrary.class);
}

View file

@ -0,0 +1,35 @@
/*
* The MIT License
*
* Copyright (c) 2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
/**
* @author Sebastian Sdorra
*/
public interface SolarisCLibrary extends CLibrary {
SolarisPasswd getpwnam(String username);
}

View file

@ -0,0 +1,86 @@
/*
* The MIT License
*
* Copyright (c) 2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.libpam.impl;
import org.jvnet.libpam.impl.CLibrary.passwd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Solaris passwd
* <p>
* struct passwd {
* char *pw_name;
* char *pw_passwd;
* uid_t pw_uid;
* gid_t pw_gid;
* char *pw_age;
* char *pw_comment;
* char *pw_gecos;
* char *pw_dir;
* char *pw_shell;
* };
*
* @author Sebastian Sdorra
*/
public class SolarisPasswd extends passwd {
public String pw_age;
public String pw_comment;
public String pw_gecos;
public String pw_dir;
public String pw_shell;
@Override
public String getPwGecos() {
return pw_gecos;
}
@Override
public String getPwDir() {
return pw_dir;
}
@Override
public String getPwShell() {
return pw_shell;
}
@Override
protected List getFieldOrder() {
List fieldOrder = new ArrayList(super.getFieldOrder());
fieldOrder.addAll(Arrays.asList("pw_age", "pw_comment", "pw_gecos",
"pw_dir", "pw_shell"));
return fieldOrder;
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.federation.sssd;
import org.keycloak.models.ModelReadOnlyException;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.UserModelDelegate;
/**
* Readonly proxy for a SSSD UserModel that prevents attributes from being updated.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
* @version $Revision: 1 $
*/
public class ReadonlySSSDUserModelDelegate extends UserModelDelegate implements UserModel {
private final SSSDFederationProvider provider;
public ReadonlySSSDUserModelDelegate(UserModel delegate, SSSDFederationProvider provider) {
super(delegate);
this.provider = provider;
}
@Override
public void setUsername(String username) {
throw new ModelReadOnlyException("Federated storage is not writable");
}
@Override
public void setLastName(String lastName) {
throw new ModelReadOnlyException("Federated storage is not writable");
}
@Override
public void setFirstName(String first) {
throw new ModelReadOnlyException("Federated storage is not writable");
}
@Override
public void updateCredentialDirectly(UserCredentialValueModel cred) {
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
throw new IllegalStateException("Federated storage is not writable");
}
super.updateCredentialDirectly(cred);
}
@Override
public void updateCredential(UserCredentialModel cred) {
if (provider.getSupportedCredentialTypes(delegate).contains(cred.getType())) {
throw new ModelReadOnlyException("Federated storage is not writable");
}
delegate.updateCredential(cred);
}
@Override
public void setEmail(String email) {
throw new ModelReadOnlyException("Federated storage is not writable");
}
}

View file

@ -0,0 +1,224 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.federation.sssd;
import org.freedesktop.dbus.Variant;
import org.jboss.logging.Logger;
import org.keycloak.federation.sssd.api.Sssd;
import org.keycloak.federation.sssd.impl.PAMAuthenticator;
import org.keycloak.models.CredentialValidationOutput;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.managers.UserManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* SPI provider implementation to retrieve data from SSSD and authenticate
* against PAM
*
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
* @version $Revision: 1 $
*/
public class SSSDFederationProvider implements UserFederationProvider {
private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
protected static final Set<String> supportedCredentialTypes = new HashSet<>();
private final SSSDFederationProviderFactory factory;
protected KeycloakSession session;
protected UserFederationProviderModel model;
public SSSDFederationProvider(KeycloakSession session, UserFederationProviderModel model, SSSDFederationProviderFactory sssdFederationProviderFactory) {
this.session = session;
this.model = model;
this.factory = sssdFederationProviderFactory;
}
static {
supportedCredentialTypes.add(UserCredentialModel.PASSWORD);
}
@Override
public UserModel getUserByUsername(RealmModel realm, String username) {
return findOrCreateAuthenticatedUser(realm, username);
}
/**
* Called after successful authentication
*
* @param realm realm
* @param username username without realm prefix
* @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider
*/
protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
UserModel user = session.userStorage().getUserByUsername(username, realm);
if (user != null) {
logger.debug("SSSD authenticated user " + username + " found in Keycloak storage");
if (!model.getId().equals(user.getFederationLink())) {
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() + "]");
return null;
} else {
UserModel proxied = validateAndProxy(realm, user);
if (proxied != null) {
return proxied;
} else {
logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
"] but principal is not correct.");
logger.warn("Will re-create user");
new UserManager(session).removeUser(realm, user, session.userStorage());
}
}
}
logger.debug("SSSD authenticated user " + username + " not in Keycloak storage. Creating...");
return importUserToKeycloak(realm, username);
}
protected UserModel importUserToKeycloak(RealmModel realm, String username) {
Sssd sssd = new Sssd(username);
Map<String, Variant> sssdUser = sssd.getUserAttributes();
logger.debugf("Creating SSSD user: %s to local Keycloak storage", username);
UserModel user = session.userStorage().addUser(realm, username);
user.setEnabled(true);
user.setEmail(Sssd.getRawAttribute(sssdUser.get("mail")));
user.setFirstName(Sssd.getRawAttribute(sssdUser.get("givenname")));
user.setLastName(Sssd.getRawAttribute(sssdUser.get("sn")));
for (String s : sssd.getUserGroups()) {
GroupModel group = KeycloakModelUtils.findGroupByPath(realm, "/" + s);
if (group == null) {
group = session.realms().createGroup(realm, s);
}
user.joinGroup(group);
}
user.setFederationLink(model.getId());
return validateAndProxy(realm, user);
}
@Override
public UserModel getUserByEmail(RealmModel realm, String email) {
return null;
}
@Override
public List<UserModel> searchByAttributes(Map<String, String> attributes, RealmModel realm, int maxResults) {
return Collections.emptyList();
}
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
return Collections.emptyList();
}
@Override
public void preRemove(RealmModel realm) {
// complete We don't care about the realm being removed
}
@Override
public void preRemove(RealmModel realm, RoleModel role) {
// complete we dont'care if a role is removed
}
@Override
public void preRemove(RealmModel realm, GroupModel group) {
// complete we dont'care if a role is removed
}
@Override
public boolean isValid(RealmModel realm, UserModel local) {
Map<String, Variant> attributes = new Sssd(local.getUsername()).getUserAttributes();
return Sssd.getRawAttribute(attributes.get("mail")).equalsIgnoreCase(local.getEmail());
}
@Override
public Set<String> getSupportedCredentialTypes(UserModel user) {
return supportedCredentialTypes;
}
@Override
public Set<String> getSupportedCredentialTypes() {
return supportedCredentialTypes;
}
@Override
public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) {
for (UserCredentialModel cred : input) {
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
PAMAuthenticator pam = factory.createPAMAuthenticator(user.getUsername(), cred.getValue());
return (pam.authenticate() != null);
}
}
return false;
}
@Override
public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) {
return validCredentials(realm, user, Arrays.asList(input));
}
@Override
public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential) {
return CredentialValidationOutput.failed();
}
@Override
public UserModel validateAndProxy(RealmModel realm, UserModel local) {
if (isValid(realm, local)) {
return new ReadonlySSSDUserModelDelegate(local, this);
} else {
return null;
}
}
@Override
public boolean synchronizeRegistrations() {
return false;
}
@Override
public UserModel register(RealmModel realm, UserModel user) {
throw new IllegalStateException("Registration not supported");
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
return true;
}
@Override
public void close() {
Sssd.disconnect();
}
}

View file

@ -0,0 +1,102 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.federation.sssd;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.federation.sssd.impl.PAMAuthenticator;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderFactory;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserFederationSyncResult;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
* @version $Revision: 1 $
*/
public class SSSDFederationProviderFactory implements UserFederationProviderFactory {
private static final String PROVIDER_NAME = "sssd";
private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
static final Set<String> configOptions = new HashSet<String>();
@Override
public String getId() {
return PROVIDER_NAME;
}
@Override
public UserFederationProvider getInstance(KeycloakSession session, UserFederationProviderModel model) {
return new SSSDFederationProvider(session, model, this);
}
/**
* List the configuration options to render and display in the admin console's generic management page for this
* plugin
*
* @return
*/
@Override
public Set<String> getConfigurationOptions() {
return configOptions;
}
@Override
public UserFederationProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public UserFederationSyncResult syncAllUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model) {
logger.info("Sync users not supported for this provider");
return UserFederationSyncResult.empty();
}
@Override
public UserFederationSyncResult syncChangedUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model, Date lastSync) {
logger.info("Sync users not supported for this provider");
return UserFederationSyncResult.empty();
}
protected PAMAuthenticator createPAMAuthenticator(String username, String... factors) {
return new PAMAuthenticator(username, factors);
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.federation.sssd.api;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.Variant;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.sssd.infopipe.InfoPipe;
import org.freedesktop.sssd.infopipe.User;
import org.jboss.logging.Logger;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
* @version $Revision: 1 $
*/
public class Sssd {
public static final String BUSNAME = "org.freedesktop.sssd.infopipe";
public static User user() {
return SingletonHolder.USER_OBJECT;
}
public static InfoPipe infopipe() {
return SingletonHolder.INFOPIPE_OBJECT;
}
public static void disconnect() {
SingletonHolder.DBUS_CONNECTION.disconnect();
}
private String username;
private static final Logger logger = Logger.getLogger(Sssd.class);
private Sssd() {
}
public Sssd(String username) {
this.username = username;
}
private static final class SingletonHolder {
private static InfoPipe INFOPIPE_OBJECT;
private static User USER_OBJECT;
private static DBusConnection DBUS_CONNECTION;
static {
try {
DBUS_CONNECTION = DBusConnection.getConnection(DBusConnection.SYSTEM);
INFOPIPE_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, InfoPipe.OBJECTPATH, InfoPipe.class);
USER_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, User.OBJECTPATH, User.class);
} catch (DBusException e) {
e.printStackTrace();
}
}
}
public static String getRawAttribute(Variant variant) {
if (variant != null) {
Vector value = (Vector) variant.getValue();
if (value.size() >= 1) {
return value.get(0).toString();
}
}
return null;
}
public Map<String, Variant> getUserAttributes() {
String[] attr = {"mail", "givenname", "sn", "telephoneNumber"};
Map<String, Variant> attributes = null;
try {
InfoPipe infoPipe = infopipe();
attributes = infoPipe.getUserAttributes(username, Arrays.asList(attr));
} catch (Exception e) {
logger.error("Failed to retrieve user's attributes from SSSD", e);
}
return attributes;
}
public List<String> getUserGroups() {
List<String> userGroups = null;
try {
InfoPipe infoPipe = Sssd.infopipe();
userGroups = infoPipe.getUserGroups(username);
} catch (Exception e) {
logger.error("Failed to retrieve user's groups from SSSD", e);
}
return userGroups;
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.keycloak.federation.sssd.impl;
import org.jboss.logging.Logger;
import org.jvnet.libpam.PAM;
import org.jvnet.libpam.PAMException;
import org.jvnet.libpam.UnixUser;
/**
* PAMAuthenticator for Unix users
*
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
* @version $Revision: 1 $
*/
public class PAMAuthenticator {
private static final String PAM_SERVICE = "keycloak";
private static final Logger logger = Logger.getLogger(PAMAuthenticator.class);
private final String username;
private final String[] factors;
public PAMAuthenticator(String username, String... factors) {
this.username = username;
this.factors = factors;
}
/**
* Returns true if user was successfully authenticated against PAM
*
* @return UnixUser object if user was successfully authenticated
*/
public UnixUser authenticate() {
PAM pam = null;
UnixUser user = null;
try {
pam = new PAM(PAM_SERVICE);
user = pam.authenticate(username, factors);
} catch (PAMException e) {
logger.error("Authentication failed", e);
e.printStackTrace();
} finally {
pam.dispose();
}
return user;
}
}

View file

@ -0,0 +1,37 @@
The D-Bus Java implementation was written by:
Matthew Johnson <dbus -at matthew -dot- ath -dot- cx>
Bug fixes/reports and other suggestions from:
Remi Emonet <remi.emonet -at- inrialpes -dot- fr>
Simon McVittie <simon -dot- mcvittie -at- collabora -dot- co -dot- uk>
Dick Hollenbeck <dick -at- softplc -dot- com>
Joshua Nichols <nichoj -at- gentoo -dot- org>
Ralf Kistner <ralf.kistner -at- gmail -dot- com>
Henrik Petander <henrik -dot- petander -at- iki -dot- fi>
Luigi Paioro <luigi -at- lambrate -dot- it>
Roberto Francisco Arroyo Moreno <robfram -at- ugr -dot- es>
Steve Crane <Steve -dot Crane -at- rococosoft -dot- com>
Philippe Marschall <philippe -dot- marschall -at- gmail -dot- com>
Daniel Machado <cdanielmachado -at- gmail -dot- com>
Anibal Sanchez <anibal -dot- sanchez -at- sunya -dot- com -dot- ar>
Jan Kümmel <freedesktop -at- snorc -dot- org>
Johannes Felten <johannesfelten -at- googlemail -dot- com>
Tom Walsh <walshtc -at- gmail -dot- com>
Ed Wei <Edward.Wei.03 -at- alum -dot- dartmouth -dot- org>
Sveinung Kvilhaugsvik <sveinung84 -at- users -dot- sourceforge -dot- net>
Hugues Moreau <hmoreau -at- gmail -dot- com>
Viktar Vauchkevich <vctr -at- yandex -dot- ru>
Serkan Kaba <serkan_kaba -at- yahoo -dot- com>
Adam Bennett <cruxic -at- gmail -dot- com>
Frank Benoit <benoit -at- tionex -dot- de>
Gunnar Aastrand Grimnes <gunnar -dot- grimnes -at- dfki -dot- de>
The included Viewer application was originally written by:
Peter Cox <petercox -at- gawab -dot- com>
with patches from:
Zsombor Gegesy <gzsombor -at- gmail -dot- com>

View file

@ -0,0 +1,680 @@
The D-Bus Java implementation is licensed to you under your choice of the
Academic Free License version 2.1, or the GNU Lesser/Library General Public License
version 2. Both licenses are included here. Each source code file is marked
with the proper copyright information.
The Academic Free License
v. 2.1
This Academic Free License (the "License") applies to any original work of
authorship (the "Original Work") whose owner (the "Licensor") has placed the
following notice immediately following the copyright notice for the Original
Work:
Licensed under the Academic Free License version 2.1
1) Grant of Copyright License. Licensor hereby grants You a world-wide,
royalty-free, non-exclusive, perpetual, sublicenseable license to do the
following:
a) to reproduce the Original Work in copies;
b) to prepare derivative works ("Derivative Works") based upon the Original
Work;
c) to distribute copies of the Original Work and Derivative Works to the
public;
d) to perform the Original Work publicly; and
e) to display the Original Work publicly.
2) Grant of Patent License. Licensor hereby grants You a world-wide,
royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
claims owned or controlled by the Licensor that are embodied in the Original
Work as furnished by the Licensor, to make, use, sell and offer for sale the
Original Work and Derivative Works.
3) Grant of Source Code License. The term "Source Code" means the preferred
form of the Original Work for making modifications to it and all available
documentation describing how to modify the Original Work. Licensor hereby
agrees to provide a machine-readable copy of the Source Code of the Original
Work along with each copy of the Original Work that Licensor distributes.
Licensor reserves the right to satisfy this obligation by placing a
machine-readable copy of the Source Code in an information repository
reasonably calculated to permit inexpensive and convenient access by You for as
long as Licensor continues to distribute the Original Work, and by publishing
the address of that information repository in a notice immediately following
the copyright notice that applies to the Original Work.
4) Exclusions From License Grant. Neither the names of Licensor, nor the names
of any contributors to the Original Work, nor any of their trademarks or
service marks, may be used to endorse or promote products derived from this
Original Work without express prior written permission of the Licensor. Nothing
in this License shall be deemed to grant any rights to trademarks, copyrights,
patents, trade secrets or any other intellectual property of Licensor except as
expressly stated herein. No patent license is granted to make, use, sell or
offer to sell embodiments of any patent claims other than the licensed claims
defined in Section 2. No right is granted to the trademarks of Licensor even if
such marks are included in the Original Work. Nothing in this License shall be
interpreted to prohibit Licensor from licensing under different terms from this
License any Original Work that Licensor otherwise would have a right to
license.
5) This section intentionally omitted.
6) Attribution Rights. You must retain, in the Source Code of any Derivative
Works that You create, all copyright, patent or trademark notices from the
Source Code of the Original Work, as well as any notices of licensing and any
descriptive text identified therein as an "Attribution Notice." You must cause
the Source Code for any Derivative Works that You create to carry a prominent
Attribution Notice reasonably calculated to inform recipients that You have
modified the Original Work.
7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
the copyright in and to the Original Work and the patent rights granted herein
by Licensor are owned by the Licensor or are sublicensed to You under the terms
of this License with the permission of the contributor(s) of those copyrights
and patent rights. Except as expressly stated in the immediately proceeding
sentence, the Original Work is provided under this License on an "AS IS" BASIS
and WITHOUT WARRANTY, either express or implied, including, without limitation,
the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
license to Original Work is granted hereunder except under this disclaimer.
8) Limitation of Liability. Under no circumstances and under no legal theory,
whether in tort (including negligence), contract, or otherwise, shall the
Licensor be liable to any person for any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License
or the use of the Original Work including, without limitation, damages for loss
of goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses. This limitation of liability shall not
apply to liability for death or personal injury resulting from Licensor's
negligence to the extent applicable law prohibits such limitation. Some
jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.
9) Acceptance and Termination. If You distribute copies of the Original Work or
a Derivative Work, You must make a reasonable effort under the circumstances to
obtain the express assent of recipients to the terms of this License. Nothing
else but this License (or another written agreement between Licensor and You)
grants You permission to create Derivative Works based upon the Original Work
or to exercise any of the rights granted in Section 1 herein, and any attempt
to do so except under the terms of this License (or another written agreement
between Licensor and You) is expressly prohibited by U.S. copyright law, the
equivalent laws of other countries, and by international treaty. Therefore, by
exercising any of the rights granted to You in Section 1 herein, You indicate
Your acceptance of this License and all of its terms and conditions.
10) Termination for Patent Action. This License shall terminate automatically
and You may no longer exercise any of the rights granted to You by this License
as of the date You commence an action, including a cross-claim or counterclaim,
against Licensor or any licensee alleging that the Original Work infringes a
patent. This termination provision shall not apply for an action alleging
patent infringement by combinations of the Original Work with other software or
hardware.
11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
License may be brought only in the courts of a jurisdiction wherein the
Licensor resides or in which Licensor conducts its primary business, and under
the laws of that jurisdiction excluding its conflict-of-law provisions. The
application of the United Nations Convention on Contracts for the International
Sale of Goods is expressly excluded. Any use of the Original Work outside the
scope of this License or after its termination shall be subject to the
requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq.,
the equivalent laws of other countries, and international treaty. This section
shall survive the termination of this License.
12) Attorneys Fees. In any action to enforce the terms of this License or
seeking damages relating thereto, the prevailing party shall be entitled to
recover its costs and expenses, including, without limitation, reasonable
attorneys' fees and costs incurred in connection with such action, including
any appeal of such action. This section shall survive the termination of this
License.
13) Miscellaneous. This License represents the complete agreement concerning
the subject matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent necessary to
make it enforceable.
14) Definition of "You" in This License. "You" throughout this License, whether
in upper or lower case, means an individual or a legal entity exercising rights
under, and complying with all of the terms of, this License. For legal
entities, "You" includes any entity that controls, is controlled by, or is
under common control with you. For 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.
15) Right to Use. You may use the Original Work in all ways not otherwise
restricted or conditioned by this License or by law, and Licensor promises not
to interfere with or be responsible for such uses by You.
This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved.
Permission is hereby granted to copy and distribute this license without
modification. This license may not be modified without the express written
permission of its copyright owner.
--
END OF ACADEMIC FREE LICENSE. The following is intended to describe the
essential differences between the Academic Free License (AFL) version 1.0 and
other open source licenses:
The Academic Free License is similar to the BSD, MIT, UoI/NCSA and Apache
licenses in many respects but it is intended to solve a few problems with those
licenses.
* The AFL is written so as to make it clear what software is being
licensed (by the inclusion of a statement following the copyright notice in the
software). This way, the license functions better than a template license. The
BSD, MIT and UoI/NCSA licenses apply to unidentified software.
* The AFL contains a complete copyright grant to the software. The BSD
and Apache licenses are vague and incomplete in that respect.
* The AFL contains a complete patent grant to the software. The BSD, MIT,
UoI/NCSA and Apache licenses rely on an implied patent license and contain no
explicit patent grant.
* The AFL makes it clear that no trademark rights are granted to the
licensor's trademarks. The Apache license contains such a provision, but the
BSD, MIT and UoI/NCSA licenses do not.
* The AFL includes the warranty by the licensor that it either owns the
copyright or that it is distributing the software under a license. None of the
other licenses contain that warranty. All other warranties are disclaimed, as
is the case for the other licenses.
* The AFL is itself copyrighted (with the right granted to copy and distribute
without modification). This ensures that the owner of the copyright to the
license will control changes. The Apache license contains a copyright notice,
but the BSD, MIT and UoI/NCSA licenses do not.
--
START OF GNU LIBRARY GENERAL PUBLIC LICENSE
--
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

Some files were not shown because too many files have changed in this diff Show more