You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1348 lines
48 KiB
C

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include <utime.h>
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <pi-source.h>
#include <pi-socket.h>
#include <pi-dlp.h>
#include <pi-file.h>
#include <pi-memo.h>
#include "libjpisock.h"
#define MAX_RESOURCE_SIZE 65536
int pilot_connect(JNIEnv * env, const char *port);
static void postPilotLinkException(JNIEnv *, const char *, int, int);
static void postJavaException(JNIEnv *, const char *, const char *);
static int getBasicTypeField(JNIEnv * env, jclass pClass, jobject pObject,
const char * sFieldType, const char * sFieldName, void * pLocation);
static int assignBasicTypeField(JNIEnv * env, jclass pClass, jobject pObject,
const char * sFieldType, const char * sFieldName, ...);
/*
PilotLink.connect
*/
JNIEXPORT jint JNICALL Java_org_gnu_pilotlink_PilotLink_connect
(JNIEnv *env, jobject obj, jstring jprt) {
jint iResult = 0;
const char * port = NULL;
char * prt = NULL;
/* Get working copy of port name */
port = env->GetStringUTFChars(jprt, NULL);
prt = (char *)malloc(strlen(port) + 1);
if (prt != NULL) strcpy(prt, port);
env->ReleaseStringUTFChars(jprt, port);
iResult = pilot_connect(env, prt);
if (prt != NULL) free(prt);
return iResult;
}
/*
ReadAppInfo
*/
JNIEXPORT jobject JNICALL Java_org_gnu_pilotlink_PilotLink_readAppInfo
(JNIEnv *env, jobject obj, jint handle, jint db)
{
/*
unsigned char buffer[MAX_RESOURCE_SIZE];
int size=dlp_ReadAppBlock(handle,db, 0,buffer,MAX_RESOURCE_SIZE);
//printf("STill alive...\n");
//fflush(stdout);
jclass appinfo_cls=env->FindClass("org/gnu/pilotlink/RawAppInfo");
if (appinfo_cls==NULL) {
printf("Class not found! Sysinfo!\n");
return NULL;
}
//printf("STill alive...\n");
fflush(stdout);
jmethodID appinfo_mid=env->GetMethodID(appinfo_cls, "<init>","([B)V");
if (appinfo_mid==NULL) {
printf("Problem mid!\n");
fflush(stdout);
return NULL;
}
//printf("STill alive...\n");
//fflush(stdout);
jbyteArray array=env->NewByteArray(size);
env->SetByteArrayRegion(array,0,(jint)size,(jbyte*)buffer);
jobject appinfo=env->NewObject(appinfo_cls, appinfo_mid, array);
return appinfo;
*/
jclass jClass_appInfo = NULL;
jobject jObject_appInfo = NULL;
jmethodID jMethod_appInfo = NULL;
jbyte * pBuffer = NULL;
int bProceed = 1;
int iNumBytesRead = 0;
if (bProceed) {
/* Allocate memory for maximum data size */
pBuffer = (jbyte *)malloc(MAX_RESOURCE_SIZE);
if (pBuffer == NULL) {
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to allocate buffer for app-info block");
bProceed = 0;
}
}
if (bProceed) {
/* Read app-info block && verify successful read */
iNumBytesRead = dlp_ReadAppBlock(handle, db, 0, MAX_RESOURCE_SIZE, (pi_buffer_t*)pBuffer);
if (iNumBytesRead < 0) {
/* Throw Java exception, iNumBytesRead is actually an error code */
postPilotLinkException(env, "Unable to read app-block", iNumBytesRead, errno);
bProceed = 0;
}
}
if (bProceed) {
/* Look up RawAppInfo class */
jClass_appInfo = env->FindClass("org/gnu/pilotlink/RawAppInfo");
if (jClass_appInfo == NULL) {
/* pending ClassNotFoundException in env */
bProceed = 0;
}
}
if (bProceed) {
/* Look up constructor method with byte array argument */
jMethod_appInfo = env->GetMethodID(jClass_appInfo, "<init>","([B)V");
if (jMethod_appInfo == NULL) {
/* pending NoSuchMethodException in env */
bProceed = 0;
}
}
if (bProceed) {
jbyteArray jArray_buffer = env->NewByteArray(iNumBytesRead);
env->SetByteArrayRegion(jArray_buffer, 0, (jint)iNumBytesRead, pBuffer);
jObject_appInfo = env->NewObject(jClass_appInfo, jMethod_appInfo, jArray_buffer);
}
if (pBuffer != NULL) free(pBuffer);
return jObject_appInfo;
}
/*
readSysInfo
*/
JNIEXPORT jobject JNICALL Java_org_gnu_pilotlink_PilotLink_readSysInfo
(JNIEnv *env, jobject obj, jint handle) {
/*
struct SysInfo s;
s.prodID[s.prodIDLength]=0;
int r=dlp_ReadSysInfo(handle,&s);
jstring prod=env->NewStringUTF(s.prodID);
//printf("STill alive...\n");
fflush(stdout);
jclass sysinfo_cls=env->FindClass("org/gnu/pilotlink/SysInfo");
if (sysinfo_cls==NULL) {
printf("Class not found! Sysinfo!\n");
return NULL;
}
//printf("STill alive...\n");
fflush(stdout);
jmethodID sysinfo_mid=env->GetMethodID(sysinfo_cls, "<init>","(Ljava/lang/String;JJSSSSJ)V");
if (sysinfo_mid==NULL) {
printf("Problem mid!\n");
fflush(stdout);
return NULL;
}
//printf("STill alive...\n");
fflush(stdout);
jobject sysinfo=env->NewObject(sysinfo_cls, sysinfo_mid, prod, s.romVersion, s.locale, s.dlpMajorVersion, s.dlpMinorVersion,s.compatMajorVersion,s.compatMinorVersion,s.maxRecSize);
printf("Returning from getsysinfo...\n");
fflush(stdout);
return sysinfo;
*/
jclass jClass_sysInfo = NULL;
jobject jObject_sysInfo = NULL;
jmethodID jMethod_sysInfo = NULL;
struct SysInfo rSysInfo;
int bProceed = 1;
if (bProceed) {
int iResult;
/* Check that dlp_ReadSysInfo call actually succeeded */
memset(&rSysInfo, 0, sizeof(struct SysInfo));
iResult = dlp_ReadSysInfo(handle, &rSysInfo);
if (iResult < 0) {
/* Throw Java exception in case of failure */
postPilotLinkException(env, "Unable to read SysInfo", iResult, errno);
bProceed = 0;
}
}
if (bProceed) {
/* Look up SysInfo class */
jClass_sysInfo = env->FindClass("org/gnu/pilotlink/SysInfo");
if (jClass_sysInfo == NULL) {
/* pending ClassNotFoundException in env */
bProceed = 0;
}
}
if (bProceed) {
/* Look up constructor method with complete-specification argument */
jMethod_sysInfo = env->GetMethodID(jClass_sysInfo, "<init>",
"(Ljava/lang/String;JJSSSSJ)V");
if (jMethod_sysInfo == NULL) {
/* pending NoSuchMethodException in env */
bProceed = 0;
}
}
if (bProceed) {
/* Explicit casts to jlong are required because env->NewObject() works
very similar to (and probably identical) to printf() and related
procedures which use stdarg.h routines for variable arguments.
The constructor requires a jlong (64 bits) for some fields, but the
corresponding fields in the C struct are of a system-dependent size
(32 bits for an unsigned long in i386). Failure to cast to an appropriate
size results in a stack misalignment which, at the very least, causes
incorrect values to be received at the Java side. For the sake of
completeness, jshort values are explicitly casted too.
*/
jstring jString_prodID = env->NewStringUTF(rSysInfo.prodID);
jObject_sysInfo = env->NewObject(jClass_sysInfo, jMethod_sysInfo,
jString_prodID, (jlong)rSysInfo.romVersion, (jlong)rSysInfo.locale,
(jshort)rSysInfo.dlpMajorVersion, (jshort)rSysInfo.dlpMinorVersion,
(jshort)rSysInfo.compatMajorVersion,
(jshort)rSysInfo.compatMinorVersion, (jlong)rSysInfo.maxRecSize);
}
return jObject_sysInfo;
}
/*
readUserInfo
*/
JNIEXPORT jobject JNICALL Java_org_gnu_pilotlink_PilotLink_readUserInfo
(JNIEnv *env, jobject obj, jint handler) {
/*
struct PilotUser U;
dlp_ReadUserInfo(handler, &U);
U.username[127]=0;
U.password[U.passwordLength]=0;
printf("Last sync-->%ld\n",U.lastSyncDate);
printf("Last ssync->%ld\n",U.successfulSyncDate);
jstring str_name=env->NewStringUTF(U.username);
if (str_name==NULL) {
return NULL;
}
jstring str_pw=env->NewStringUTF(U.password);
if (str_pw==NULL) {
return NULL;
}
jlong vid=U.viewerID;
jlong uid=U.userID;
jlong lspc=U.lastSyncPC;
jclass calclass=env->FindClass("java/util/Date");
if (calclass==NULL) {
return NULL;
}
jmethodID cal_mid=env->GetMethodID(calclass,"<init>","(J)V");
if (cal_mid==NULL){
return NULL;
}
jobject lsd_date=env->NewObject(calclass,cal_mid,U.lastSyncDate*1000);
jobject sucd_date=env->NewObject(calclass,cal_mid,U.successfulSyncDate*1000);
jclass usercls=env->FindClass("org/gnu/pilotlink/User");
if (usercls==NULL) {
printf("USERCLASS not found!\n");
return NULL;
} else {
printf("ok...\n");
}
jmethodID umid=env->GetMethodID(usercls,"<init>","(Ljava/lang/String;Ljava/lang/String;JJJLjava/util/Date;Ljava/util/Date;)V");
if (umid==NULL) {
printf("MethodID not found!\n");
return NULL;
} else {
printf("ok...\n");
}
//printf("Returning from getuserinfo...\n");
jobject u=env->NewObject(usercls,umid,str_name,str_pw,uid,vid,lspc,lsd_date, sucd_date);
return u;
*/
jclass jClass_user = NULL;
jobject jObject_user = NULL;
jmethodID jMethod_user = NULL;
struct PilotUser rUserInfo;
int bProceed = 1;
if (bProceed) {
int iResult;
/* Check that dlp_ReadUserInfo call actually succeeded */
memset(&rUserInfo, 0, sizeof(struct PilotUser));
iResult = dlp_ReadUserInfo(handler, &rUserInfo);
if (iResult < 0) {
/* Throw Java exception in case of failure */
postPilotLinkException(env, "Unable to read UserInfo", iResult, errno);
bProceed = 0;
} else {
/* This was taken from previous code... */
rUserInfo.username[sizeof(rUserInfo.username) - 1] = '\0';
rUserInfo.password[rUserInfo.passwordLength] = '\0';
}
}
if (bProceed) {
/* Look up User class */
jClass_user = env->FindClass("org/gnu/pilotlink/User");
if (jClass_user == NULL) {
/* pending ClassNotFoundException in env */
bProceed = 0;
}
}
if (bProceed) {
/* Look up constructor method with complete-specification argument.
NOTE: a new constructor was provided in User.java in order to
avoid having to create Date objects in C code, AND to fix a subtle
bug in which the multiplication of time_t * int (miliseconds since
Epoch) silently overflows because both time_t and int are 32-bit,
and the result is NOT promoted to at least 64 bits, required for
the constructor Date(long).
*/
jMethod_user = env->GetMethodID(jClass_user, "<init>",
"(Ljava/lang/String;Ljava/lang/String;JJJJJ)V");
if (jMethod_user == NULL) {
/* pending NoSuchMethodException in env */
bProceed = 0;
}
}
if (bProceed) {
/* Explicit casts added - see object creation at
Java_org_gnu_pilotlink_PilotLink_readSysInfo() for explanation. */
jstring jString_username = env->NewStringUTF(rUserInfo.username);
jstring jString_password = env->NewStringUTF(rUserInfo.password);
jObject_user = env->NewObject(jClass_user, jMethod_user, jString_username,
jString_password, (jlong)rUserInfo.userID, (jlong)rUserInfo.viewerID,
(jlong)rUserInfo.lastSyncPC, (jlong)rUserInfo.lastSyncDate,
(jlong)rUserInfo.successfulSyncDate);
}
return jObject_user;
}
/*
writeUserInfo
*/
JNIEXPORT void JNICALL Java_org_gnu_pilotlink_PilotLink_writeUserInfo
(JNIEnv *env, jobject obj, jint so, jobject user) {
/*
printf("Not implemented yet...sorry\n");
*/
/* Now it IS implemented... ;-) */
jclass jClass_user = NULL;
jmethodID jMethod_user = NULL;
struct PilotUser rUserInfo;
jlong jTempValue;
jstring jTempString;
int bProceed = 1;
/* Set everything not explicitly assigned to blanks */
memset(&rUserInfo, 0, sizeof(struct PilotUser));
/* Get object class for user... this should not fail */
jClass_user = env->GetObjectClass(user);
/* Assign all of the basic fields */
if (bProceed) {
bProceed = getBasicTypeField(env, jClass_user, user,
"J", "userid", &jTempValue);
rUserInfo.userID = jTempValue;
}
if (bProceed) {
bProceed = getBasicTypeField(env, jClass_user, user,
"J", "viewerid", &jTempValue);
rUserInfo.viewerID = jTempValue;
}
if (bProceed) {
bProceed = getBasicTypeField(env, jClass_user, user,
"J", "lastSyncPC", &jTempValue);
rUserInfo.lastSyncPC = jTempValue;
}
if (bProceed) {
jTempString = NULL;
bProceed = getBasicTypeField(env, jClass_user, user,
"Ljava/lang/String;", "name", &jTempString);
if (bProceed && jTempString != NULL) {
const char * sTempString = env->GetStringUTFChars(jTempString, 0);
strncpy(rUserInfo.username, sTempString, sizeof(rUserInfo.username) - 1);
rUserInfo.username[sizeof(rUserInfo.username) - 1] = '\0';
env->ReleaseStringUTFChars(jTempString, sTempString);
}
}
if (bProceed) {
jTempString = NULL;
bProceed = getBasicTypeField(env, jClass_user, user,
"Ljava/lang/String;", "password", &jTempString);
if (bProceed && jTempString != NULL) {
const char * sTempString = env->GetStringUTFChars(jTempString, 0);
strncpy(rUserInfo.password, sTempString, sizeof(rUserInfo.password) - 1);
rUserInfo.password[sizeof(rUserInfo.password) - 1] = '\0';
rUserInfo.passwordLength = strlen(rUserInfo.password);
env->ReleaseStringUTFChars(jTempString, sTempString);
}
}
/* In order to get the correct time_t, a function call is needed. The methods
User.getLastSyncDate_time_t() and User.getLastSuccessfulSyncDate_time_t()
were created for this purpose.
*/
if (bProceed) {
jMethod_user = env->GetMethodID(jClass_user, "getLastSyncDate_time_t",
"()J");
if (jMethod_user == NULL) {
/* pending NoSuchMethodException in env */
bProceed = 0;
} else {
/* Use Date.getTime() in Java side and divide by 1000 */
rUserInfo.lastSyncDate = env->CallLongMethod(user, jMethod_user);
}
}
if (bProceed) {
jMethod_user = env->GetMethodID(jClass_user, "getLastSuccessfulSyncDate_time_t",
"()J");
if (jMethod_user == NULL) {
/* pending NoSuchMethodException in env */
bProceed = 0;
} else {
/* Use Date.getTime() in Java side and divide by 1000 */
rUserInfo.successfulSyncDate = env->CallLongMethod(user, jMethod_user);
}
}
/* Write user info if all assignments were successful */
if (bProceed) {
int iResult = dlp_WriteUserInfo(so, &rUserInfo);
if (iResult < 0) {
postPilotLinkException(env, "Unable to write UserInfo", iResult, errno);
}
}
}
/*
* writeAppBlock
*/
JNIEXPORT int JNICALL Java_org_gnu_pilotlink_PilotLink_writeAppBlock
(JNIEnv *env, jobject obj, jint handle, jint dbhandle, jbyteArray data, jint length) {
/*
char buffer[MAX_RESOURCE_SIZE];
env->GetByteArrayRegion(data,0,length,(jbyte*)buffer);
return dlp_WriteAppBlock(handle,dbhandle,buffer,length);
*/
jbyte * buffer;
int iResult = 0;
/* Allocate memory for copy of app block */
if ((buffer = (jbyte *)malloc(length * sizeof(jbyte))) != NULL) {
env->GetByteArrayRegion(data, 0, length, buffer);
iResult = dlp_WriteAppBlock(handle, dbhandle, buffer, length);
if (iResult < 0) {
/* Throw Java exception to signal error */
postPilotLinkException(env, "Unable to write app-block", iResult, errno);
}
free(buffer);
} else {
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to allocate memory for app block");
}
return iResult;
}
/*
openConduit
*/
JNIEXPORT void JNICALL Java_org_gnu_pilotlink_PilotLink_openConduit
(JNIEnv *env, jobject obj, jint handle) {
int iResult = dlp_OpenConduit(handle);
if (iResult < 0) postPilotLinkException(env, "Unable to open conduit", iResult, errno);
}
/*
* createDB
*/
JNIEXPORT jint JNICALL Java_org_gnu_pilotlink_PilotLink_createDB
(JNIEnv *env, jobject obj, jint handle, jlong creator, jstring jdbname, jlong type, jint flags, jint version)
{
jint db = -1;
/* Get working copy of database name */
const char * dbname = env->GetStringUTFChars(jdbname, NULL);
char * dbn = (char *)malloc(strlen(dbname) + 1);
if (dbn != NULL) strcpy(dbn, dbname);
env->ReleaseStringUTFChars(jdbname, dbname);
if (dbn != NULL) {
int ret = dlp_CreateDB(handle,creator,type,0,flags,version,dbn, &db);
if (ret < 0) {
/* debug message replaced by Java exception */
/*
printf("Error creating db %s: %d\n",dbn, ret);
*/
postPilotLinkException(env, "Could not create database",
ret, errno);
}
free(dbn);
} else {
/* Unable to create copy - memory heap may be corrupted */
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to create working copy of database name");
}
return db;
}
/*
* deleteDB
*/
JNIEXPORT jint JNICALL Java_org_gnu_pilotlink_PilotLink_deleteDB
(JNIEnv *env, jobject obj, jint handle, jstring jdbname) {
int ret = 0;
/* Get working copy of database name */
const char * dbname = env->GetStringUTFChars(jdbname,NULL);
char * dbn = (char*)malloc(strlen(dbname)+1);
if (dbn != NULL) strcpy(dbn,dbname);
env->ReleaseStringUTFChars(jdbname, dbname);
if (dbn != NULL) {
ret = dlp_DeleteDB(handle,0,dbn);
if (ret < 0) {
/* debug message replaced by Java exception */
/*
printf("Error deleting db %s %d:\n",dbn,ret);
*/
postPilotLinkException(env, "Could not delete database",
ret, errno);
}
free(dbn);
} else {
/* Unable to create copy - memory heap may be corrupted */
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to create working copy of database name");
}
return ret;
}
JNIEXPORT jobject JNICALL Java_org_gnu_pilotlink_PilotLink_getAppInfoBlock(JNIEnv *env,jobject obj, jint handle,jstring jdbname) {
int db;
const char * dbname = env->GetStringUTFChars(jdbname, NULL);
char * dbn = (char *)malloc(strlen(dbname) + 1);
if (dbn != NULL) strcpy(dbn, dbname);
env->ReleaseStringUTFChars(jdbname, dbname);
if (dlp_OpenDB(handle,0,0x80|0x40,dbn,&db)<0) {
printf("Fehler!");
return NULL;
}
jbyte buff[0xffff];
int l=dlp_ReadAppBlock(handle,db,0,0xffff,(pi_buffer_t*)&buff);
printf("read app-Block of size %d\n",l);
fflush(stdout);
jclass jClass_appInfo = NULL;
jobject jObject_appInfo = NULL;
jmethodID jMethod_appInfo = NULL;
int bProceed = 1;
int iNumBytesRead = 0;
if (bProceed) {
/* Look up RawAppInfo class */
jClass_appInfo = env->FindClass("org/gnu/pilotlink/RawAppInfo");
if (jClass_appInfo == NULL) {
/* pending ClassNotFoundException in env */
bProceed = 0;
}
}
if (bProceed) {
/* Look up constructor method with byte array argument */
jMethod_appInfo = env->GetMethodID(jClass_appInfo, "<init>","([B)V");
if (jMethod_appInfo == NULL) {
/* pending NoSuchMethodException in env */
bProceed = 0;
}
}
if (bProceed) {
jbyteArray jArray_buffer = env->NewByteArray(l);
env->SetByteArrayRegion(jArray_buffer, 0, (jint)l, buff);
jObject_appInfo = env->NewObject(jClass_appInfo, jMethod_appInfo, jArray_buffer);
}
dlp_CloseDB(handle,db);
return jObject_appInfo;
}
/*
openDB
*/
JNIEXPORT jint JNICALL Java_org_gnu_pilotlink_PilotLink_openDB
(JNIEnv *env, jobject obj, jint handle, jstring jdbname) {
jint db = 0;
/* Get working copy of database name */
const char* dbname = env->GetStringUTFChars(jdbname,NULL);
char* dbn = (char*)malloc(strlen(dbname)+1);
if (dbn != NULL) strcpy(dbn,dbname);
env->ReleaseStringUTFChars(jdbname, dbname);
if (dbn != NULL) {
int ret=dlp_OpenDB(handle,0,dlpOpenReadWrite,dbn,&db);
if (ret < 0) {
/*
printf("Error opening db %s: %d\n",dbn, ret);
*/
postPilotLinkException(env, "Could not open database",
ret, errno);
return (jint)ret;
}
} else {
/* Unable to create copy - memory heap may be corrupted */
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to create working copy of database name");
}
return db;
}
/*
getRecordCount
*/
JNIEXPORT jint JNICALL Java_org_gnu_pilotlink_PilotLink_getRecordCount
(JNIEnv *env, jobject obj, jint handle, jint dbh) {
jint num;
int iResult;
iResult = dlp_ReadOpenDBInfo(handle,dbh,&num);
if (iResult < 0) {
postPilotLinkException(env, "Could not get record count for database",
iResult, errno);
}
return num;
}
/*
getRecordByIndex
*/
JNIEXPORT jobject JNICALL Java_org_gnu_pilotlink_PilotLink_getRecordByIndex
(JNIEnv *env, jobject obj, jint handle , jint db , jint idx) {
jbyte buffer[MAX_RESOURCE_SIZE];
recordid_t id;
jint size, attr, category;
//printf("Getting record..\n");
int ret = dlp_ReadRecordByIndex(handle, db, idx, (pi_buffer_t*)buffer,
&id, &attr, &category);
if (ret<0) {
postPilotLinkException(env,"Error reading database by index",ret,errno);
return NULL;
}
//printf("getting class!\n");
jclass rcls=env->FindClass("org/gnu/pilotlink/RawRecord");
if (rcls==NULL) {
return NULL;
}
jmethodID rid=env->GetMethodID(rcls,"<init>","([BJIII)V");
if (rid==NULL) {
printf("jmethodID is null!\n");
return NULL;
}
jbyteArray array=env->NewByteArray(size);
env->SetByteArrayRegion(array,0,size,buffer);
jobject record=env->NewObject(rcls, rid, array, (jlong)id,size,attr,category );
return record;
/*jbyte * buffer;
jobject jObject_RawRecord = NULL;
if ((buffer = (jbyte *)malloc(MAX_RESOURCE_SIZE)) != NULL) {
recordid_t id;
jint iRecSize, iRecAttr, iRecCategory;
jclass jClass_RawRecord;
jmethodID jMethod_RawRecord;
int iResult = dlp_ReadRecordByIndex(handle, db, idx, buffer,
&id, &iRecSize, &iRecAttr, &iRecCategory);
if (iResult < 0) {
postPilotLinkException(env, "Could not read database record by index",
iResult, errno);
} else if ((jClass_RawRecord = env->FindClass(
"org/gnu/pilotlink/RawRecord")) == NULL) {
} else if ((jMethod_RawRecord = env->GetMethodID(jClass_RawRecord,
"<init>", "([BJIII)V")) == NULL) {
} else {
jbyteArray jArray_buffer = env->NewByteArray(iRecSize);
env->SetByteArrayRegion(jArray_buffer, 0, iRecSize, buffer);
jObject_RawRecord = env->NewObject(jClass_RawRecord, jMethod_RawRecord,
jArray_buffer, (jlong)id, (jint)iRecSize, (jint)iRecAttr, (jint)iRecCategory);
}
free(buffer);
} else {
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to allocate buffer for record data");
}
return jObject_RawRecord;*/
}
/*
deleteRecordById
*/
JNIEXPORT jint JNICALL Java_org_gnu_pilotlink_PilotLink_deleteRecordById
(JNIEnv *env, jobject obj, jint handle, jint db, jlong id) {
int ret=dlp_DeleteRecord(handle,db,0,id);
if (ret<0) {
postPilotLinkException(env,"Deletition not possible!",ret,errno);
}
return ret;
}
/* Write Record
*/
JNIEXPORT jint JNICALL Java_org_gnu_pilotlink_PilotLink_writeRecord
(JNIEnv *env, jobject obj, jint handle, jint db, jobject record) {
jlong id=0;
jclass cls=env->GetObjectClass(record);
jmethodID mid=env->GetMethodID(cls,"getCategory","()I");
if (mid==NULL) { printf("Error getting mid!"); return -1; }
jint cat=env->CallIntMethod(record,mid);
jmethodID mid2=env->GetMethodID(cls,"getId","()J");
id=env->CallLongMethod(record,mid2, NULL);
if (id==0) {
printf("Creating new entry!\n");
}
mid=env->GetMethodID(cls,"getAttribs","()I");
jint attr=env->CallIntMethod(record,mid);
mid=env->GetMethodID(cls,"getSize","()I");
jint size=env->CallIntMethod(record,mid);
printf("Got size: %d\n",size);
char buffer[MAX_RESOURCE_SIZE];
mid=env->GetMethodID(cls,"getBuffer","()[B");
jbyteArray arr=(jbyteArray)env->CallObjectMethod(record,mid);
env->GetByteArrayRegion(arr,0,size,(jbyte*)buffer);
recordid_t i=0;
int ret=dlp_WriteRecord(handle,db,attr, id, cat, buffer,size,&i);
if (id==0 && ret>0) {
mid=env->GetMethodID(cls,"setId","(J)V");
env->CallVoidMethod(record,mid,(jlong)i);
}
return ret;
}
/*CloseDB*/
JNIEXPORT void JNICALL Java_org_gnu_pilotlink_PilotLink_closeDB
(JNIEnv *env, jobject obj, jint han, jint db) {
int bException = 0;
int ret=dlp_CleanUpDatabase(han, db);
if (ret<0) {
// printf("Error cleaning up! %d\n",ret);
postPilotLinkException(env, "Unable to clean up before database close",
ret, errno);
bException = 1;
}
ret=dlp_CloseDB(han, db);
if (ret < 0 && !bException) {
// printf("Error closing DB: %d\n",ret);
postPilotLinkException(env, "Unable to close database",
ret, errno);
}
}
/*ENDSync*/
JNIEXPORT void JNICALL Java_org_gnu_pilotlink_PilotLink_endSync
(JNIEnv *env, jobject obj, jint sd) {
int iResult = dlp_EndOfSync(sd, dlpEndCodeNormal);
if (iResult < 0) postPilotLinkException(env, "Unable to signal endSync",
iResult, errno);
}
/*Close*/
JNIEXPORT void JNICALL Java_org_gnu_pilotlink_PilotLink_close
(JNIEnv *env, jobject obj, jint sd) {
pi_close(sd);
}
/*pilot-connect*/
int pilot_connect(JNIEnv * env, const char *port)
{
int parent_sd = -1, /* Client socket, formerly sd */
client_sd = -1, /* Parent socket, formerly sd2 */
result;
struct pi_sockaddr addr;
struct stat attr;
struct SysInfo sys_info;
const char *defport = "/dev/pilot";
int bProceed = 1;
if (port == NULL && (port = getenv("PILOTPORT")) == NULL) {
/* err seems to be used for stat() only */
int err = 0;
/* Commented out debug code */
/*
fprintf(stderr, " No $PILOTPORT specified and no -p "
"<port> given.\n"
" Defaulting to '%s'\n", defport);
*/
port = defport;
err = stat(port, &attr);
/* Moved err check inside if() block - err only meaningful here */
if (err) {
/* *BAD* practice - cannot recover from within Java if exit() here.
Should create && throw exception instead.
*/
/*
fprintf(stderr, " ERROR: %s (%d)\n\n", strerror(errno), errno);
fprintf(stderr, " Error accessing: '%s'. Does '%s' exist?\n",
port, port);
//fprintf(stderr, " Please use --help for more information\n\n");
exit(1);
*/
/* Throw an exception - FileNotFoundException seems appropriate here */
postJavaException(env, "java/io/FileNotFoundException", strerror(errno));
bProceed = 0;
}
}
/* At this point, either bProceed is 0, or port != NULL, further checks are unnecesary */
/* Check bProceed to account for previous exceptions */
if (bProceed && !(parent_sd = pi_socket(PI_AF_PILOT, PI_SOCK_STREAM, PI_PF_DLP))) {
/*
fprintf(stderr, "\n Unable to create socket '%s'\n",
port ? port : getenv("PILOTPORT"));
return -1;
*/
/* Throw exception here to inform nature of connection failure. */
const char * sTemplate = "Unable to create socket '%s'";
char * sMessage = (char *)malloc(strlen(sTemplate) + strlen(port) + 1);
if (sMessage != NULL) sprintf(sMessage, sTemplate, port);
postJavaException(env, "org/gnu/pilotlink/PilotLinkException",
(sMessage != NULL) ? sMessage : port);
if (sMessage != NULL) free(sMessage);
bProceed = 0;
}
/* Check bProceed to account for previous exceptions */
if (bProceed) {
/* Removed check for port != NULL, since port was validated before */
/*
if (port != NULL) {
*/
result =
pi_bind(parent_sd, port);
/*
} else {
result = pi_bind(parent_sd, NULL, 0);
}
*/
}
if (bProceed && result < 0) {
int save_errno = errno;
/*
const char *portname;
portname = (port != NULL) ? port : getenv("PILOTPORT");
if (portname) {
fprintf(stderr, "\n");
errno = save_errno;
fprintf(stderr, " ERROR: %s (%d)\n\n", strerror(errno),
errno);
if (errno == 2) {
fprintf(stderr, " The device %s does not exist..\n",
portname);
fprintf(stderr, " Possible solution:\n\n\tmknod %s c "
"<major> <minor>\n\n", portname );
} else if (errno == 13) {
fprintf(stderr, " Please check the "
"permissions on %s..\n", portname );
fprintf(stderr, " Possible solution:\n\n\tchmod 0666 "
"%s\n\n", portname );
} else if (errno == 19) {
fprintf(stderr, " Press the HotSync button first and "
"relaunch this conduit..\n\n");
} else if (errno == 21) {
fprintf(stderr, " The port specified must contain a "
"device name, and %s was a directory.\n"
" Please change that to reference a real "
"device, and try again\n\n", portname );
}
fprintf(stderr, " Unable to bind to port: %s\n",
portname) ;
fprintf(stderr, " Please use --help for more "
"information\n\n");
} else
fprintf(stderr, "\n No port specified\n");
*/
const char * sTemplate = "Unable to bind to port %s - (%d) %s%s";
const char * sFailureReason;
char * sMessage;
switch (save_errno) {
case 2:
sFailureReason = "; Device does not exist (use mknod to fix)";
break;
case 13:
sFailureReason = "; Access denied on device (use chmod to fix)";
break;
case 19:
sFailureReason = "; HotSync button must be pressed first";
break;
case 21:
sFailureReason = "; Device name appears to be a directory";
break;
default:
sFailureReason = "";
break;
}
sMessage = (char *)malloc(strlen(sTemplate) + strlen(port) + 16 +
strlen(strerror(save_errno)) + strlen(sFailureReason));
if (sMessage != NULL) {
sprintf(sMessage, sTemplate, port, save_errno, strerror(save_errno), sFailureReason);
postJavaException(env, "org/gnu/pilotlink/PilotLinkException", sMessage);
free(sMessage);
} else {
/* Unable to malloc(), inform of errno string */
postJavaException(env, "org/gnu/pilotlink/PilotLinkException", strerror(save_errno));
}
pi_close(parent_sd);
pi_close(client_sd);
// return -1;
bProceed = 0;
}
/* Removed debug message, maybe add notification framework to invoke here
fprintf(stderr,
"\n Listening to port: %s\n\n Please press the HotSync "
"button now... ",
port ? port : getenv("PILOTPORT"));
*/
/* Check bProceed to account for previous exceptions */
if (bProceed && pi_listen(parent_sd, 1) == -1) {
/* debug message replaced with Java exception */
/* fprintf(stderr, "\n Error listening on %s\n", port); */
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to listen on port");
pi_close(parent_sd);
pi_close(client_sd);
/* return -1; */
bProceed = 0;
}
/* Check bProceed to account for previous exceptions */
if (bProceed) {
client_sd = pi_accept_to(parent_sd, 0, 0, 5);
if (client_sd == -1) {
/* debug message replaced with Java exception */
/* fprintf(stderr, "\n Error accepting data on %s\n", port); */
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to accept data on port");
pi_close(parent_sd);
pi_close(client_sd);
/* return -1;*/
bProceed = 0;
} else {
int so_timeout = 16;
size_t sizeof_so_timeout = sizeof(so_timeout);
pi_setsockopt(client_sd, PI_LEVEL_DEV, PI_DEV_TIMEOUT,
&so_timeout, &sizeof_so_timeout);
}
}
/* Removed debug message, maybe add notification framework to invoke here */
/* fprintf(stderr, "Connected\n\n"); */
/* Check bProceed to account for previous exceptions */
if (bProceed) {
int iResult;
int iNumRetries = 5;
while (iNumRetries > 0 && (iResult = dlp_ReadSysInfo(client_sd, &sys_info)) < 0)
iNumRetries--;
if (iResult < 0) {
/* debug message replaced with Java exception */
/* fprintf(stderr, "\n Error read system info on %s\n", port); */
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to read system info on port");
pi_close(parent_sd);
pi_close(client_sd);
/* return -1; */
bProceed = 0;
}
}
/* Removed debug message, maybe add notification framework to invoke here */
/* printf("Opening counduit...\n"); */
dlp_OpenConduit(client_sd);
/* Why should parent_sd remain open after connect? Nobody receives it. */
pi_close(parent_sd);
return client_sd;
}
/*
* getResourceByIndex()
*/
JNIEXPORT jobject JNICALL Java_org_gnu_pilotlink_PilotLink_getResourceByIndex
(JNIEnv * env, jobject obj, jint iSockHandle, jint iDBHandle, jint iRsrcIndex) {
unsigned long iRsrcType; /* Resource type */
int iRsrcID; /* Resource ID */
int iRsrcSize; /* Actual resource size */
jbyte * pRsrcData; /* Buffer for resource data */
int iResult; /* Result of library call */
jobject pRecordObject = NULL;
/* Get "enough" memory for incoming resource data */
if ((pRsrcData = (jbyte *)malloc(MAX_RESOURCE_SIZE * sizeof(jbyte))) != NULL) {
/* Invoke C library function */
iResult = dlp_ReadResourceByIndex(iSockHandle, iDBHandle, iRsrcIndex,
(pi_buffer_t*)pRsrcData, &iRsrcType, &iRsrcID);
if (iResult >= 0) {
jclass pRecordClass;
jmethodID pRecordConstructor;
/* Look up class and constructor method */
if ((pRecordClass = env->FindClass("org/gnu/pilotlink/RawRecord")) != NULL &&
(pRecordConstructor = env->GetMethodID(pRecordClass, "<init>",
"([BJIII)V")) != NULL ) {
/* Fill a Java array with resource data && invoke constructor */
jbyteArray pJavaArray = env->NewByteArray(iRsrcSize);
env->SetByteArrayRegion(pJavaArray, 0, iRsrcSize, pRsrcData);
pRecordObject = env->NewObject(pRecordClass, pRecordConstructor,
pJavaArray, (jlong)iRsrcID, (jint)iRsrcSize, (jint)0, (jint)iRsrcType);
}
} else {
postPilotLinkException(env, "Unable to read resource by index", iResult, errno);
}
free(pRsrcData);
} else {
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to allocate buffer for copy of resource");
}
return pRecordObject;
}
/*
* writeResource()
*/
JNIEXPORT void JNICALL Java_org_gnu_pilotlink_PilotLink_writeResource
(JNIEnv * env, jobject obj, jint iSockHandle, jint iDBHandle, jobject pRecord)
{
jlong iRsrcID; /* Resource ID for record */
jint iRsrcType; /* Resource type for record */
jint iRsrcSize; /* Actual resource size */
jbyte * pRsrcData = NULL; /* Buffer for resource data */
jclass pRecordClass; /* Java class for record */
jmethodID pRecordMethod; /* Java instance method for record */
jbyteArray pDataArray; /* Java array for resource data */
jint iResult = -1; /* Result of library call */
int bProceed = 1;
/* Get reference to record class */
pRecordClass = env->GetObjectClass(pRecord);
/* Find out required attributes for resource write */
if (bProceed) {
/* Find out category (resource type) */
if ((pRecordMethod = env->GetMethodID(pRecordClass, "getCategory", "()I")) != NULL) {
iRsrcType = env->CallIntMethod(pRecord, pRecordMethod);
} else {
/* Method lookup failed */
bProceed = 0;
}
}
if (bProceed) {
/* Find out resource ID */
if ((pRecordMethod = env->GetMethodID(pRecordClass, "getId", "()J")) != NULL) {
iRsrcID = env->CallLongMethod(pRecord, pRecordMethod);
} else {
/* Method lookup failed */
bProceed = 0;
}
}
if (bProceed) {
/* Find out resource size && allocate memory */
if ((pRecordMethod = env->GetMethodID(pRecordClass, "getSize", "()I")) != NULL) {
iRsrcSize = env->CallIntMethod(pRecord, pRecordMethod);
if (iRsrcSize > 0) pRsrcData = (jbyte *)malloc(iRsrcSize * sizeof(char));
if (pRsrcData == NULL) {
postJavaException(env,
"org/gnu/pilotlink/PilotLinkException",
"Unable to allocate buffer for copy of resource");
bProceed = 0;
}
} else {
/* Method lookup failed */
bProceed = 0;
}
}
if (bProceed) {
/* Get copy of resource data in allocated memory */
if ((pRecordMethod = env->GetMethodID(pRecordClass, "getBuffer", "()[B")) != NULL) {
pDataArray = (jbyteArray)env->CallObjectMethod(pRecord, pRecordMethod);
env->GetByteArrayRegion(pDataArray, 0, iRsrcSize, pRsrcData);
iResult = dlp_WriteResource(iSockHandle, iDBHandle, iRsrcType, iRsrcID,
pRsrcData, iRsrcSize);
if (iResult < 0) {
postPilotLinkException(env, "Unable to write resource", iResult, errno);
}
} else {
/* Method lookup failed */
bProceed = 0;
}
}
if (pRsrcData != NULL) free(pRsrcData);
}
JNIEXPORT void JNICALL Java_org_gnu_pilotlink_PilotLink_resetSystem
(JNIEnv * env, jobject, jint iSockHandle)
{
int iResult = dlp_ResetSystem(iSockHandle);
if (iResult < 0) {
postPilotLinkException(env, "Unable to reset system", iResult, errno);
}
}
/*
* readDBList
*/
JNIEXPORT jobject JNICALL Java_org_gnu_pilotlink_PilotLink_readDBList
(JNIEnv * env, jobject, jint iSockHandle, jint cardno, jint flags, jint start)
{
int iResult = 0;
struct DBInfo rInfoDB;
jobject pDBInfoObject = NULL;
/* Execute low-level library call... */
iResult = dlp_ReadDBList(iSockHandle, cardno, flags, start, (pi_buffer_t*)&rInfoDB);
if (iResult >= 0) {
jclass pDBInfoClass = NULL;
jmethodID pDBInfoMethod = NULL;
int bProceed = 1;
/* Find class for DBInfo - throws ClassNotFoundException if not found */
if (bProceed) {
pDBInfoClass = env->FindClass("org/gnu/pilotlink/DBInfo");
if (pDBInfoClass == NULL) bProceed = 0;
}
/* Find constructor method for class DBInfo */
if (bProceed) {
pDBInfoMethod = env->GetMethodID(pDBInfoClass, "<init>",
"(Ljava/lang/String;IIIIIISSSBB)V");
if (pDBInfoMethod != NULL && env->ExceptionOccurred() == NULL) {
/* Build new object, propagate any exception into Java caller */
jstring jString_nombre = env->NewStringUTF(rInfoDB.name);
pDBInfoObject = env->NewObject(pDBInfoClass, pDBInfoMethod,
jString_nombre, (jint)rInfoDB.createDate, (jint)rInfoDB.modifyDate,
(jint)rInfoDB.backupDate, (jint)rInfoDB.type, (jint)rInfoDB.creator,
(jint)rInfoDB.modnum, (jshort)rInfoDB.flags, (jshort)rInfoDB.version,
(jshort)rInfoDB.index, (jbyte)rInfoDB.miscFlags, (jbyte)rInfoDB.more);
if (env->ExceptionOccurred() != NULL) bProceed = 0;
} else {
/* pending NoSuchMethodException in env */
bProceed = 0;
}
}
/* "Not Found" error returns null, else throw Java exception to inform problem with listing */
} else if (iResult != -5) {
postPilotLinkException(env, "Unable to read DB list entry", iResult, errno);
}
return pDBInfoObject;
}
static void postPilotLinkException(JNIEnv * env, const char * sTexto, int iResult, int save_errno)
{
const char * sTemplate = "%s: %s - %s";
const char * sGenericException = "org/gnu/pilotlink/PilotLinkException";
const char * sDBExistsException = "org/gnu/pilotlink/DatabaseExistsException";
const char * sDBNotFoundException = "org/gnu/pilotlink/DatabaseNotFoundException";
const char * sExceptionClass;
char * sMessage = NULL;
// Make save_errno positive in all cases
if (save_errno < 0) save_errno = -save_errno;
// Choose which exception to report
switch (abs(iResult)) {
case 5:
sExceptionClass = sDBNotFoundException;
break;
case 9:
sExceptionClass = sDBExistsException;
break;
default:
sExceptionClass = sGenericException;
break;
}
// Attempt to describe underlying errno for exception
sMessage = (char *)malloc(strlen(sTemplate) + strlen(sTexto) +
strlen(dlp_strerror(iResult)) + strlen(strerror(save_errno)) + 1);
if (sMessage != NULL) {
sprintf(sMessage, sTemplate, sTexto, dlp_strerror(iResult), strerror(save_errno));
postJavaException(env, sExceptionClass, sMessage);
free(sMessage);
} else {
postJavaException(env, sExceptionClass, dlp_strerror(iResult));
}
}
/* Post a named exception in the Java environment */
static void postJavaException(JNIEnv * env, const char * sExceptionClass, const char * sMessage)
{
jclass pExceptionClass = env->FindClass(sExceptionClass);
if (pExceptionClass != NULL) env->ThrowNew(pExceptionClass, sMessage);
}
/* Get a value from a named Java field of basic type or String */
static int getBasicTypeField(JNIEnv * env, jclass pClass, jobject pObject,
const char * sFieldType, const char * sFieldName, void * pLocation)
{
int bProceed = 1;
jfieldID pFieldID = NULL;
jthrowable pException = NULL;
pFieldID = env->GetFieldID(pClass, sFieldName, sFieldType);
if (pFieldID != NULL && (pException = env->ExceptionOccurred()) == NULL) {
if (strcmp(sFieldType, "I") == 0) {
*((jint *)pLocation) = env->GetIntField(pObject, pFieldID);
} else if (strcmp(sFieldType, "S") == 0) {
*((jshort *)pLocation) = env->GetShortField(pObject, pFieldID);
} else if (strcmp(sFieldType, "B") == 0) {
*((jbyte *)pLocation) = env->GetByteField(pObject, pFieldID);
} else if (strcmp(sFieldType, "Z") == 0) {
*((jboolean *)pLocation) = env->GetBooleanField(pObject, pFieldID);
} else if (strcmp(sFieldType, "C") == 0) {
*((jchar *)pLocation) = env->GetCharField(pObject, pFieldID);
} else if (strcmp(sFieldType, "J") == 0) {
*((jlong *)pLocation) = env->GetLongField(pObject, pFieldID);
} else if (strcmp(sFieldType, "F") == 0) {
*((jfloat *)pLocation) = env->GetFloatField(pObject, pFieldID);
} else if (strcmp(sFieldType, "D") == 0) {
*((jdouble *)pLocation) = env->GetDoubleField(pObject, pFieldID);
} else if (sFieldType[0] == 'L') {
*((jobject *)pLocation) = env->GetObjectField(pObject, pFieldID);
}
} else {
bProceed = 0;
}
return bProceed;
}
/* Assign a value to a named Java field of basic type or String */
static int assignBasicTypeField(JNIEnv * env, jclass pClass, jobject pObject,
const char * sFieldType, const char * sFieldName, ...)
{
int bProceed = 1;
jfieldID pFieldID = NULL;
jthrowable pException = NULL;
pFieldID = env->GetFieldID(pClass, sFieldName, sFieldType);
if (pFieldID != NULL && (pException = env->ExceptionOccurred()) == NULL) {
va_list ap;
va_start(ap, sFieldName);
if (strcmp(sFieldType, "I") == 0) {
jint iValue = va_arg(ap, jint);
env->SetIntField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "S") == 0) {
jshort iValue = va_arg(ap, int);
env->SetShortField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "B") == 0) {
jbyte iValue = va_arg(ap, int);
env->SetByteField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "Z") == 0) {
jboolean iValue = va_arg(ap, int);
env->SetBooleanField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "C") == 0) {
jchar iValue = va_arg(ap, int);
env->SetCharField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "J") == 0) {
jlong iValue = va_arg(ap, jlong);
env->SetLongField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "F") == 0) {
jfloat iValue = va_arg(ap, double);
env->SetFloatField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "D") == 0) {
jdouble iValue = va_arg(ap, jdouble);
env->SetDoubleField(pObject, pFieldID, iValue);
} else if (strcmp(sFieldType, "Ljava/lang/String;") == 0) {
const char * s = va_arg(ap, const char *);
jstring jNameString = env->NewStringUTF(s);
env->SetObjectField(pObject, pFieldID, jNameString);
} else if (sFieldType[0] == 'L') {
jobject pAssignedObject = va_arg(ap, jobject);
env->SetObjectField(pObject, pFieldID, pAssignedObject);
}
va_end(ap);
} else {
bProceed = 0;
}
return bProceed;
}