Saturday 3 April 2010

SIP Communicator GSoC 2010 Application Part 4

The Progress

I managed to get JNI to talk to GnomeKeyring via libgnome-keyring. Basically I can store, delete, load passwords, check GK availability and list it's keyrings. Here's the code:
First the java part:

package example;


public class GnomeKeyring {
public native void setApplicationName(String name);
public native String[] getKeyRingNames();
public native boolean isKeyRingAvailable();
public native boolean storePassword(String account, String pass);
public native boolean deletePassword(String account);
public native String loadPassword(String account);

static {
System.loadLibrary("gk-native");
}

public GnomeKeyring(String appName) {
setApplicationName(appName);
}

public static void main(String[] args) {
String libPath = System.getProperty("java.library.path");
System.out.println("java.library.path = " + libPath);

GnomeKeyring gk = new GnomeKeyring("SIP Communicator");

System.out.println("Keyring available? " + gk.isKeyRingAvailable());
System.out.println("Keyrings: ");
for (String s : gk.getKeyRingNames()) {
System.out.println(s);
}
if (gk.storePassword("dmitri@msn.com", "secret")) {
System.out.println("Password stored OK");
}
System.out.println("Pass found: " + gk.loadPassword("dmitri@msn.com"));
if (gk.deletePassword("dmitri@msn.com")) {
System.out.println("Password deleted OK");
}
}

}


Pretty simple, it loads the custom shared library gk-native and calls native methods.

The C part is bigger:


#include <jni.h>
#include <stdio.h>
#include <gnome-keyring.h>
#include <glib.h>
#include <libintl.h>
#include "GnomeKeyring.h"

JNIEXPORT jstring JNICALL Java_example_GnomeKeyring_loadPassword
(JNIEnv *env, jobject obj, jstring jaccount) {
gchar *password;
jstring jpass = NULL;
const char *account = (*env)->GetStringUTFChars(env, jaccount, 0);
GnomeKeyringResult result = gnome_keyring_find_password_sync(GNOME_KEYRING_NETWORK_PASSWORD,
&password,
"user", account,
/* Can put other properties here that
* GNOME_KEYRING_NETWORK_PASSWORD schema supports.
*/
NULL
);
(*env)->ReleaseStringUTFChars(env, jaccount, account);

if (result == GNOME_KEYRING_RESULT_OK) {
jpass = (*env)->NewStringUTF(env, password);
}

gnome_keyring_free_password(password);
return jpass;
}

JNIEXPORT jboolean JNICALL Java_example_GnomeKeyring_deletePassword
(JNIEnv *env, jobject obj, jstring jaccount) {
const char *account = (*env)->GetStringUTFChars(env, jaccount, 0);
GnomeKeyringResult result = gnome_keyring_delete_password_sync(GNOME_KEYRING_NETWORK_PASSWORD,
"user", account,
/* Can put other properties here that
* GNOME_KEYRING_NETWORK_PASSWORD schema supports.
*/
NULL
);
(*env)->ReleaseStringUTFChars(env, jaccount, account);

return result == GNOME_KEYRING_RESULT_OK ? TRUE : FALSE;
}

JNIEXPORT jboolean JNICALL Java_example_GnomeKeyring_storePassword
(JNIEnv *env, jobject obj, jstring jaccount, jstring jpass) {
const char *account = (*env)->GetStringUTFChars(env, jaccount, 0);
const char *pass = (*env)->GetStringUTFChars(env, jpass, 0);
GnomeKeyringResult result = gnome_keyring_store_password_sync(GNOME_KEYRING_NETWORK_PASSWORD,
NULL,
"My Password",
pass,
"user", account,
/* Can put other properties here that
* GNOME_KEYRING_NETWORK_PASSWORD schema supports.
*/
NULL
);
(*env)->ReleaseStringUTFChars(env, jaccount, account);
(*env)->ReleaseStringUTFChars(env, jpass, pass);

return result == GNOME_KEYRING_RESULT_OK ? TRUE : FALSE;
}

JNIEXPORT void JNICALL Java_example_GnomeKeyring_setApplicationName
(JNIEnv *env, jobject obj, jstring name) {
const char *str = (*env)->GetStringUTFChars(env, name, 0);
g_set_application_name(str);
(*env)->ReleaseStringUTFChars(env, name, str);
}

JNIEXPORT jobjectArray JNICALL Java_example_GnomeKeyring_getKeyRingNames
(JNIEnv *env, jobject obj)
{
int i;
char *keyring;
GList *keyrings, *l;
jstring string = NULL;

gnome_keyring_list_keyring_names_sync (&keyrings);
guint len = g_list_length(keyrings);

jclass stringClass = (*env)->FindClass(env,"Ljava/lang/String;");
jobjectArray stringArray = (*env)->NewObjectArray(env, len, stringClass, NULL);
for (l = keyrings, i = 0; l != NULL; l = l->next, i++) {
keyring = l->data;
string = (*env)->NewStringUTF(env, keyring);
(*env)->SetObjectArrayElement(env, stringArray, i, string);
(*env)->DeleteLocalRef(env, string);
}
gnome_keyring_string_list_free(keyrings);

return stringArray;
}

JNIEXPORT jboolean JNICALL Java_example_GnomeKeyring_isKeyRingAvailable
(JNIEnv *env, jobject obj)
{
if(gnome_keyring_is_available()) {
return TRUE;
}
return FALSE;
}


Here I used only "user" property of the GNOME_KEYRING_NETWORK_PASSWORD schema, but other can be used as well, or even new schemas can be created.
Finally the makefile to put it all together:

BIN=bin
PAK=example
CSRC=src/$(PAK)/native

JFILE=GnomeKeyring
CFILE=$(JFILE).c
HFILE=$(JFILE).h
OBJ=$(JFILE).o

LIB=libgk-native.so

all : $(BIN)/$(LIB)

$(BIN)/$(LIB) : $(BIN)/$(OBJ)
gcc -shared -o $(BIN)/$(LIB) $(BIN)/$(OBJ) /usr/lib/libgnome-keyring.so

$(BIN)/$(OBJ) : $(CSRC)/$(CFILE)
gcc -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -I/usr/include/gnome-keyring-1 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -c -fpic $(CSRC)/$(CFILE) -o $(BIN)/$(OBJ)

header : $(BIN)/$(PAK)/$(JFILE).class
javah -jni -classpath bin -o $(CSRC)/$(HFILE) $(PAK).$(JFILE)

run:
java -cp $(BIN) -Djava.library.path=$(BIN) $(PAK).$(JFILE)
clean :
rm $(BIN)/$(OBJ)
rm $(BIN)/$(LIB)



So now I can do everything that's required with GnomeKeyring, next I will try to think of a way to integrate it all into SC.

No comments:

Post a Comment