const char *do_uemis_import(device_data_t *data) { const char *mountpath = data->devname; short force_download = data->force_download; char *newmax = NULL; int first, start, end = -2; uint32_t deviceidnr; char *deviceid = NULL; const char *result = NULL; char *endptr; bool success, keep_number = false, once = true; int match_dive_and_log = 0; int uemis_mem_status = UEMIS_MEM_OK; #if UEMIS_DEBUG home = getenv("HOME"); user = getenv("LOGNAME"); #endif if (dive_table.nr == 0) keep_number = true; uemis_info(translate("gettextFromC", "Initialise communication")); if (!uemis_init(mountpath)) { free(reqtxt_path); return translate("gettextFromC", "Uemis init failed"); } if (!uemis_get_answer(mountpath, "getDeviceId", 0, 1, &result)) goto bail; deviceid = strdup(param_buff[0]); deviceidnr = atoi(deviceid); /* param_buff[0] is still valid */ if (!uemis_get_answer(mountpath, "initSession", 1, 6, &result)) goto bail; uemis_info(translate("gettextFromC", "Start download")); if (!uemis_get_answer(mountpath, "processSync", 0, 2, &result)) goto bail; /* before starting the long download, check if user pressed cancel */ if (import_thread_cancelled) goto bail; param_buff[1] = "notempty"; newmax = uemis_get_divenr(deviceid, force_download); if (verbose) fprintf(stderr, "Uemis downloader: start looking at dive nr %s", newmax); first = start = atoi(newmax); dive_to_read = first; for (;;) { #if UEMIS_DEBUG & 2 debug_round++; #endif #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i inner loop start %d end %d newmax %s\n", start, end, newmax); #endif /* start at the last filled download table index */ match_dive_and_log = data->download_table->nr; sprintf(newmax, "%d", start); param_buff[2] = newmax; param_buff[3] = 0; success = uemis_get_answer(mountpath, "getDivelogs", 3, 0, &result); uemis_mem_status = get_memory(data->download_table, UEMIS_CHECK_DETAILS); if (success && mbuf && uemis_mem_status != UEMIS_MEM_FULL) { #if UEMIS_DEBUG & 16 do_dump_buffer_to_file(mbuf, "Divelogs"); #endif /* process the buffer we have assembled */ if (!process_raw_buffer(data, deviceidnr, mbuf, &newmax, keep_number, NULL)) { /* if no dives were downloaded, mark end appropriately */ if (end == -2) end = start - 1; success = false; } if (once) { char *t = first_object_id_val(mbuf); if (t && atoi(t) > start) start = atoi(t); free(t); once = false; } /* clean up mbuf */ endptr = strstr(mbuf, "{{{"); if (endptr) *(endptr + 2) = '\0'; /* last object_id we parsed */ sscanf(newmax, "%d", &end); #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i after download and parse start %d end %d newmax %s progress %4.2f\n", start, end, newmax, progress_bar_fraction); #endif /* The way this works is that I am reading the current dive from what has been loaded during the getDiveLogs call to the UEMIS. * As the object_id of the divelog entry and the object_id of the dive details are not necessarily the same, the match needs * to happen based on the logfilenr. * What the following part does is to optimize the mapping by using * dive_to_read = the dive deatils entry that need to be read using the object_id * logFileNoToFind = map the logfilenr of the dive details with the object_id = diveid from the get dive logs */ for (int i = match_dive_and_log; i < data->download_table->nr; i++) { bool success = get_matching_dive(i, newmax, &uemis_mem_status, data, mountpath, deviceidnr); if (!success) break; if (import_thread_cancelled) break; } start = end; /* Do some memory checking here */ uemis_mem_status = get_memory(data->download_table, UEMIS_CHECK_LOG); if (uemis_mem_status != UEMIS_MEM_OK) { #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i out of memory, bailing\n"); #endif break; } /* if the user clicked cancel, exit gracefully */ if (import_thread_cancelled) { #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i thread cancelled, bailing\n"); #endif break; } /* if we got an error or got nothing back, stop trying */ if (!success || !param_buff[3]) { #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i after download nothing found, giving up\n"); #endif break; } #if UEMIS_DEBUG & 2 if (debug_round != -1) if (debug_round-- == 0) { fprintf(debugfile, "d_u_i debug_round is now 0, bailing\n"); goto bail; } #endif } else { /* some of the loading from the UEMIS failed at the divelog level * if the memory status = full, we cant even load the divespots and/or buddys. * The loaded block of divelogs is useless and all new loaded divelogs need to * be deleted from the download_table. */ if (uemis_mem_status == UEMIS_MEM_FULL) do_delete_dives(data->download_table, match_dive_and_log); #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i out of memory, bailing instead of processing\n"); #endif break; } } if (end == -2 && sscanf(newmax, "%d", &end) != 1) end = start; #if UEMIS_DEBUG & 2 fprintf(debugfile, "Done: read from object_id %d to %d\n", first, end); #endif /* Regardless on where we are with the memory situation, it's time now * to see if we have to clean some dead bodies from our download table */ next_table_index = 0; while (next_table_index < data->download_table->nr) { if (!data->download_table->dives[next_table_index]->downloaded) uemis_delete_dive(data, data->download_table->dives[next_table_index]->dc.diveid); else next_table_index++; } if (uemis_mem_status != UEMIS_MEM_OK) result = translate("gettextFromC", ERR_FS_ALMOST_FULL); bail: (void)uemis_get_answer(mountpath, "terminateSync", 0, 3, &result); if (!strcmp(param_buff[0], "error")) { if (!strcmp(param_buff[2], "Out of Memory")) result = translate("gettextFromC", ERR_FS_FULL); else result = param_buff[2]; } free(deviceid); free(reqtxt_path); if (!data->download_table->nr) result = translate("gettextFromC", ERR_NO_FILES); return result; }
const char *do_uemis_import(const char *mountpath, short force_download) { char *newmax = NULL; int start, end = -2, i, offset; uint32_t deviceidnr; char objectid[10]; char *deviceid = NULL; const char *result = NULL; char *endptr; bool success, keep_number = false, once = true; if (dive_table.nr == 0) keep_number = true; uemis_info(translate("gettextFromC", "Init Communication")); if (!uemis_init(mountpath)) return translate("gettextFromC", "Uemis init failed"); if (!uemis_get_answer(mountpath, "getDeviceId", 0, 1, &result)) goto bail; deviceid = strdup(param_buff[0]); deviceidnr = atoi(deviceid); /* the answer from the DeviceId call becomes the input parameter for getDeviceData */ if (!uemis_get_answer(mountpath, "getDeviceData", 1, 0, &result)) goto bail; /* param_buff[0] is still valid */ if (!uemis_get_answer(mountpath, "initSession", 1, 6, &result)) goto bail; uemis_info(translate("gettextFromC", "Start download")); if (!uemis_get_answer(mountpath, "processSync", 0, 2, &result)) goto bail; /* before starting the long download, check if user pressed cancel */ if (import_thread_cancelled) goto bail; param_buff[1] = "notempty"; /* if we have an empty divelist or force it, then we start downloading from the * first dive on the Uemis; otherwise check which was the last dive downloaded */ if (!force_download && dive_table.nr > 0) newmax = uemis_get_divenr(deviceid); else newmax = strdup("0"); start = atoi(newmax); for (;;) { #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i inner loop start %d end %d newmax %s\n", start, end, newmax); #endif param_buff[2] = newmax; param_buff[3] = 0; success = uemis_get_answer(mountpath, "getDivelogs", 3, 0, &result); /* process the buffer we have assembled */ if (mbuf) if (!process_raw_buffer(deviceidnr, mbuf, &newmax, keep_number, NULL)) { /* if no dives were downloaded, mark end appropriately */ if (end == -2) end = start - 1; success = false; } if (once) { char *t = first_object_id_val(mbuf); if (t && atoi(t) > start) start = atoi(t); free(t); once = false; } #if UEMIS_DEBUG & 4 fprintf(debugfile, "d_u_i after download and parse start %d end %d newmax %s\n", start, end, newmax); #endif /* if the user clicked cancel, exit gracefully */ if (import_thread_cancelled) goto bail; /* if we got an error or got nothing back, stop trying */ if (!success || !param_buff[3]) break; /* finally, if the memory is getting too full, maybe we better stop, too */ if (progress_bar_fraction > 0.85) { result = translate("gettextFromC", ERR_FS_ALMOST_FULL); break; } /* clean up mbuf */ endptr = strstr(mbuf, "{{{"); if (endptr) *(endptr + 2) = '\0'; /* last object_id we parsed */ sscanf(newmax, "%d", &end); } if (end == -2 && sscanf(newmax, "%d", &end) != 1) end = start; #if UEMIS_DEBUG & 2 fprintf(debugfile, "done: read from object_id %d to %d\n", start, end); #endif free(newmax); offset = 0; for (i = start; i <= end; i++) { snprintf(objectid, sizeof(objectid), "%d", i + offset); param_buff[2] = objectid; #if UEMIS_DEBUG & 2 fprintf(debugfile, "getDive %d, object_id %s\n", i, objectid); #endif /* there is no way I have found to directly get the dive information * for dive #i as the object_id and logfilenr can be different in the * getDive call; so we get the first one, compare the actual divenr * with the one that we wanted, calculate the offset and try again. * What an insane design... */ success = uemis_get_answer(mountpath, "getDive", 3, 0, &result); if (mbuf) { int divenr; (void)process_raw_buffer(deviceidnr, mbuf, &newmax, false, &divenr); #if UEMIS_DEBUG & 2 fprintf(debugfile, "got dive %d, looking for dive %d\n", divenr, i); #endif if (divenr != i) { if (divenr == -1) { offset--; } else { offset += i - divenr; } #if UEMIS_DEBUG & 2 fprintf(debugfile, " -> trying again with offset %d\n", offset); #endif i = start - 1; if (i + offset < 0) break; continue; } } if (!success || import_thread_cancelled) break; } success = true; for (i = 0; i <= nr_divespots; i++) { char divespotnr[10]; snprintf(divespotnr, sizeof(divespotnr), "%d", i); param_buff[2] = divespotnr; #if UEMIS_DEBUG & 2 fprintf(debugfile, "getDivespot %d\n", i); #endif success = uemis_get_answer(mountpath, "getDivespot", 3, 0, &result); if (mbuf) parse_divespot(mbuf); } bail: (void)uemis_get_answer(mountpath, "terminateSync", 0, 3, &result); if (!strcmp(param_buff[0], "error")) { if (!strcmp(param_buff[2], "Out of Memory")) result = translate("gettextFromC", ERR_FS_FULL); else result = param_buff[2]; } free(deviceid); return result; }
static bool get_matching_dive(int idx, char *newmax, int *uemis_mem_status, struct device_data_t *data, const char *mountpath, const char deviceidnr) { struct dive *dive = data->download_table->dives[idx]; char log_file_no_to_find[20]; char dive_to_read_buf[10]; bool found = false; bool found_below = false; bool found_above = false; int deleted_files = 0; snprintf(log_file_no_to_find, sizeof(log_file_no_to_find), "logfilenr{int{%d", dive->dc.diveid); #if UEMIS_DEBUG & 2 fprintf(debugfile, "Looking for dive details to go with divelog id %d\n", dive->dc.diveid); #endif while (!found) { if (import_thread_cancelled) break; snprintf(dive_to_read_buf, sizeof(dive_to_read_buf), "%d", dive_to_read); param_buff[2] = dive_to_read_buf; (void)uemis_get_answer(mountpath, "getDive", 3, 0, NULL); #if UEMIS_DEBUG & 16 do_dump_buffer_to_file(mbuf, "Dive"); #endif *uemis_mem_status = get_memory(data->download_table, UEMIS_CHECK_SINGLE_DIVE); if (*uemis_mem_status == UEMIS_MEM_OK) { /* if the memory isn's completely full we can try to read more divelog vs. dive details * UEMIS_MEM_CRITICAL means not enough space for a full round but the dive details * and the divespots should fit into the UEMIS memory * The match we do here is to map the object_id to the logfilenr, we do this * by iterating through the last set of loaded divelogs and then find the corresponding * dive with the matching logfilenr */ if (mbuf) { if (strstr(mbuf, log_file_no_to_find)) { /* we found the logfilenr that matches our object_id from the divelog we were looking for * we mark the search sucessfull even if the dive has been deleted. */ found = true; if (strstr(mbuf, "deleted{bool{true") == NULL) { process_raw_buffer(data, deviceidnr, mbuf, &newmax, false, NULL); /* remember the last log file number as it is very likely that subsequent dives * have the same or higher logfile number. * UEMIS unfortunately deletes dives by deleting the dive details and not the logs. */ #if UEMIS_DEBUG & 2 d_time = get_dive_date_c_string(dive->when); fprintf(debugfile, "Matching divelog id %d from %s with dive details %d\n", dive->dc.diveid, d_time, dive_to_read); #endif int divespot_id = uemis_get_divespot_id_by_diveid(dive->dc.diveid); if (divespot_id >= 0) get_uemis_divespot(mountpath, divespot_id, dive); } else { /* in this case we found a deleted file, so let's increment */ #if UEMIS_DEBUG & 2 d_time = get_dive_date_c_string(dive->when); fprintf(debugfile, "TRY matching divelog id %d from %s with dive details %d but details are deleted\n", dive->dc.diveid, d_time, dive_to_read); #endif deleted_files++; max_deleted_seen = dive_to_read; /* mark this log entry as deleted and cleanup later, otherwise we mess up our array */ dive->downloaded = false; #if UEMIS_DEBUG & 2 fprintf(debugfile, "Deleted dive from %s, with id %d from table -- newmax is %s\n", d_time, dive->dc.diveid, newmax); #endif } } else { uint32_t nr_found = 0; char *logfilenr = strstr(mbuf, "logfilenr"); if (logfilenr) { sscanf(logfilenr, "logfilenr{int{%u", &nr_found); if (nr_found >= dive->dc.diveid) { found_above = true; dive_to_read = dive_to_read - 2; } else { found_below = true; } if (dive_to_read < -1) dive_to_read = -1; } } } if (found_above && found_below) break; dive_to_read++; } else { /* At this point the memory of the UEMIS is full, let's cleanup all divelog files were * we could not match the details to. */ do_delete_dives(data->download_table, idx); return false; } } /* decrement iDiveToRead by the amount of deleted entries found to assure * we are not missing any valid matches when processing subsequent logs */ dive_to_read = (dive_to_read - deleted_files > 0 ? dive_to_read - deleted_files : 0); deleted_files = 0; return true; }