#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, "","([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, "","([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, "","(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, "", "(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,"","(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,"","(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, "", "(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, "","([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,"","([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, "", "([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 " " 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 " " \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, "", "([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, "", "(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; }