int oph_wf_list_append(oph_job_list * job_info, oph_workflow * wf)
{
	int k;
	oph_job_info *item = (oph_job_info *) malloc(sizeof(oph_job_info));
	if (!item) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Unable to alloc memory for '%s'\n", wf->name);
		return OPH_SERVER_ERROR;
	}

	item->wf = wf;

	pthread_mutex_lock(&global_flag);
	k = oph_insert_into_job_list(job_info, item);
	pthread_mutex_unlock(&global_flag);

	if (k) {
		if (k == OPH_JOB_LIST_FARM_FULL) {
			pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "The workflow has been queued.\n");
			return OPH_SERVER_NO_RESPONSE;	// The workflow has been queued
		} else if (k == OPH_JOB_LIST_FULL)
			pmesg_safe(&global_flag, LOG_WARNING, __FILE__, __LINE__, "Reached the maximum number of pending workflows.\n");
		else
			pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Unable to store data for '%s' in server memory\n", wf->name);
		free(item);
		return OPH_SERVER_ERROR;
	}

	return OPH_SERVER_OK;
}
int _oph_odb_update_folder_table(ophidiadb * oDB, char *folder_name, int *id_folder, pthread_mutex_t * flag)
{
	if (!oDB || !folder_name || !id_folder) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Null input parameter\n");
		return OPH_ODB_NULL_PARAM;
	}

	if (oph_odb_check_connection_to_ophidiadb(oDB)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to reconnect to OphidiaDB.\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	char insertQuery[MYSQL_BUFLEN];
	int n = snprintf(insertQuery, MYSQL_BUFLEN, MYSQL_QUERY_UPDATE_OPHIDIADB_SESSION_FOLDER, folder_name);

	if (n >= MYSQL_BUFLEN) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Size of query exceed query limit.\n");
		return OPH_ODB_STR_BUFF_OVERFLOW;
	}

	if (mysql_query(oDB->conn, insertQuery)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	if (!(*id_folder = mysql_insert_id(oDB->conn))) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to find last inserted folder id\n");
		return OPH_ODB_TOO_MANY_ROWS;
	}

	return OPH_ODB_SUCCESS;
}
static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
{
	if (!file || !line)
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "");
	MUTEX_CLEANUP(l->mutex);
	free(l);
}
int _oph_odb_retrieve_job_id(ophidiadb * oDB, char *sessionid, char *markerid, int *id_job, pthread_mutex_t * flag)
{
	if (!oDB || !sessionid || !markerid || !id_job) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Null input parameter\n");
		return OPH_ODB_NULL_PARAM;
	}
	*id_job = 0;

	if (oph_odb_check_connection_to_ophidiadb(oDB)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to reconnect to OphidiaDB.\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	char query[MYSQL_BUFLEN];

	int n = snprintf(query, MYSQL_BUFLEN, MYSQL_RETRIEVE_JOB_ID, sessionid, markerid);
	if (n >= MYSQL_BUFLEN) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Size of query exceed query limit.\n");
		return OPH_ODB_STR_BUFF_OVERFLOW;
	}
	pmesg_safe(flag, LOG_DEBUG, __FILE__, __LINE__, "Find job with markerid '%s'\n", markerid);

	if (mysql_query(oDB->conn, query)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	MYSQL_RES *res;
	MYSQL_ROW row;
	res = mysql_store_result(oDB->conn);

	if (mysql_num_rows(res) < 1) {
		pmesg_safe(flag, LOG_DEBUG, __FILE__, __LINE__, "No row found by query\n");
		mysql_free_result(res);
		return OPH_ODB_NO_ROW_FOUND;
	}

	if (mysql_num_rows(res) > 1) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "More than one row found by query\n");
		mysql_free_result(res);
		return OPH_ODB_TOO_MANY_ROWS;
	}

	if (mysql_field_count(oDB->conn) != 1) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Not enough fields found by query\n");
		mysql_free_result(res);
		return OPH_ODB_TOO_MANY_ROWS;
	}

	if ((row = mysql_fetch_row(res)) != NULL)
		*id_job = (int) strtol(row[0], NULL, 10);

	mysql_free_result(res);

	return OPH_ODB_SUCCESS;
}
void locking_function(int mode, int n, const char *file, int line)
{
	if (!file || !line)
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "");
	if (mode & CRYPTO_LOCK)
		MUTEX_LOCK(mutex_buf[n]);
	else
		MUTEX_UNLOCK(mutex_buf[n]);
}
static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
{
	if (!file || !line)
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "");
	if (mode & CRYPTO_LOCK)
		MUTEX_LOCK(l->mutex);
	else
		MUTEX_UNLOCK(l->mutex);
}
static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line)
{
	if (!file || !line)
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "");
	struct CRYPTO_dynlock_value *value;
	value = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value));
	if (value)
		MUTEX_SETUP(value->mutex);
	return value;
}
int oph_serve_known_operator(struct oph_plugin_data *state, const char *request, const int ncores, const char *sessionid, const char *markerid, int *odb_wf_id, int *task_id, int *light_task_id,
			     int *odb_jobid, char **response, char **jobid_response, enum oph__oph_odb_job_status *exit_code, int *exit_output)
{
	int error = OPH_SERVER_UNKNOWN;
	if (exit_code)
		*exit_code = OPH_ODB_STATUS_ERROR;
	if (exit_output)
		*exit_output = 1;

	if (!request) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Submission string not found\n");
		return OPH_SERVER_WRONG_PARAMETER_ERROR;
	}
	if (!sessionid) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "%s not found\n", OPH_ARG_SESSIONID);
		return OPH_SERVER_WRONG_PARAMETER_ERROR;
	}
	if (!markerid) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "%s not found\n", OPH_ARG_MARKERID);
		return OPH_SERVER_WRONG_PARAMETER_ERROR;
	}

	char operator_name[OPH_MAX_STRING_SIZE];
	if (oph_tp_find_param_in_task_string(request, OPH_ARG_OPERATOR, &operator_name)) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "%s not found\n", OPH_ARG_OPERATOR);
		return OPH_SERVER_WRONG_PARAMETER_ERROR;
	}

	if ((error =
	     oph_serve_flow_control_operator(state, request, ncores, sessionid, markerid, odb_wf_id, task_id, light_task_id, odb_jobid, response, jobid_response, exit_code, exit_output,
					     operator_name)) != OPH_SERVER_UNKNOWN)
		return error;

	if ((error =
	     oph_serve_management_operator(state, request, ncores, sessionid, markerid, odb_wf_id, task_id, light_task_id, odb_jobid, response, jobid_response, exit_code, exit_output,
					   operator_name)) != OPH_SERVER_UNKNOWN)
		return error;

	return error;
}
int _oph_odb_update_session_label(ophidiadb * oDB, const char *sessionid, char *label, pthread_mutex_t * flag)
{
	if (!oDB || !sessionid) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Null input parameter\n");
		return OPH_ODB_NULL_PARAM;
	}

	if (oph_odb_check_connection_to_ophidiadb(oDB)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to reconnect to OphidiaDB.\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	int id_session;
	if (_oph_odb_retrieve_session_id(oDB, sessionid, &id_session, flag)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to retrieve session id\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	char insertQuery[MYSQL_BUFLEN];
	int n = snprintf(insertQuery, MYSQL_BUFLEN, MYSQL_QUERY_UPDATE_OPHIDIADB_SESSION_LABEL, label ? label : "", id_session);

	if (n >= MYSQL_BUFLEN) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Size of query exceed query limit.\n");
		return OPH_ODB_STR_BUFF_OVERFLOW;
	}

	if (mysql_set_server_option(oDB->conn, MYSQL_OPTION_MULTI_STATEMENTS_ON)) {
		pmesg(LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	if (mysql_query(oDB->conn, insertQuery)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	return OPH_ODB_SUCCESS;
}
int _oph_json_set_tree_root(oph_json * json, const char *objkey, int rootnode, pthread_mutex_t * flag)
{
	if (!json || !objkey || rootnode < 0) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "(NULL parameters)");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	if (json->response_num == 0) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "response_num");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	unsigned int i;
	int tree_present = 0;
	for (i = 0; i < json->response_num; i++) {
		if (!strcmp(json->response[i].objkey, objkey)) {
			if (!strcmp(json->response[i].objclass, OPH_JSON_TREE)) {
				tree_present = 1;
				break;
			}
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objkey");
			return OPH_JSON_BAD_PARAM_ERROR;
		}
	}
	if (tree_present) {
		if (json->response[i].objcontent_num < 1) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objcontent_num");
			return OPH_JSON_BAD_PARAM_ERROR;
		}

		if (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].rootnode) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "rootnode");
			return OPH_JSON_BAD_PARAM_ERROR;
		}

		char buf[20];
		memset(buf, 0, 20);
		snprintf(buf, 20, "%d", rootnode);
		((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].rootnode = (char *) strdup(buf);
		if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].rootnode) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "rootnode");
			return OPH_JSON_MEMORY_ERROR;
		}
	} else {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objkey");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	return OPH_JSON_SUCCESS;
}
int _oph_odb_update_job_table(ophidiadb * oDB, char *markerid, char *task_string, char *status, int id_user, int id_session, int nchildren, int *id_job, char *parentid, char *workflowid,
			      pthread_mutex_t * flag)
{
	if (!oDB || !markerid || !task_string || !status || !id_job) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Null input parameter\n");
		return OPH_ODB_NULL_PARAM;
	}

	if (oph_odb_check_connection_to_ophidiadb(oDB)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to reconnect to OphidiaDB.\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	char insertQuery[MYSQL_BUFLEN];
	int n, i, j;

	char new_query[OPERATION_QUERY_SIZE];
	j = 0;
	for (i = 0; i < OPERATION_QUERY_SIZE; i++) {
		if (!task_string[i])
			break;
		if (task_string[i] == '\'')
			new_query[j++] = '\\';
		new_query[j] = task_string[i];
		j++;
		if (j >= OPERATION_QUERY_SIZE - 1)
			break;
	}
	new_query[j] = 0;

	if (parentid)
		n = snprintf(insertQuery, MYSQL_BUFLEN, MYSQL_QUERY_UPDATE_OPHIDIADB_JOB_CHILD, id_user, id_session, markerid, status, new_query, parentid, workflowid);
	else if (nchildren >= 0)
		n = snprintf(insertQuery, MYSQL_BUFLEN, MYSQL_QUERY_UPDATE_OPHIDIADB_JOB_PARENT, id_user, id_session, markerid, status, new_query, nchildren, workflowid);
	else
		n = snprintf(insertQuery, MYSQL_BUFLEN, MYSQL_QUERY_UPDATE_OPHIDIADB_JOB, id_user, id_session, markerid, status, new_query);
	pmesg_safe(flag, LOG_DEBUG, __FILE__, __LINE__, "Execute query: %s\n", insertQuery);

	if (n >= MYSQL_BUFLEN) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Size of query exceed query limit.\n");
		return OPH_ODB_STR_BUFF_OVERFLOW;
	}

	if (mysql_query(oDB->conn, insertQuery)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	if (!(*id_job = mysql_insert_id(oDB->conn))) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to find last inserted job id\n");
		return OPH_ODB_TOO_MANY_ROWS;
	}

	return OPH_ODB_SUCCESS;
}
int _oph_odb_update_session_table(ophidiadb * oDB, char *sessionid, int id_user, int *id_session, pthread_mutex_t * flag)
{
	if (!oDB || !sessionid || !id_session) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Null input parameter\n");
		return OPH_ODB_NULL_PARAM;
	}

	if (oph_odb_check_connection_to_ophidiadb(oDB)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to reconnect to OphidiaDB.\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	char session_code[OPH_MAX_STRING_SIZE];
	if (oph_get_session_code(sessionid, session_code)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to extract session code.\n");
		return OPH_ODB_MYSQL_ERROR;
	}
	int id_folder;
	if (_oph_odb_update_folder_table(oDB, session_code, &id_folder, flag)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to create folder.\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	char insertQuery[MYSQL_BUFLEN];
	int n = snprintf(insertQuery, MYSQL_BUFLEN, MYSQL_QUERY_UPDATE_OPHIDIADB_SESSION, id_user, sessionid, id_folder);

	if (n >= MYSQL_BUFLEN) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Size of query exceed query limit.\n");
		return OPH_ODB_STR_BUFF_OVERFLOW;
	}

	if (mysql_set_server_option(oDB->conn, MYSQL_OPTION_MULTI_STATEMENTS_ON)) {
		pmesg(LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	if (mysql_query(oDB->conn, insertQuery)) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	if (!(*id_session = mysql_insert_id(oDB->conn))) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to find last inserted session id\n");
		return OPH_ODB_TOO_MANY_ROWS;
	}

	return OPH_ODB_SUCCESS;
}
void *process_request(struct soap *soap)
{
#if defined(_POSIX_THREADS) || defined(_SC_THREADS)
	pthread_detach(pthread_self());
#endif

#ifdef WITH_OPENSSL
	if (soap_ssl_accept(soap) != SOAP_OK) {
		/* when soap_ssl_accept() fails, socket is closed and SSL data reset */
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "SSL request failed, continue with next call...\n");
		soap_print_fault(soap, stderr);
	} else
#endif
		soap_serve(soap);

	soap_destroy(soap);	/* for C++ */
	soap_end(soap);
	soap_free(soap);

	mysql_thread_end();

	return NULL;
}
int _oph_json_add_tree_node(oph_json * json, const char *objkey, char **nodevalues, pthread_mutex_t * flag)
{
	if (!json || !objkey) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "(NULL parameters)");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	if (json->response_num == 0) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "response_num");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	unsigned int i;
	int tree_present = 0;
	for (i = 0; i < json->response_num; i++) {
		if (!strcmp(json->response[i].objkey, objkey)) {
			if (!strcmp(json->response[i].objclass, OPH_JSON_TREE)) {
				tree_present = 1;
				break;
			}
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objkey");
			return OPH_JSON_BAD_PARAM_ERROR;
		}
	}
	if (tree_present) {
		if (json->response[i].objcontent_num < 1) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objcontent_num");
			return OPH_JSON_BAD_PARAM_ERROR;
		}
		if (nodevalues) {
			if (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num2 == 0) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "nodevalues");
				return OPH_JSON_BAD_PARAM_ERROR;
			}
			unsigned int index = 0;
			if (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num1 == 0) {
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues = (char ***) malloc(sizeof(char **));
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodevalues");
					return OPH_JSON_MEMORY_ERROR;
				}
				index = 0;
			} else {
				char ***tmp = ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues;
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues =
				    (char ***) realloc(((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues,
						       sizeof(char **) * (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num1 + 1));
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues) {
					((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues = tmp;
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodevalues");
					return OPH_JSON_MEMORY_ERROR;
				}
				index = ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num1;
			}

			unsigned int k;

			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues[index] =
			    (char **) malloc(sizeof(char *) * (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num2));
			if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues[index]) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodevalues row");
				return OPH_JSON_MEMORY_ERROR;
			}
			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num1++;

			for (k = 0; k < ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num2; k++) {
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues[index][k] = NULL;
			}
			for (k = 0; k < ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num2; k++) {
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues[index][k] = (char *) strdup(nodevalues[k]);
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues[index][k]) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodevalue");
					return OPH_JSON_MEMORY_ERROR;
				}
			}
		} else {
			if (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodevalues_num2 != 0) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "nodevalues");
				return OPH_JSON_BAD_PARAM_ERROR;
			}
		}

		unsigned int index = 0;
		if (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks_num == 0) {
			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks = (oph_json_links *) malloc(sizeof(oph_json_links));
			if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodelinks");
				return OPH_JSON_MEMORY_ERROR;
			}
			index = 0;
		} else {
			oph_json_links *tmp = ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks;
			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks =
			    (oph_json_links *) realloc(((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks,
						       sizeof(oph_json_links) * (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks_num + 1));
			if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks) {
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks = tmp;
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodelinks");
				return OPH_JSON_MEMORY_ERROR;
			}
			index = ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks_num;
		}
		((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks_num++;

		((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[index].links = NULL;
		((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[index].links_num = 0;

	} else {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objkey");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	return OPH_JSON_SUCCESS;
}
int _oph_json_add_tree(oph_json * json, const char *objkey, const char *title, const char *description, char **nodekeys, int nodekeys_num, pthread_mutex_t * flag)
{
	if (!json || !objkey || !title || nodekeys_num < 0) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "(NULL parameters)");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	if (json->response_num == 0) {
		json->response = (oph_json_response *) malloc(sizeof(oph_json_response));
		if (!json->response) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "response");
			return OPH_JSON_MEMORY_ERROR;
		}
		json->response[0].objclass = NULL;
		json->response[0].objcontent = NULL;
		json->response[0].objcontent_num = 0;
		json->response[0].objkey = NULL;

		json->response[0].objclass = (char *) strdup(OPH_JSON_TREE);
		if (!json->response[0].objclass) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objclass");
			return OPH_JSON_MEMORY_ERROR;
		}

		json->response_num++;

		json->response[0].objkey = (char *) strdup(objkey);
		if (!json->response[0].objkey) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objkey");
			return OPH_JSON_MEMORY_ERROR;
		}
		if (_oph_json_add_responseKey(json, objkey, flag)) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objkey");
			return OPH_JSON_MEMORY_ERROR;
		}

		json->response[0].objcontent = malloc(sizeof(oph_json_obj_tree));
		if (!json->response[0].objcontent) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objcontent");
			return OPH_JSON_MEMORY_ERROR;
		}
		((oph_json_obj_tree *) json->response[0].objcontent)[0].description = NULL;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].nodekeys = NULL;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].nodekeys_num = 0;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].nodelinks = NULL;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].nodelinks_num = 0;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].nodevalues = NULL;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].nodevalues_num1 = 0;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].nodevalues_num2 = 0;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].rootnode = NULL;
		((oph_json_obj_tree *) json->response[0].objcontent)[0].title = NULL;

		((oph_json_obj_tree *) json->response[0].objcontent)[0].title = (char *) strdup(title);
		if (!((oph_json_obj_tree *) json->response[0].objcontent)[0].title) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "title");
			return OPH_JSON_MEMORY_ERROR;
		}

		json->response[0].objcontent_num++;

		if (description) {
			((oph_json_obj_tree *) json->response[0].objcontent)[0].description = (char *) strdup(description);
			if (!((oph_json_obj_tree *) json->response[0].objcontent)[0].description) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "description");
				return OPH_JSON_MEMORY_ERROR;
			}
		}

		if (nodekeys) {
			int k, q;

			((oph_json_obj_tree *) json->response[0].objcontent)[0].nodekeys = (char **) malloc(sizeof(char *) * nodekeys_num);
			if (!((oph_json_obj_tree *) json->response[0].objcontent)[0].nodekeys) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodekeys");
				return OPH_JSON_MEMORY_ERROR;
			}
			for (k = 0; k < nodekeys_num; k++) {
				for (q = 0; q < k; q++) {
					if (!strcmp(nodekeys[q], nodekeys[k])) {
						pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "nodekey");
						return OPH_JSON_BAD_PARAM_ERROR;
					}
				}
				((oph_json_obj_tree *) json->response[0].objcontent)[0].nodekeys[k] = (char *) strdup(nodekeys[k]);
				if (!((oph_json_obj_tree *) json->response[0].objcontent)[0].nodekeys[k]) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodekey");
					return OPH_JSON_MEMORY_ERROR;
				}
				((oph_json_obj_tree *) json->response[0].objcontent)[0].nodekeys_num++;
			}

			((oph_json_obj_tree *) json->response[0].objcontent)[0].nodevalues_num2 = nodekeys_num;
		}
	} else {
		unsigned int i;
		int add_frag = 0;
		for (i = 0; i < json->response_num; i++) {
			if (!strcmp(json->response[i].objkey, objkey)) {
				if (!strcmp(json->response[i].objclass, OPH_JSON_TREE)) {
					add_frag = 1;
					break;
				}
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objkey");
				return OPH_JSON_BAD_PARAM_ERROR;
			}
		}
		if (add_frag) {
			void *tmp = json->response[i].objcontent;
			unsigned int index = json->response[i].objcontent_num;
			json->response[i].objcontent = realloc(json->response[i].objcontent, sizeof(oph_json_obj_tree) * (json->response[i].objcontent_num + 1));
			if (!json->response[i].objcontent) {
				json->response[i].objcontent = tmp;
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objcontent");
				return OPH_JSON_MEMORY_ERROR;
			}
			((oph_json_obj_tree *) json->response[i].objcontent)[index].description = NULL;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].nodekeys = NULL;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].nodekeys_num = 0;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].nodelinks = NULL;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].nodelinks_num = 0;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].nodevalues = NULL;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].nodevalues_num1 = 0;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].nodevalues_num2 = 0;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].rootnode = NULL;
			((oph_json_obj_tree *) json->response[i].objcontent)[index].title = NULL;

			((oph_json_obj_tree *) json->response[i].objcontent)[index].title = (char *) strdup(title);
			if (!((oph_json_obj_tree *) json->response[i].objcontent)[index].title) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "title");
				return OPH_JSON_MEMORY_ERROR;
			}

			json->response[i].objcontent_num++;

			if (description) {
				((oph_json_obj_tree *) json->response[i].objcontent)[index].description = (char *) strdup(description);
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[index].description) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "description");
					return OPH_JSON_MEMORY_ERROR;
				}
			}

			if (nodekeys) {
				int k, q;

				((oph_json_obj_tree *) json->response[i].objcontent)[index].nodekeys = (char **) malloc(sizeof(char *) * nodekeys_num);
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[index].nodekeys) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodekeys");
					return OPH_JSON_MEMORY_ERROR;
				}
				for (k = 0; k < nodekeys_num; k++) {
					for (q = 0; q < k; q++) {
						if (!strcmp(nodekeys[q], nodekeys[k])) {
							pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "nodekey");
							return OPH_JSON_BAD_PARAM_ERROR;
						}
					}
					((oph_json_obj_tree *) json->response[i].objcontent)[index].nodekeys[k] = (char *) strdup(nodekeys[k]);
					if (!((oph_json_obj_tree *) json->response[i].objcontent)[index].nodekeys[k]) {
						pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodekey");
						return OPH_JSON_MEMORY_ERROR;
					}
					((oph_json_obj_tree *) json->response[i].objcontent)[index].nodekeys_num++;
				}

				((oph_json_obj_tree *) json->response[i].objcontent)[index].nodevalues_num2 = nodekeys_num;
			}
		} else {
			oph_json_response *tmp = json->response;
			unsigned int index = json->response_num;
			json->response = (oph_json_response *) realloc(json->response, sizeof(oph_json_response) * (json->response_num + 1));
			if (!json->response) {
				json->response = tmp;
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "response");
				return OPH_JSON_MEMORY_ERROR;
			}
			json->response[index].objclass = NULL;
			json->response[index].objcontent = NULL;
			json->response[index].objcontent_num = 0;
			json->response[index].objkey = NULL;

			json->response[index].objclass = (char *) strdup(OPH_JSON_TREE);
			if (!json->response[index].objclass) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objclass");
				return OPH_JSON_MEMORY_ERROR;
			}

			json->response_num++;

			json->response[index].objkey = (char *) strdup(objkey);
			if (!json->response[index].objkey) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objkey");
				return OPH_JSON_MEMORY_ERROR;
			}
			if (_oph_json_add_responseKey(json, objkey, flag)) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objkey");
				return OPH_JSON_MEMORY_ERROR;
			}

			json->response[index].objcontent = malloc(sizeof(oph_json_obj_tree));
			if (!json->response[index].objcontent) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "objcontent");
				return OPH_JSON_MEMORY_ERROR;
			}
			((oph_json_obj_tree *) json->response[index].objcontent)[0].description = NULL;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].nodekeys = NULL;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].nodekeys_num = 0;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].nodelinks = NULL;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].nodelinks_num = 0;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].nodevalues = NULL;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].nodevalues_num1 = 0;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].nodevalues_num2 = 0;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].rootnode = NULL;
			((oph_json_obj_tree *) json->response[index].objcontent)[0].title = NULL;

			((oph_json_obj_tree *) json->response[index].objcontent)[0].title = (char *) strdup(title);
			if (!((oph_json_obj_tree *) json->response[index].objcontent)[0].title) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "title");
				return OPH_JSON_MEMORY_ERROR;
			}

			json->response[index].objcontent_num++;

			if (description) {
				((oph_json_obj_tree *) json->response[index].objcontent)[0].description = (char *) strdup(description);
				if (!((oph_json_obj_tree *) json->response[index].objcontent)[0].description) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "description");
					return OPH_JSON_MEMORY_ERROR;
				}
			}

			if (nodekeys) {
				int k, q;

				((oph_json_obj_tree *) json->response[index].objcontent)[0].nodekeys = (char **) malloc(sizeof(char *) * nodekeys_num);
				if (!((oph_json_obj_tree *) json->response[index].objcontent)[0].nodekeys) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodekeys");
					return OPH_JSON_MEMORY_ERROR;
				}
				for (k = 0; k < nodekeys_num; k++) {
					for (q = 0; q < k; q++) {
						if (!strcmp(nodekeys[q], nodekeys[k])) {
							pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "nodekey");
							return OPH_JSON_BAD_PARAM_ERROR;
						}
					}
					((oph_json_obj_tree *) json->response[index].objcontent)[0].nodekeys[k] = (char *) strdup(nodekeys[k]);
					if (!((oph_json_obj_tree *) json->response[index].objcontent)[0].nodekeys[k]) {
						pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "nodekey");
						return OPH_JSON_MEMORY_ERROR;
					}
					((oph_json_obj_tree *) json->response[index].objcontent)[0].nodekeys_num++;
				}

				((oph_json_obj_tree *) json->response[index].objcontent)[0].nodevalues_num2 = nodekeys_num;
			}
		}
	}

	return OPH_JSON_SUCCESS;
}
int oph_finalize_known_operator(int idjob, oph_json * oper_json, const char *operator_name, char *error_message, int success, char **response, ophidiadb * oDB, enum oph__oph_odb_job_status *exit_code)
{
	pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "Finalize known operator: %s (%s)\n", success ? "success" : "failure", error_message ? error_message : "-");

	char *jstring = NULL;
	if (oper_json) {
		int return_code = 0;

		if (!success) {
			if (!strlen(error_message)) {
				snprintf(error_message, OPH_MAX_STRING_SIZE, "Operator '%s' failed!", operator_name);
				if (exit_code)
					*exit_code = OPH_ODB_STATUS_ERROR;
			}
			if (oph_json_add_text(oper_json, OPH_JSON_OBJKEY_STATUS, "ERROR", error_message)) {
				pmesg_safe(&global_flag, LOG_WARNING, __FILE__, __LINE__, "ADD TEXT error\n");
				return_code = -1;
			} else if (oph_write_and_get_json(oper_json, &jstring)) {
				pmesg_safe(&global_flag, LOG_WARNING, __FILE__, __LINE__, "JSON file creation error\n");
				return_code = -1;
			}
		} else {
			if (oph_json_add_text(oper_json, OPH_JSON_OBJKEY_STATUS, "SUCCESS", strlen(error_message) ? error_message : NULL)) {
				pmesg_safe(&global_flag, LOG_WARNING, __FILE__, __LINE__, "ADD TEXT error\n");
				return_code = -1;
			} else if (oph_write_and_get_json(oper_json, &jstring)) {
				pmesg_safe(&global_flag, LOG_WARNING, __FILE__, __LINE__, "JSON file creation error\n");
				return_code = -1;
			} else if (exit_code && (*exit_code != OPH_ODB_STATUS_WAIT))
				*exit_code = OPH_ODB_STATUS_COMPLETED;
		}
		oph_json_free(oper_json);

		if (return_code && exit_code)
			*exit_code = OPH_ODB_STATUS_ERROR;

	} else if (exit_code)
		*exit_code = OPH_ODB_STATUS_ERROR;

	if (!jstring) {
		pmesg_safe(&global_flag, LOG_WARNING, __FILE__, __LINE__, "Unable to convert JSON Response into a string\n");
		if (exit_code)
			*exit_code = OPH_ODB_STATUS_ERROR;
		oph_odb_disconnect_from_ophidiadb(oDB);
		return OPH_SERVER_SYSTEM_ERROR;
	}
	if (response)
		*response = jstring;
	else
		free(jstring);

	// Set ODB_STATUS to COMPLETED
	pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "Finalize OphDB status\n");
	if (exit_code && (*exit_code == OPH_ODB_STATUS_WAIT))
		oph_odb_set_job_status(idjob, OPH_ODB_STATUS_WAIT, oDB);
	else
		oph_odb_stop_job_fast(idjob, oDB);
	oph_odb_disconnect_from_ophidiadb(oDB);

	return OPH_SERVER_OK;
}
int oph_ssh_submit(const char *cmd)
{
	int sock;
	struct sockaddr_in sin;
	struct addrinfo hints, *result;
	LIBSSH2_SESSION *session;
	LIBSSH2_CHANNEL *channel;
	int rc;
	int exitcode;
	char *exitsignal = (char *) "none";
	int bytecount = 0;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = 0;
	hints.ai_protocol = 0;
	result = NULL;
	rc = getaddrinfo(oph_ip_target_host, NULL, &hints, &result);
	if (rc != 0) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Unable to resolve address from target hostname: %s\n", gai_strerror(rc));
		return OPH_LIBSSH_ERROR;
	}

	sock = socket(AF_INET, SOCK_STREAM, 0);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(22);
	sin.sin_addr.s_addr = ((struct sockaddr_in *) result->ai_addr)->sin_addr.s_addr;
	freeaddrinfo(result);
	if (connect(sock, (struct sockaddr *) (&sin), sizeof(struct sockaddr_in)) != 0) {
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Failed to connect to submission host\n");
		return OPH_LIBSSH_ERROR;
	}

	pthread_mutex_lock(&libssh2_flag);	// Lock the access to SSH library
	pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "SSH2 library locked\n");

	rc = libssh2_init(0);
	if (rc != 0) {
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		pthread_mutex_unlock(&libssh2_flag);
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "libssh2 initialization failed (%d)\n", rc);
		return OPH_LIBSSH_ERROR;
	}

	session = libssh2_session_init();
	if (!session) {
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		libssh2_exit();
		pthread_mutex_unlock(&libssh2_flag);
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Failed to init ssh sessione\n");
		return OPH_LIBSSH_ERROR;
	}

	libssh2_session_set_blocking(session, 0);

	while ((rc = libssh2_session_handshake(session, sock)) == LIBSSH2_ERROR_EAGAIN);
	if (rc) {
		libssh2_session_disconnect(session, "Session disconnected");
		libssh2_session_free(session);
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		libssh2_exit();
		pthread_mutex_unlock(&libssh2_flag);
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Failure establishing SSH session: %d\n", rc);
		return OPH_LIBSSH_ERROR;
	}

	while ((rc = libssh2_userauth_publickey_fromfile(session, oph_subm_user, oph_subm_user_publk, oph_subm_user_privk, "")) == LIBSSH2_ERROR_EAGAIN);
	if (rc) {
		libssh2_session_disconnect(session, "Session disconnected");
		libssh2_session_free(session);
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		libssh2_exit();
		pthread_mutex_unlock(&libssh2_flag);
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Authentication by public key failed\n");
		return OPH_LIBSSH_ERROR;
	}

	while ((channel = libssh2_channel_open_session(session)) == NULL && libssh2_session_last_error(session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) {
		waitsocket(sock, session);
	}
	if (channel == NULL) {
		libssh2_session_disconnect(session, "Session disconnected");
		libssh2_session_free(session);
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		libssh2_exit();
		pthread_mutex_unlock(&libssh2_flag);
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Error during opening session channel\n");
		return OPH_LIBSSH_ERROR;
	}
	while ((rc = libssh2_channel_exec(channel, cmd)) == LIBSSH2_ERROR_EAGAIN) {
		waitsocket(sock, session);
	}
	if (rc != 0) {
		libssh2_channel_free(channel);
		libssh2_session_disconnect(session, "Session disconnected");
		libssh2_session_free(session);
#ifdef WIN32
		closesocket(sock);
#else
		close(sock);
#endif
		libssh2_exit();
		pthread_mutex_unlock(&libssh2_flag);
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Error during opening session channel\n");
		return OPH_LIBSSH_ERROR;
	}

	int flag = 0;
	for (;;) {
		int rc;
		do {
			char buffer[0x4000];
			rc = libssh2_channel_read(channel, buffer, sizeof(buffer));

			if (rc > 0) {
				int i;
				bytecount += rc;
				if (!flag) {
					pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "ssh submission returned:\n");
					flag = 1;
				}
				for (i = 0; i < rc; ++i)
					pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "%c\n", buffer[i]);
			} else if (rc != LIBSSH2_ERROR_EAGAIN)
				pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "ssh channel read returned %d\n", rc);
		}
		while (rc > 0);

		if (rc == LIBSSH2_ERROR_EAGAIN) {
			waitsocket(sock, session);
		} else
			break;
	}
	exitcode = 127;
	while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
		waitsocket(sock, session);

	if (rc == 0) {
		exitcode = libssh2_channel_get_exit_status(channel);
		libssh2_channel_get_exit_signal(channel, &exitsignal, NULL, NULL, NULL, NULL, NULL);
	}

	if (exitsignal)
		pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "ssh got signal %s\n", exitsignal);
	else
		pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "ssh exit code %d with: bytecount %d\n", exitcode, bytecount);

	libssh2_channel_free(channel);
	channel = NULL;

	libssh2_session_disconnect(session, "Session ended normally");
	libssh2_session_free(session);
#ifdef WIN32
	closesocket(sock);
#else
	close(sock);
#endif
	pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "Session ended normally\n");

	libssh2_exit();

	pthread_mutex_unlock(&libssh2_flag);	// Release the lock for SSH library
	pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "SSH2 library unlocked\n");

	return OPH_LIBSSH_OK;
}
int oph_odb_get_uncompleted_job_number(int parent_idjob, int *number, ophidiadb * oDB)
{
	if (!oDB || !number) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Null input parameter\n");
		return OPH_ODB_NULL_PARAM;
	}
	*number = 0;

	if (oph_odb_check_connection_to_ophidiadb(oDB)) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Unable to reconnect to OphidiaDB.\n");
		return OPH_ODB_MYSQL_ERROR;
	}

	char query[MYSQL_BUFLEN];

	int n = snprintf(query, MYSQL_BUFLEN, MYSQL_RETRIEVE_UNCOMPLETED_JOB_NUMBER, parent_idjob);
	if (n >= MYSQL_BUFLEN) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Size of query exceed query limit.\n");
		return OPH_ODB_STR_BUFF_OVERFLOW;
	}

	pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "Extract number of pending children using: %s.\n", query);
	if (mysql_query(oDB->conn, query)) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "MySQL query error: %s\n", mysql_error(oDB->conn));
		return OPH_ODB_MYSQL_ERROR;
	}

	MYSQL_RES *res;
	MYSQL_ROW row;
	res = mysql_store_result(oDB->conn);

	if (mysql_num_rows(res) < 1) {
		pmesg_safe(&global_flag, LOG_DEBUG, __FILE__, __LINE__, "No row found by query\n");
		mysql_free_result(res);
		return OPH_ODB_NO_ROW_FOUND;
	}

	if (mysql_num_rows(res) > 1) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "More than one row found by query\n");
		mysql_free_result(res);
		return OPH_ODB_TOO_MANY_ROWS;
	}

	if (mysql_field_count(oDB->conn) != 1) {
		pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "Not enough fields found by query\n");
		mysql_free_result(res);
		return OPH_ODB_TOO_MANY_ROWS;
	}

	if ((row = mysql_fetch_row(res)) != NULL) {
		if (!row[0]) {
			pmesg_safe(&global_flag, LOG_ERROR, __FILE__, __LINE__, "No parent job found\n");
			mysql_free_result(res);
			return OPH_ODB_ERROR;
		}
		*number = (int) strtol(row[0], NULL, 10);
	}

	mysql_free_result(res);

	return OPH_ODB_SUCCESS;
}
int _oph_json_add_tree_link(oph_json * json, const char *objkey, int sourcenode, int targetnode, const char *description, pthread_mutex_t * flag)
{
	if (!json || !objkey || sourcenode < 0 || targetnode < 0) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "(NULL parameters)");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	if (json->response_num == 0) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "response_num");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	unsigned int i;
	int tree_present = 0;
	for (i = 0; i < json->response_num; i++) {
		if (!strcmp(json->response[i].objkey, objkey)) {
			if (!strcmp(json->response[i].objclass, OPH_JSON_TREE)) {
				tree_present = 1;
				break;
			}
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objkey");
			return OPH_JSON_BAD_PARAM_ERROR;
		}
	}
	if (tree_present) {
		if (json->response[i].objcontent_num < 1) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objcontent_num");
			return OPH_JSON_BAD_PARAM_ERROR;
		}
		if (sourcenode != targetnode && (int) ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks_num >= (sourcenode + 1)
		    && (int) ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks_num >= (targetnode + 1)) {
			unsigned int index = 0;
			if (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links_num == 0) {
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links =
				    (oph_json_link *) malloc(sizeof(oph_json_link));
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "links");
					return OPH_JSON_MEMORY_ERROR;
				}
				index = 0;
			} else {
				char buf[20];
				memset(buf, 0, 20);
				snprintf(buf, 20, "%d", targetnode);
				unsigned int n;
				for (n = 0; n < ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links_num; n++) {
					if (!strcmp(((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links[n].node, buf)) {
						pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "targetnode");
						return OPH_JSON_BAD_PARAM_ERROR;
					}
				}
				oph_json_link *tmp = ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links;
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links =
				    (oph_json_link *) realloc(((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links,
							      sizeof(oph_json_link) *
							      (((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links_num + 1));
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links) {
					((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links = tmp;
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "links");
					return OPH_JSON_MEMORY_ERROR;
				}
				index = ((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links_num;
			}
			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links[index].description = NULL;
			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links[index].node = NULL;

			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links_num++;

			char buf[20];
			memset(buf, 0, 20);
			snprintf(buf, 20, "%d", targetnode);
			((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links[index].node = (char *) strdup(buf);
			if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links[index].node) {
				pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "targetnode");
				return OPH_JSON_MEMORY_ERROR;
			}

			if (description) {
				((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links[index].description =
				    (char *) strdup(description);
				if (!((oph_json_obj_tree *) json->response[i].objcontent)[json->response[i].objcontent_num - 1].nodelinks[sourcenode].links[index].description) {
					pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_MEMORY_ERROR, "description");
					return OPH_JSON_MEMORY_ERROR;
				}
			}
		} else {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "sourcenode/targetnode");
			return OPH_JSON_BAD_PARAM_ERROR;
		}
	} else {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, OPH_JSON_LOG_BAD_PARAM_ERROR, "objkey");
		return OPH_JSON_BAD_PARAM_ERROR;
	}

	return OPH_JSON_SUCCESS;
}
int _oph_odb_create_job(ophidiadb * oDB, char *task_string, HASHTBL * task_tbl, int nchildren, int *id_job, pthread_mutex_t * flag)
{
	if (!task_tbl) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Null input parameter task table\n");
		return OPH_ODB_NULL_PARAM;
	}

	char *username = hashtbl_get(task_tbl, OPH_ARG_USERNAME);
	if (!username) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Missing input parameter '%s'\n", OPH_ARG_USERNAME);
		return OPH_ODB_NULL_PARAM;
	}

	char *sessionid = hashtbl_get(task_tbl, OPH_ARG_SESSIONID);
	if (!sessionid) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Missing input parameter '%s'\n", OPH_ARG_SESSIONID);
		return OPH_ODB_NULL_PARAM;
	}

	char *markerid = hashtbl_get(task_tbl, OPH_ARG_MARKERID);
	if (!markerid) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Missing input parameter '%s'\n", OPH_ARG_MARKERID);
		return OPH_ODB_NULL_PARAM;
	}

	int res, id_user;
	if ((res = _oph_odb_retrieve_user_id(oDB, username, &id_user, flag))) {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to retrieve user id.\n");
		return res;
	}

	int id_session;
	if ((res = _oph_odb_retrieve_session_id(oDB, sessionid, &id_session, flag))) {
		if (res != OPH_ODB_NO_ROW_FOUND) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to retrieve session id\n");
			return res;
		}
		if ((res = _oph_odb_update_session_table(oDB, sessionid, id_user, &id_session, flag))) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to create a new entry in table 'session'\n");
			return res;
		}
	}

	if ((res = _oph_odb_retrieve_job_id(oDB, sessionid, markerid, id_job, flag))) {
		if (res != OPH_ODB_NO_ROW_FOUND) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to retrieve job id\n");
			return res;
		}
		if ((res =
		     _oph_odb_update_job_table(oDB, markerid, task_string, OPH_ODB_STATUS_PENDING_STR, id_user, id_session, nchildren, id_job, hashtbl_get(task_tbl, OPH_ARG_PARENTID),
					       hashtbl_get(task_tbl, OPH_ARG_WORKFLOWID), flag))) {
			pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Unable to create a new entry in table 'job'\n");
			return res;
		}
	} else {
		pmesg_safe(flag, LOG_ERROR, __FILE__, __LINE__, "Found a job with the same identifier '%s'\n", markerid);
		return res;
	}

	return OPH_ODB_SUCCESS;
}