static bool load_uemis_divespot(const char *mountpath, int divespot_id)
{
	char divespotnr[10];
	snprintf(divespotnr, sizeof(divespotnr), "%d", divespot_id);
	param_buff[2] = divespotnr;
#if UEMIS_DEBUG & 2
	fprintf(debugfile, "getDivespot %d\n", divespot_id);
#endif
	bool success = uemis_get_answer(mountpath, "getDivespot", 3, 0, NULL);
	if (mbuf && success) {
#if UEMIS_DEBUG & 16
		do_dump_buffer_to_file(mbuf, "Spot");
#endif
		return parse_divespot(mbuf);
	}
	return false;
}
Example #2
0
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;
}
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;
}
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;
}