feat: import evidence from GTK interface
This commit is contained in:
parent
0912e7263e
commit
6c34287feb
10 changed files with 2658 additions and 231 deletions
27
Makefile
27
Makefile
|
|
@ -54,6 +54,7 @@ TEST_TOOL_INITIALIZER := tests/test_tool_initializer
|
||||||
TEST_FILE_HASH := tests/test_file_hash
|
TEST_FILE_HASH := tests/test_file_hash
|
||||||
TEST_EVIDENCE_COPY := tests/test_evidence_copy
|
TEST_EVIDENCE_COPY := tests/test_evidence_copy
|
||||||
TEST_EVIDENCE_IMPORTER := tests/test_evidence_importer
|
TEST_EVIDENCE_IMPORTER := tests/test_evidence_importer
|
||||||
|
TEST_EVIDENCE_IMPORT_TASK := tests/test_evidence_import_task
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -245,6 +246,25 @@ $(TEST_EVIDENCE_IMPORTER): \
|
||||||
-DEVIDENCE_IMPORTER_ENABLE_TEST_HOOKS \
|
-DEVIDENCE_IMPORTER_ENABLE_TEST_HOOKS \
|
||||||
$^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
$^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
|
$(TEST_EVIDENCE_IMPORT_TASK): \
|
||||||
|
tests/test_evidence_import_task.c \
|
||||||
|
src/core/evidence_import_task.c \
|
||||||
|
src/core/evidence_importer.c \
|
||||||
|
src/core/evidence_copy.c \
|
||||||
|
src/core/file_hash.c \
|
||||||
|
src/core/background_task.c \
|
||||||
|
src/core/task_manager.c \
|
||||||
|
src/dao/evidence_dao.c \
|
||||||
|
src/models/evidence_record.c \
|
||||||
|
src/database/database.c \
|
||||||
|
src/database/schema.c \
|
||||||
|
src/database/statement.c \
|
||||||
|
src/database/transaction.c \
|
||||||
|
src/database/error.c
|
||||||
|
$(CC) $(TEST_CFLAGS) \
|
||||||
|
-DEVIDENCE_IMPORTER_ENABLE_TEST_HOOKS \
|
||||||
|
$^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
test: \
|
test: \
|
||||||
$(TEST_NODE) \
|
$(TEST_NODE) \
|
||||||
$(TEST_TREE_MODEL) \
|
$(TEST_TREE_MODEL) \
|
||||||
|
|
@ -268,7 +288,8 @@ test: \
|
||||||
$(TEST_TOOL_INITIALIZER) \
|
$(TEST_TOOL_INITIALIZER) \
|
||||||
$(TEST_FILE_HASH) \
|
$(TEST_FILE_HASH) \
|
||||||
$(TEST_EVIDENCE_COPY) \
|
$(TEST_EVIDENCE_COPY) \
|
||||||
$(TEST_EVIDENCE_IMPORTER)
|
$(TEST_EVIDENCE_IMPORTER) \
|
||||||
|
$(TEST_EVIDENCE_IMPORT_TASK)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -293,6 +314,7 @@ test: \
|
||||||
@$(TEST_FILE_HASH)
|
@$(TEST_FILE_HASH)
|
||||||
@$(TEST_EVIDENCE_COPY)
|
@$(TEST_EVIDENCE_COPY)
|
||||||
@$(TEST_EVIDENCE_IMPORTER)
|
@$(TEST_EVIDENCE_IMPORTER)
|
||||||
|
@$(TEST_EVIDENCE_IMPORT_TASK)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -325,7 +347,8 @@ clean:
|
||||||
$(TEST_TOOL_INITIALIZER) \
|
$(TEST_TOOL_INITIALIZER) \
|
||||||
$(TEST_FILE_HASH) \
|
$(TEST_FILE_HASH) \
|
||||||
$(TEST_EVIDENCE_COPY) \
|
$(TEST_EVIDENCE_COPY) \
|
||||||
$(TEST_EVIDENCE_IMPORTER)
|
$(TEST_EVIDENCE_IMPORTER) \
|
||||||
|
$(TEST_EVIDENCE_IMPORT_TASK)
|
||||||
|
|
||||||
|
|
||||||
.PHONY: clean run test
|
.PHONY: clean run test
|
||||||
|
|
|
||||||
89
include/core/evidence_import_task.h
Normal file
89
include/core/evidence_import_task.h
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file evidence_import_task.h
|
||||||
|
* @brief Tâche asynchrone d’import d’une preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_EVIDENCE_IMPORT_TASK_H
|
||||||
|
#define LABFY_INVESTIGATION_EVIDENCE_IMPORT_TASK_H
|
||||||
|
|
||||||
|
#include "core/background_task.h"
|
||||||
|
#include "core/task_manager.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Codes d’erreur propres à la tâche d’import.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_INVALID_ARGUMENT,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_DATABASE,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_IMPORT
|
||||||
|
} EvidenceImportTaskError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Domaine d’erreur du module.
|
||||||
|
*/
|
||||||
|
#define EVIDENCE_IMPORT_TASK_ERROR \
|
||||||
|
evidence_import_task_error_quark()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Paramètres nécessaires à une tâche d’import.
|
||||||
|
*
|
||||||
|
* Toutes les chaînes sont copiées avant le démarrage du worker.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *database_path;
|
||||||
|
|
||||||
|
const char *source_path;
|
||||||
|
const char *destination_directory;
|
||||||
|
const char *relative_directory;
|
||||||
|
|
||||||
|
const char *type_identifier;
|
||||||
|
const char *collected_at;
|
||||||
|
const char *source;
|
||||||
|
const char *description;
|
||||||
|
} EvidenceImportTaskRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le domaine d’erreur du module.
|
||||||
|
*
|
||||||
|
* @return Quark GLib du domaine d’erreur.
|
||||||
|
*/
|
||||||
|
GQuark evidence_import_task_error_quark(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée, enregistre et démarre une tâche d’import.
|
||||||
|
*
|
||||||
|
* La tâche ouvre sa propre connexion SQLite dans le thread secondaire.
|
||||||
|
*
|
||||||
|
* En cas de succès :
|
||||||
|
*
|
||||||
|
* - TaskManager conserve une référence ;
|
||||||
|
* - le worker conserve une référence pendant son exécution ;
|
||||||
|
* - l’appelant reçoit sa référence initiale et doit la libérer avec
|
||||||
|
* background_task_unref().
|
||||||
|
*
|
||||||
|
* completion_data est transféré à BackgroundTask uniquement si le
|
||||||
|
* démarrage réussit. En cas d’échec, l’appelant en reste propriétaire.
|
||||||
|
*
|
||||||
|
* @param task_manager Gestionnaire recevant la tâche.
|
||||||
|
* @param request Paramètres de l’import.
|
||||||
|
* @param completion_callback Callback final facultatif.
|
||||||
|
* @param completion_data Données du callback final.
|
||||||
|
* @param completion_data_destroy Destructeur de completion_data.
|
||||||
|
* @param error Emplacement facultatif recevant une erreur.
|
||||||
|
*
|
||||||
|
* @return Nouvelle tâche démarrée, ou NULL.
|
||||||
|
*/
|
||||||
|
BackgroundTask *evidence_import_task_start(
|
||||||
|
TaskManager *task_manager,
|
||||||
|
const EvidenceImportTaskRequest *request,
|
||||||
|
BackgroundTaskCompletionCallback completion_callback,
|
||||||
|
gpointer completion_data,
|
||||||
|
GDestroyNotify completion_data_destroy,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
45
include/views/file_dialog.h
Normal file
45
include/views/file_dialog.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file file_dialog.h
|
||||||
|
* @brief Interface du dialogue de sélection d’un fichier de preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_FILE_DIALOG_H
|
||||||
|
#define LABFY_INVESTIGATION_FILE_DIALOG_H
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fonction appelée après la fermeture du sélecteur.
|
||||||
|
*
|
||||||
|
* Cas possibles :
|
||||||
|
*
|
||||||
|
* - succès : file_path non NULL et error NULL ;
|
||||||
|
* - annulation : file_path NULL et error NULL ;
|
||||||
|
* - erreur : file_path NULL et error non NULL.
|
||||||
|
*
|
||||||
|
* Le chemin et l’erreur restent valides uniquement pendant l’appel.
|
||||||
|
*
|
||||||
|
* @param file_path Chemin local sélectionné, ou NULL.
|
||||||
|
* @param error Erreur de sélection, ou NULL.
|
||||||
|
* @param user_data Données transmises lors de l’ouverture.
|
||||||
|
*/
|
||||||
|
typedef void (*FileDialogCallback)(
|
||||||
|
const char *file_path,
|
||||||
|
const GError *error,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ouvre un dialogue permettant de sélectionner un fichier.
|
||||||
|
*
|
||||||
|
* @param parent Fenêtre parente, éventuellement NULL.
|
||||||
|
* @param callback Fonction appelée lorsque le dialogue est terminé.
|
||||||
|
* @param user_data Données transmises au callback.
|
||||||
|
*/
|
||||||
|
void file_dialog_select_file(
|
||||||
|
GtkWindow *parent,
|
||||||
|
FileDialogCallback callback,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -27,6 +27,16 @@ typedef void (*MainWindowNewInvestigationCallback)(
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback appelé lorsque l'utilisateur demande
|
||||||
|
* l'import d'une preuve.
|
||||||
|
*
|
||||||
|
* @param user_data Données utilisateur associées au callback.
|
||||||
|
*/
|
||||||
|
typedef void (*MainWindowImportEvidenceCallback)(
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Définit le callback du bouton « Nouvelle enquête ».
|
* @brief Définit le callback du bouton « Nouvelle enquête ».
|
||||||
*
|
*
|
||||||
|
|
@ -163,16 +173,6 @@ typedef void (*MainWindowQuitCallback)(
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback appelé lorsque l'utilisateur demande une tâche
|
|
||||||
* de démonstration.
|
|
||||||
*
|
|
||||||
* @param user_data Données utilisateur associées au callback.
|
|
||||||
*/
|
|
||||||
typedef void (*MainWindowDemoTaskCallback)(
|
|
||||||
gpointer user_data
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Définit le callback du bouton « Ouvrir une enquête ».
|
* @brief Définit le callback du bouton « Ouvrir une enquête ».
|
||||||
*
|
*
|
||||||
|
|
@ -204,20 +204,31 @@ void main_window_set_quit_callback(
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Définit le callback du bouton « Tâche de test ».
|
* @brief Définit le callback de l'action « Importer une preuve ».
|
||||||
*
|
*
|
||||||
* Ce bouton est temporaire et sert à valider le panneau d'activité.
|
* MainWindow transmet uniquement la demande au contrôleur.
|
||||||
*
|
*
|
||||||
* @param main_window Fenêtre principale.
|
* @param main_window Fenêtre principale.
|
||||||
* @param callback Fonction appelée lors du clic.
|
* @param callback Fonction appelée lors du clic.
|
||||||
* @param user_data Données transmises au callback.
|
* @param user_data Données transmises au callback.
|
||||||
*/
|
*/
|
||||||
void main_window_set_demo_task_callback(
|
void main_window_set_import_evidence_callback(
|
||||||
MainWindow *main_window,
|
MainWindow *main_window,
|
||||||
MainWindowDemoTaskCallback callback,
|
MainWindowImportEvidenceCallback callback,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Active ou désactive l'action d'import d'une preuve.
|
||||||
|
*
|
||||||
|
* @param main_window Fenêtre principale.
|
||||||
|
* @param enabled TRUE pour autoriser l'import.
|
||||||
|
*/
|
||||||
|
void main_window_set_import_evidence_enabled(
|
||||||
|
MainWindow *main_window,
|
||||||
|
gboolean enabled
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Libère les ressources de la fenêtre.
|
* @brief Libère les ressources de la fenêtre.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,30 @@
|
||||||
#include "core/task_manager.h"
|
#include "core/task_manager.h"
|
||||||
#include "core/background_task.h"
|
#include "core/background_task.h"
|
||||||
#include "core/tool_initializer.h"
|
#include "core/tool_initializer.h"
|
||||||
|
#include "views/file_dialog.h"
|
||||||
|
#include "core/evidence_import_task.h"
|
||||||
|
#include "models/evidence_record.h"
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Identifiant unique utilisé par GLib pour l'application.
|
* @brief Identifiant unique utilisé par GLib pour l'application.
|
||||||
*/
|
*/
|
||||||
#define APPLICATION_ID "com.labfytools.investigation"
|
#define APPLICATION_ID "com.labfytools.investigation"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dossier physique recevant les documents importés.
|
||||||
|
*/
|
||||||
|
#define APPLICATION_EVIDENCE_DIRECTORY \
|
||||||
|
"01_Preuves_Originales/Documents"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type utilisé avant l’ajout du formulaire de métadonnées.
|
||||||
|
*/
|
||||||
|
#define APPLICATION_DEFAULT_EVIDENCE_TYPE \
|
||||||
|
"document"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Erreurs produites lors du chargement d'une enquête.
|
* @brief Erreurs produites lors du chargement d'une enquête.
|
||||||
*/
|
*/
|
||||||
|
|
@ -71,6 +87,78 @@ struct Application
|
||||||
ToolInitializer *tool_initializer;
|
ToolInitializer *tool_initializer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contexte conservé jusqu’à la fin d’un import.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Application *application;
|
||||||
|
char *investigation_root_path;
|
||||||
|
} ApplicationEvidenceImportContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère le contexte d’un import asynchrone.
|
||||||
|
*/
|
||||||
|
static void application_evidence_import_context_free(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ApplicationEvidenceImportContext *context =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
if (context == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
context->investigation_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie que l’enquête active correspond à un chemin racine.
|
||||||
|
*/
|
||||||
|
static gboolean application_session_matches_root(
|
||||||
|
const Application *application,
|
||||||
|
const char *expected_root_path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const InvestigationProject *project = NULL;
|
||||||
|
const char *current_root_path = NULL;
|
||||||
|
|
||||||
|
if (application == NULL ||
|
||||||
|
application->session == NULL ||
|
||||||
|
expected_root_path == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
project =
|
||||||
|
investigation_session_get_project(
|
||||||
|
application->session
|
||||||
|
);
|
||||||
|
|
||||||
|
if (project == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_root_path =
|
||||||
|
investigation_project_get_root_path(
|
||||||
|
project
|
||||||
|
);
|
||||||
|
|
||||||
|
return g_strcmp0(
|
||||||
|
current_root_path,
|
||||||
|
expected_root_path
|
||||||
|
) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void application_present_error(
|
static void application_present_error(
|
||||||
Application *application,
|
Application *application,
|
||||||
const char *title,
|
const char *title,
|
||||||
|
|
@ -359,6 +447,11 @@ static gboolean application_install_session(
|
||||||
root_path
|
root_path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
main_window_set_import_evidence_enabled(
|
||||||
|
application->main_window,
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -775,265 +868,631 @@ static void application_on_open_investigation_requested(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Exécute une tâche temporaire servant à tester le panneau.
|
* @brief Reconstruit et remplace l’arborescence active.
|
||||||
*
|
*
|
||||||
* Cette fonction s'exécute dans un thread secondaire.
|
* Le nouveau modèle est entièrement construit avant que l’ancien
|
||||||
|
* soit détaché et libéré.
|
||||||
*
|
*
|
||||||
* @param task Tâche en cours.
|
* @param application Application concernée.
|
||||||
* @param cancellable Objet d'annulation.
|
* @param investigation_root_path Racine à parcourir.
|
||||||
* @param worker_data Données inutilisées.
|
|
||||||
* @param result Emplacement recevant le résultat.
|
|
||||||
* @param error Emplacement recevant une erreur.
|
|
||||||
*
|
*
|
||||||
* @return TRUE en cas de succès, sinon FALSE.
|
* @return TRUE si le remplacement a réussi.
|
||||||
*/
|
*/
|
||||||
static gboolean application_demo_task_worker(
|
static gboolean application_refresh_investigation_tree(
|
||||||
BackgroundTask *task,
|
Application *application,
|
||||||
GCancellable *cancellable,
|
const char *investigation_root_path
|
||||||
gpointer worker_data,
|
|
||||||
gpointer *result,
|
|
||||||
GError **error
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
guint step = 0;
|
InvestigationTreeModel *new_tree_model = NULL;
|
||||||
char status_message[64];
|
InvestigationTreeModel *old_tree_model = NULL;
|
||||||
|
|
||||||
(void) worker_data;
|
if (application == NULL ||
|
||||||
|
application->main_window == NULL ||
|
||||||
if (task == NULL ||
|
investigation_root_path == NULL ||
|
||||||
cancellable == NULL ||
|
investigation_root_path[0] == '\0')
|
||||||
result == NULL ||
|
|
||||||
error == NULL)
|
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (step = 0; step <= 20; step++)
|
new_tree_model =
|
||||||
{
|
investigation_tree_builder_build(
|
||||||
if (g_cancellable_set_error_if_cancelled(
|
investigation_root_path
|
||||||
cancellable,
|
);
|
||||||
error
|
|
||||||
))
|
if (new_tree_model == NULL)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_snprintf(
|
old_tree_model =
|
||||||
status_message,
|
application->tree_model;
|
||||||
sizeof(status_message),
|
|
||||||
"Étape %u sur 20",
|
/*
|
||||||
step
|
* MainWindow transmet le nouveau modèle à la Sidebar.
|
||||||
|
*
|
||||||
|
* InvestigationTreeView détache d’abord son ancien modèle GTK,
|
||||||
|
* puis construit le nouveau. L’ancien modèle métier reste vivant
|
||||||
|
* pendant toute cette opération.
|
||||||
|
*/
|
||||||
|
main_window_set_tree_model(
|
||||||
|
application->main_window,
|
||||||
|
new_tree_model
|
||||||
);
|
);
|
||||||
|
|
||||||
background_task_report_progress(
|
application->tree_model =
|
||||||
task,
|
new_tree_model;
|
||||||
(double) step / 20.0,
|
|
||||||
status_message
|
|
||||||
);
|
|
||||||
|
|
||||||
if (step < 20)
|
/*
|
||||||
{
|
* La vue ne référence plus les anciens nœuds.
|
||||||
g_usleep(
|
*/
|
||||||
500000
|
investigation_tree_model_free(
|
||||||
);
|
old_tree_model
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*result = g_strdup(
|
|
||||||
"Tâche de démonstration terminée."
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Journalise la fin de la tâche de démonstration.
|
* @brief Traite la fin d’une tâche d’import.
|
||||||
*
|
*
|
||||||
* @param task Tâche terminée.
|
* @param task Tâche d’import terminée.
|
||||||
* @param user_data Données inutilisées.
|
* @param user_data Contexte ApplicationEvidenceImportContext.
|
||||||
*/
|
*/
|
||||||
static void application_demo_task_completed(
|
static void application_on_evidence_import_completed(
|
||||||
BackgroundTask *task,
|
BackgroundTask *task,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
ApplicationEvidenceImportContext *context =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
Application *application = NULL;
|
||||||
|
|
||||||
BackgroundTaskState state;
|
BackgroundTaskState state;
|
||||||
const char *result = NULL;
|
|
||||||
|
EvidenceRecord *evidence_record = NULL;
|
||||||
|
|
||||||
|
const char *original_name = NULL;
|
||||||
|
|
||||||
|
char *status_message = NULL;
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
(void) user_data;
|
if (task == NULL ||
|
||||||
|
context == NULL)
|
||||||
if (task == NULL)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = background_task_get_state(
|
application =
|
||||||
|
context->application;
|
||||||
|
|
||||||
|
if (application == NULL ||
|
||||||
|
application->main_window == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
main_window_set_import_evidence_enabled(
|
||||||
|
application->main_window,
|
||||||
|
application->session != NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
state =
|
||||||
|
background_task_get_state(
|
||||||
task
|
task
|
||||||
);
|
);
|
||||||
|
|
||||||
if (state == BACKGROUND_TASK_STATE_COMPLETED)
|
if (state ==
|
||||||
|
BACKGROUND_TASK_STATE_COMPLETED)
|
||||||
{
|
{
|
||||||
result = background_task_get_result(
|
evidence_record =
|
||||||
|
background_task_get_result(
|
||||||
task
|
task
|
||||||
);
|
);
|
||||||
|
|
||||||
g_print(
|
if (evidence_record == NULL)
|
||||||
"%s\n",
|
|
||||||
result != NULL
|
|
||||||
? result
|
|
||||||
: "Tâche terminée."
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == BACKGROUND_TASK_STATE_CANCELLED)
|
|
||||||
{
|
{
|
||||||
g_print(
|
application_present_error(
|
||||||
"Tâche de démonstration annulée.\n"
|
application,
|
||||||
|
"Import incomplet",
|
||||||
|
"La tâche est terminée sans fournir de preuve."
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = background_task_dup_error(
|
original_name =
|
||||||
|
evidence_record_get_original_name(
|
||||||
|
evidence_record
|
||||||
|
);
|
||||||
|
|
||||||
|
if (application_session_matches_root(
|
||||||
|
application,
|
||||||
|
context->investigation_root_path
|
||||||
|
))
|
||||||
|
{
|
||||||
|
if (application_refresh_investigation_tree(
|
||||||
|
application,
|
||||||
|
context->investigation_root_path
|
||||||
|
))
|
||||||
|
{
|
||||||
|
status_message =
|
||||||
|
g_strdup_printf(
|
||||||
|
"Preuve importée : %s",
|
||||||
|
original_name != NULL
|
||||||
|
? original_name
|
||||||
|
: "(nom indisponible)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* L’import reste valide même si le rafraîchissement visuel
|
||||||
|
* échoue. Le fichier et la ligne SQLite ne doivent surtout
|
||||||
|
* pas être présentés comme un échec.
|
||||||
|
*/
|
||||||
|
status_message =
|
||||||
|
g_strdup_printf(
|
||||||
|
"Preuve importée : %s — "
|
||||||
|
"arborescence non actualisée",
|
||||||
|
original_name != NULL
|
||||||
|
? original_name
|
||||||
|
: "(nom indisponible)"
|
||||||
|
);
|
||||||
|
|
||||||
|
g_warning(
|
||||||
|
"La preuve a été importée, mais l’arborescence de '%s' "
|
||||||
|
"n’a pas pu être reconstruite.",
|
||||||
|
context->investigation_root_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
main_window_set_status(
|
||||||
|
application->main_window,
|
||||||
|
status_message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g_message(
|
||||||
|
"Preuve importée dans '%s' : %s",
|
||||||
|
context->investigation_root_path,
|
||||||
|
original_name != NULL
|
||||||
|
? original_name
|
||||||
|
: "(nom indisponible)"
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
status_message
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state ==
|
||||||
|
BACKGROUND_TASK_STATE_CANCELLED)
|
||||||
|
{
|
||||||
|
if (application_session_matches_root(
|
||||||
|
application,
|
||||||
|
context->investigation_root_path
|
||||||
|
))
|
||||||
|
{
|
||||||
|
main_window_set_status(
|
||||||
|
application->main_window,
|
||||||
|
"Import de preuve annulé."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error =
|
||||||
|
background_task_dup_error(
|
||||||
task
|
task
|
||||||
);
|
);
|
||||||
|
|
||||||
g_warning(
|
g_warning(
|
||||||
"La tâche de démonstration a échoué : %s",
|
"L’import de la preuve a échoué : %s",
|
||||||
error != NULL
|
error != NULL
|
||||||
? error->message
|
? error->message
|
||||||
: "erreur inconnue"
|
: "erreur inconnue"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Import impossible",
|
||||||
|
error != NULL
|
||||||
|
? error->message
|
||||||
|
: "La preuve n’a pas pu être importée."
|
||||||
|
);
|
||||||
|
|
||||||
g_clear_error(
|
g_clear_error(
|
||||||
&error
|
&error
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Crée et lance une tâche de démonstration.
|
* @brief Prépare et démarre l’import asynchrone d’un fichier.
|
||||||
*
|
|
||||||
* @param user_data Pointeur vers Application.
|
|
||||||
*/
|
*/
|
||||||
static void application_on_demo_task_requested(
|
static void application_start_evidence_import(
|
||||||
gpointer user_data
|
Application *application,
|
||||||
|
const char *file_path
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Application *application = user_data;
|
const InvestigationProject *project = NULL;
|
||||||
|
|
||||||
|
const char *root_path = NULL;
|
||||||
|
const char *database_path = NULL;
|
||||||
|
|
||||||
|
EvidenceImportTaskRequest request =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
ApplicationEvidenceImportContext *context =
|
||||||
|
NULL;
|
||||||
|
|
||||||
BackgroundTask *task = NULL;
|
BackgroundTask *task = NULL;
|
||||||
|
|
||||||
|
char *destination_directory = NULL;
|
||||||
|
char *source_name = NULL;
|
||||||
|
char *status_message = NULL;
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
if (application == NULL ||
|
if (application == NULL ||
|
||||||
application->task_manager == NULL)
|
application->main_window == NULL ||
|
||||||
|
application->session == NULL ||
|
||||||
|
application->task_manager == NULL ||
|
||||||
|
file_path == NULL ||
|
||||||
|
file_path[0] == '\0')
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = background_task_new(
|
project =
|
||||||
"Tâche de démonstration"
|
investigation_session_get_project(
|
||||||
|
application->session
|
||||||
|
);
|
||||||
|
|
||||||
|
if (project == NULL)
|
||||||
|
{
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Import impossible",
|
||||||
|
"La session ne fournit aucun projet d’enquête."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
root_path =
|
||||||
|
investigation_project_get_root_path(
|
||||||
|
project
|
||||||
|
);
|
||||||
|
|
||||||
|
database_path =
|
||||||
|
investigation_project_get_database_path(
|
||||||
|
project
|
||||||
|
);
|
||||||
|
|
||||||
|
if (root_path == NULL ||
|
||||||
|
root_path[0] == '\0' ||
|
||||||
|
database_path == NULL ||
|
||||||
|
database_path[0] == '\0')
|
||||||
|
{
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Import impossible",
|
||||||
|
"Les chemins de l’enquête sont invalides."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination_directory =
|
||||||
|
g_build_filename(
|
||||||
|
root_path,
|
||||||
|
"01_Preuves_Originales",
|
||||||
|
"Documents",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (destination_directory == NULL)
|
||||||
|
{
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Import impossible",
|
||||||
|
"Impossible de construire le dossier de destination."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le dossier devrait exister dans une enquête normale.
|
||||||
|
* Cette création rend néanmoins l’import robuste face à un dossier
|
||||||
|
* supprimé accidentellement.
|
||||||
|
*/
|
||||||
|
if (g_mkdir_with_parents(
|
||||||
|
destination_directory,
|
||||||
|
0700
|
||||||
|
) != 0)
|
||||||
|
{
|
||||||
|
status_message =
|
||||||
|
g_strdup_printf(
|
||||||
|
"Impossible de préparer le dossier '%s' : %s",
|
||||||
|
destination_directory,
|
||||||
|
g_strerror(errno)
|
||||||
|
);
|
||||||
|
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Import impossible",
|
||||||
|
status_message
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
status_message
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
destination_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context =
|
||||||
|
g_try_new0(
|
||||||
|
ApplicationEvidenceImportContext,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (context == NULL)
|
||||||
|
{
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Import impossible",
|
||||||
|
"Impossible d’allouer le contexte de la tâche."
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
destination_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->application =
|
||||||
|
application;
|
||||||
|
|
||||||
|
context->investigation_root_path =
|
||||||
|
g_strdup(
|
||||||
|
root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
if (context->investigation_root_path == NULL)
|
||||||
|
{
|
||||||
|
application_evidence_import_context_free(
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
destination_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Import impossible",
|
||||||
|
"Impossible de conserver le chemin de l’enquête."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.database_path =
|
||||||
|
database_path;
|
||||||
|
|
||||||
|
request.source_path =
|
||||||
|
file_path;
|
||||||
|
|
||||||
|
request.destination_directory =
|
||||||
|
destination_directory;
|
||||||
|
|
||||||
|
request.relative_directory =
|
||||||
|
APPLICATION_EVIDENCE_DIRECTORY;
|
||||||
|
|
||||||
|
request.type_identifier =
|
||||||
|
APPLICATION_DEFAULT_EVIDENCE_TYPE;
|
||||||
|
|
||||||
|
request.collected_at = NULL;
|
||||||
|
request.source = NULL;
|
||||||
|
request.description = NULL;
|
||||||
|
|
||||||
|
task =
|
||||||
|
evidence_import_task_start(
|
||||||
|
application->task_manager,
|
||||||
|
&request,
|
||||||
|
application_on_evidence_import_completed,
|
||||||
|
context,
|
||||||
|
application_evidence_import_context_free,
|
||||||
|
&error
|
||||||
);
|
);
|
||||||
|
|
||||||
if (task == NULL)
|
if (task == NULL)
|
||||||
{
|
{
|
||||||
application_present_error(
|
|
||||||
application,
|
|
||||||
"Tâche impossible",
|
|
||||||
"La tâche de démonstration n'a pas pu être créée."
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Le manager prend une référence supplémentaire.
|
* La tâche n’a pas pris possession du contexte.
|
||||||
*/
|
*/
|
||||||
if (!task_manager_add(
|
application_evidence_import_context_free(
|
||||||
application->task_manager,
|
context
|
||||||
task,
|
|
||||||
&error
|
|
||||||
))
|
|
||||||
{
|
|
||||||
g_warning(
|
|
||||||
"Impossible d'ajouter la tâche : %s",
|
|
||||||
error != NULL
|
|
||||||
? error->message
|
|
||||||
: "erreur inconnue"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
application_present_error(
|
application_present_error(
|
||||||
application,
|
application,
|
||||||
"Tâche impossible",
|
"Import impossible",
|
||||||
error != NULL
|
error != NULL
|
||||||
? error->message
|
? error->message
|
||||||
: "La tâche n'a pas pu être ajoutée."
|
: "La tâche d’import n’a pas pu être démarrée."
|
||||||
);
|
);
|
||||||
|
|
||||||
g_clear_error(
|
g_clear_error(
|
||||||
&error
|
&error
|
||||||
);
|
);
|
||||||
|
|
||||||
background_task_unref(
|
g_free(
|
||||||
task
|
destination_directory
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!background_task_start(
|
|
||||||
task,
|
|
||||||
application_demo_task_worker,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
g_free,
|
|
||||||
application_demo_task_completed,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
&error
|
|
||||||
))
|
|
||||||
{
|
|
||||||
g_warning(
|
|
||||||
"Impossible de démarrer la tâche : %s",
|
|
||||||
error != NULL
|
|
||||||
? error->message
|
|
||||||
: "erreur inconnue"
|
|
||||||
);
|
|
||||||
|
|
||||||
application_present_error(
|
|
||||||
application,
|
|
||||||
"Démarrage impossible",
|
|
||||||
error != NULL
|
|
||||||
? error->message
|
|
||||||
: "La tâche n'a pas pu être démarrée."
|
|
||||||
);
|
|
||||||
|
|
||||||
g_clear_error(
|
|
||||||
&error
|
|
||||||
);
|
|
||||||
|
|
||||||
task_manager_remove(
|
|
||||||
application->task_manager,
|
|
||||||
task
|
|
||||||
);
|
|
||||||
|
|
||||||
background_task_unref(
|
|
||||||
task
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* La référence locale n'est plus nécessaire :
|
* Le TaskManager et le worker conservent désormais leurs références.
|
||||||
|
*/
|
||||||
|
background_task_unref(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
main_window_set_import_evidence_enabled(
|
||||||
|
application->main_window,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
source_name =
|
||||||
|
g_path_get_basename(
|
||||||
|
file_path
|
||||||
|
);
|
||||||
|
|
||||||
|
status_message =
|
||||||
|
g_strdup_printf(
|
||||||
|
"Import en cours : %s",
|
||||||
|
source_name != NULL
|
||||||
|
? source_name
|
||||||
|
: file_path
|
||||||
|
);
|
||||||
|
|
||||||
|
main_window_set_status(
|
||||||
|
application->main_window,
|
||||||
|
status_message
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
status_message
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
source_name
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
destination_directory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Traite le fichier de preuve sélectionné.
|
||||||
*
|
*
|
||||||
* - TaskManager conserve une référence ;
|
* @param file_path Chemin local sélectionné, ou NULL.
|
||||||
* - BackgroundTask conserve une référence interne pendant
|
* @param error Erreur de sélection, ou NULL.
|
||||||
* l'exécution.
|
* @param user_data Pointeur vers Application.
|
||||||
*/
|
*/
|
||||||
background_task_unref(
|
static void application_on_evidence_file_selected(
|
||||||
task
|
const char *file_path,
|
||||||
|
const GError *error,
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Application *application =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
if (application == NULL ||
|
||||||
|
application->main_window == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Une annulation ne constitue pas une erreur.
|
||||||
|
*/
|
||||||
|
if (file_path == NULL &&
|
||||||
|
error == NULL)
|
||||||
|
{
|
||||||
|
main_window_set_status(
|
||||||
|
application->main_window,
|
||||||
|
"Import de preuve annulé."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_warning(
|
||||||
|
"Impossible de sélectionner le fichier : %s",
|
||||||
|
error->message
|
||||||
|
);
|
||||||
|
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Sélection impossible",
|
||||||
|
error->message
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_path == NULL ||
|
||||||
|
file_path[0] == '\0')
|
||||||
|
{
|
||||||
|
application_present_error(
|
||||||
|
application,
|
||||||
|
"Sélection impossible",
|
||||||
|
"Le chemin du fichier sélectionné est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
application_start_evidence_import(
|
||||||
|
application,
|
||||||
|
file_path
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Traite la demande d'import d'une preuve.
|
||||||
|
*
|
||||||
|
* Le sélecteur de fichier sera ajouté à l'étape suivante.
|
||||||
|
*
|
||||||
|
* @param user_data Pointeur vers Application.
|
||||||
|
*/
|
||||||
|
static void application_on_import_evidence_requested(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Application *application = user_data;
|
||||||
|
|
||||||
|
if (application == NULL ||
|
||||||
|
application->main_window == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (application->session == NULL)
|
||||||
|
{
|
||||||
|
main_window_set_import_evidence_enabled(
|
||||||
|
application->main_window,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_dialog_select_file(
|
||||||
|
main_window_get_window(
|
||||||
|
application->main_window
|
||||||
|
),
|
||||||
|
application_on_evidence_file_selected,
|
||||||
|
application
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1183,12 +1642,17 @@ static void application_on_activate(
|
||||||
application
|
application
|
||||||
);
|
);
|
||||||
|
|
||||||
main_window_set_demo_task_callback(
|
main_window_set_import_evidence_callback(
|
||||||
application->main_window,
|
application->main_window,
|
||||||
application_on_demo_task_requested,
|
application_on_import_evidence_requested,
|
||||||
application
|
application
|
||||||
);
|
);
|
||||||
|
|
||||||
|
main_window_set_import_evidence_enabled(
|
||||||
|
application->main_window,
|
||||||
|
application->session != NULL
|
||||||
|
);
|
||||||
|
|
||||||
main_window_set_quit_callback(
|
main_window_set_quit_callback(
|
||||||
application->main_window,
|
application->main_window,
|
||||||
application_on_quit_requested,
|
application_on_quit_requested,
|
||||||
|
|
|
||||||
663
src/core/evidence_import_task.c
Normal file
663
src/core/evidence_import_task.c
Normal file
|
|
@ -0,0 +1,663 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file evidence_import_task.c
|
||||||
|
* @brief Exécution asynchrone de l’import d’une preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "core/evidence_import_task.h"
|
||||||
|
|
||||||
|
#include "core/evidence_importer.h"
|
||||||
|
#include "database/database.h"
|
||||||
|
#include "models/evidence_record.h"
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copie privée des paramètres nécessaires au worker.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *database_path;
|
||||||
|
|
||||||
|
char *source_path;
|
||||||
|
char *destination_directory;
|
||||||
|
char *relative_directory;
|
||||||
|
|
||||||
|
char *type_identifier;
|
||||||
|
char *collected_at;
|
||||||
|
char *source;
|
||||||
|
char *description;
|
||||||
|
} EvidenceImportTaskData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère les données privées du worker.
|
||||||
|
*/
|
||||||
|
static void evidence_import_task_data_free(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceImportTaskData *task_data =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
if (task_data == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->description
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->source
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->collected_at
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->type_identifier
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->relative_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->destination_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->source_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie les paramètres obligatoires.
|
||||||
|
*/
|
||||||
|
static gboolean evidence_import_task_request_is_valid(
|
||||||
|
const EvidenceImportTaskRequest *request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (request == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->database_path == NULL ||
|
||||||
|
request->database_path[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->source_path == NULL ||
|
||||||
|
request->source_path[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->destination_directory == NULL ||
|
||||||
|
request->destination_directory[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->relative_directory == NULL ||
|
||||||
|
request->relative_directory[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->type_identifier == NULL ||
|
||||||
|
request->type_identifier[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copie les paramètres avant le lancement du thread.
|
||||||
|
*/
|
||||||
|
static EvidenceImportTaskData *
|
||||||
|
evidence_import_task_data_new(
|
||||||
|
const EvidenceImportTaskRequest *request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceImportTaskData *task_data =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (!evidence_import_task_request_is_valid(
|
||||||
|
request
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_data =
|
||||||
|
g_try_new0(
|
||||||
|
EvidenceImportTaskData,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task_data == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_data->database_path =
|
||||||
|
g_strdup(
|
||||||
|
request->database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->source_path =
|
||||||
|
g_strdup(
|
||||||
|
request->source_path
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->destination_directory =
|
||||||
|
g_strdup(
|
||||||
|
request->destination_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->relative_directory =
|
||||||
|
g_strdup(
|
||||||
|
request->relative_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->type_identifier =
|
||||||
|
g_strdup(
|
||||||
|
request->type_identifier
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->collected_at =
|
||||||
|
g_strdup(
|
||||||
|
request->collected_at
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->source =
|
||||||
|
g_strdup(
|
||||||
|
request->source
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->description =
|
||||||
|
g_strdup(
|
||||||
|
request->description
|
||||||
|
);
|
||||||
|
|
||||||
|
return task_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark evidence_import_task_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string(
|
||||||
|
"evidence-import-task-error-quark"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Traduit l’annulation métier en annulation GIO.
|
||||||
|
*
|
||||||
|
* BackgroundTask reconnaît une annulation uniquement avec :
|
||||||
|
*
|
||||||
|
* G_IO_ERROR / G_IO_ERROR_CANCELLED.
|
||||||
|
*/
|
||||||
|
static void evidence_import_task_propagate_import_error(
|
||||||
|
GError **error,
|
||||||
|
GError *import_error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (import_error != NULL &&
|
||||||
|
g_error_matches(
|
||||||
|
import_error,
|
||||||
|
EVIDENCE_IMPORTER_ERROR,
|
||||||
|
EVIDENCE_IMPORTER_ERROR_CANCELLED
|
||||||
|
))
|
||||||
|
{
|
||||||
|
g_clear_error(
|
||||||
|
&import_error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_CANCELLED,
|
||||||
|
"L’import de la preuve a été annulé."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import_error != NULL)
|
||||||
|
{
|
||||||
|
g_propagate_error(
|
||||||
|
error,
|
||||||
|
import_error
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_IMPORT,
|
||||||
|
"L’import a échoué sans fournir d’erreur."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exécute l’import dans le thread secondaire.
|
||||||
|
*/
|
||||||
|
static gboolean evidence_import_task_worker(
|
||||||
|
BackgroundTask *task,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
gpointer worker_data,
|
||||||
|
gpointer *result,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceImportTaskData *task_data =
|
||||||
|
worker_data;
|
||||||
|
|
||||||
|
EvidenceImportRequest import_request =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
Database *database = NULL;
|
||||||
|
|
||||||
|
EvidenceImporter *evidence_importer =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
EvidenceRecord *evidence_record =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *importer_error = NULL;
|
||||||
|
GError *import_error = NULL;
|
||||||
|
|
||||||
|
if (task == NULL ||
|
||||||
|
cancellable == NULL ||
|
||||||
|
task_data == NULL ||
|
||||||
|
result == NULL ||
|
||||||
|
error == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
|
||||||
|
if (g_cancellable_set_error_if_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
background_task_report_progress(
|
||||||
|
task,
|
||||||
|
0.05,
|
||||||
|
"Préparation de l’import"
|
||||||
|
);
|
||||||
|
|
||||||
|
database =
|
||||||
|
database_open(
|
||||||
|
task_data->database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
if (database == NULL)
|
||||||
|
{
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_DATABASE,
|
||||||
|
"Impossible d’ouvrir la base SQLite : %s",
|
||||||
|
task_data->database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_cancellable_set_error_if_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
database_close(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
evidence_importer =
|
||||||
|
evidence_importer_new(
|
||||||
|
database,
|
||||||
|
&importer_error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (evidence_importer == NULL)
|
||||||
|
{
|
||||||
|
if (importer_error != NULL)
|
||||||
|
{
|
||||||
|
g_propagate_prefixed_error(
|
||||||
|
error,
|
||||||
|
importer_error,
|
||||||
|
"Impossible de préparer l’import : "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_IMPORT,
|
||||||
|
"Impossible de créer le service d’import."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
import_request.source_path =
|
||||||
|
task_data->source_path;
|
||||||
|
|
||||||
|
import_request.destination_directory =
|
||||||
|
task_data->destination_directory;
|
||||||
|
|
||||||
|
import_request.relative_directory =
|
||||||
|
task_data->relative_directory;
|
||||||
|
|
||||||
|
import_request.type_identifier =
|
||||||
|
task_data->type_identifier;
|
||||||
|
|
||||||
|
import_request.collected_at =
|
||||||
|
task_data->collected_at;
|
||||||
|
|
||||||
|
import_request.source =
|
||||||
|
task_data->source;
|
||||||
|
|
||||||
|
import_request.description =
|
||||||
|
task_data->description;
|
||||||
|
|
||||||
|
background_task_report_progress(
|
||||||
|
task,
|
||||||
|
0.20,
|
||||||
|
"Copie et vérification de la preuve"
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_record =
|
||||||
|
evidence_importer_import(
|
||||||
|
evidence_importer,
|
||||||
|
&import_request,
|
||||||
|
cancellable,
|
||||||
|
&import_error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (evidence_record == NULL)
|
||||||
|
{
|
||||||
|
evidence_import_task_propagate_import_error(
|
||||||
|
error,
|
||||||
|
import_error
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_importer_free(
|
||||||
|
evidence_importer
|
||||||
|
);
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
background_task_report_progress(
|
||||||
|
task,
|
||||||
|
1.0,
|
||||||
|
"Preuve importée"
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_importer_free(
|
||||||
|
evidence_importer
|
||||||
|
);
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
*result =
|
||||||
|
evidence_record;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmet une erreur secondaire au code appelant.
|
||||||
|
*/
|
||||||
|
static void evidence_import_task_propagate_start_error(
|
||||||
|
GError **error,
|
||||||
|
GError *start_error,
|
||||||
|
const char *prefix
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (start_error == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_IMPORT,
|
||||||
|
"La tâche d’import n’a pas pu être démarrée."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_propagate_prefixed_error(
|
||||||
|
error,
|
||||||
|
start_error,
|
||||||
|
"%s",
|
||||||
|
prefix
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&start_error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère le résultat EvidenceRecord d’une tâche.
|
||||||
|
*
|
||||||
|
* Cette fonction adapte evidence_record_free() au type GDestroyNotify.
|
||||||
|
*
|
||||||
|
* @param user_data Pointeur vers EvidenceRecord.
|
||||||
|
*/
|
||||||
|
static void evidence_import_task_result_free(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceRecord *evidence_record =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
evidence_record_free(
|
||||||
|
evidence_record
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BackgroundTask *evidence_import_task_start(
|
||||||
|
TaskManager *task_manager,
|
||||||
|
const EvidenceImportTaskRequest *request,
|
||||||
|
BackgroundTaskCompletionCallback completion_callback,
|
||||||
|
gpointer completion_data,
|
||||||
|
GDestroyNotify completion_data_destroy,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceImportTaskData *task_data =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
BackgroundTask *task = NULL;
|
||||||
|
|
||||||
|
char *source_name = NULL;
|
||||||
|
char *task_title = NULL;
|
||||||
|
|
||||||
|
GError *start_error = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task_manager == NULL ||
|
||||||
|
!evidence_import_task_request_is_valid(
|
||||||
|
request
|
||||||
|
))
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Les paramètres de la tâche d’import sont invalides."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_data =
|
||||||
|
evidence_import_task_data_new(
|
||||||
|
request
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task_data == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_IMPORT,
|
||||||
|
"Impossible d’allouer les données de la tâche d’import."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_name =
|
||||||
|
g_path_get_basename(
|
||||||
|
request->source_path
|
||||||
|
);
|
||||||
|
|
||||||
|
task_title =
|
||||||
|
g_strdup_printf(
|
||||||
|
"Importer la preuve : %s",
|
||||||
|
source_name
|
||||||
|
);
|
||||||
|
|
||||||
|
task =
|
||||||
|
background_task_new(
|
||||||
|
task_title
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_title
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
source_name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task == NULL)
|
||||||
|
{
|
||||||
|
evidence_import_task_data_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR,
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_IMPORT,
|
||||||
|
"Impossible de créer la tâche d’import."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!task_manager_add(
|
||||||
|
task_manager,
|
||||||
|
task,
|
||||||
|
&start_error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
evidence_import_task_data_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
|
||||||
|
background_task_unref(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_import_task_propagate_start_error(
|
||||||
|
error,
|
||||||
|
start_error,
|
||||||
|
"Impossible d’ajouter la tâche : "
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!background_task_start(
|
||||||
|
task,
|
||||||
|
evidence_import_task_worker,
|
||||||
|
task_data,
|
||||||
|
evidence_import_task_data_free,
|
||||||
|
evidence_import_task_result_free,
|
||||||
|
completion_callback,
|
||||||
|
completion_data,
|
||||||
|
completion_data_destroy,
|
||||||
|
&start_error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* background_task_start() n’a pas pris possession
|
||||||
|
* de task_data ni de completion_data en cas d’échec.
|
||||||
|
*/
|
||||||
|
evidence_import_task_data_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
|
||||||
|
task_manager_remove(
|
||||||
|
task_manager,
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
background_task_unref(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_import_task_propagate_start_error(
|
||||||
|
error,
|
||||||
|
start_error,
|
||||||
|
"Impossible de démarrer la tâche : "
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
236
src/views/file_dialog.c
Normal file
236
src/views/file_dialog.c
Normal file
|
|
@ -0,0 +1,236 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file file_dialog.c
|
||||||
|
* @brief Implémentation du dialogue de sélection d’un fichier de preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "views/file_dialog.h"
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contexte conservé pendant l’opération asynchrone.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FileDialogCallback callback;
|
||||||
|
gpointer user_data;
|
||||||
|
} FileDialogContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère le contexte du dialogue.
|
||||||
|
*/
|
||||||
|
static void file_dialog_context_free(
|
||||||
|
FileDialogContext *context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
g_free(
|
||||||
|
context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmet le résultat au code appelant.
|
||||||
|
*/
|
||||||
|
static void file_dialog_emit_result(
|
||||||
|
FileDialogContext *context,
|
||||||
|
const char *file_path,
|
||||||
|
const GError *error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (context == NULL ||
|
||||||
|
context->callback == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->callback(
|
||||||
|
file_path,
|
||||||
|
error,
|
||||||
|
context->user_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Traite le résultat du sélecteur de fichier.
|
||||||
|
*/
|
||||||
|
static void file_dialog_on_file_selected(
|
||||||
|
GObject *source_object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GtkFileDialog *dialog =
|
||||||
|
GTK_FILE_DIALOG(
|
||||||
|
source_object
|
||||||
|
);
|
||||||
|
|
||||||
|
FileDialogContext *context =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
GFile *file = NULL;
|
||||||
|
|
||||||
|
char *file_path = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
GError *path_error = NULL;
|
||||||
|
|
||||||
|
if (context == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file =
|
||||||
|
gtk_file_dialog_open_finish(
|
||||||
|
dialog,
|
||||||
|
result,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Fermer volontairement le dialogue n’est pas une erreur.
|
||||||
|
*/
|
||||||
|
if (error != NULL &&
|
||||||
|
g_error_matches(
|
||||||
|
error,
|
||||||
|
GTK_DIALOG_ERROR,
|
||||||
|
GTK_DIALOG_ERROR_DISMISSED
|
||||||
|
))
|
||||||
|
{
|
||||||
|
file_dialog_emit_result(
|
||||||
|
context,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file_dialog_emit_result(
|
||||||
|
context,
|
||||||
|
NULL,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
file_dialog_context_free(
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_path =
|
||||||
|
g_file_get_path(
|
||||||
|
file
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* g_file_get_path() retourne NULL pour une ressource qui ne
|
||||||
|
* correspond pas à un fichier local.
|
||||||
|
*/
|
||||||
|
if (file_path == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
&path_error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
"Le fichier sélectionné ne possède pas de chemin local."
|
||||||
|
);
|
||||||
|
|
||||||
|
file_dialog_emit_result(
|
||||||
|
context,
|
||||||
|
NULL,
|
||||||
|
path_error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&path_error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_object_unref(
|
||||||
|
file
|
||||||
|
);
|
||||||
|
|
||||||
|
file_dialog_context_free(
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_dialog_emit_result(
|
||||||
|
context,
|
||||||
|
file_path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
file_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_object_unref(
|
||||||
|
file
|
||||||
|
);
|
||||||
|
|
||||||
|
file_dialog_context_free(
|
||||||
|
context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_dialog_select_file(
|
||||||
|
GtkWindow *parent,
|
||||||
|
FileDialogCallback callback,
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GtkFileDialog *dialog = NULL;
|
||||||
|
|
||||||
|
FileDialogContext *context = NULL;
|
||||||
|
|
||||||
|
if (callback == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context =
|
||||||
|
g_new0(
|
||||||
|
FileDialogContext,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
context->callback =
|
||||||
|
callback;
|
||||||
|
|
||||||
|
context->user_data =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
dialog =
|
||||||
|
gtk_file_dialog_new();
|
||||||
|
|
||||||
|
gtk_file_dialog_set_title(
|
||||||
|
dialog,
|
||||||
|
"Sélectionner un fichier de preuve"
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_file_dialog_set_modal(
|
||||||
|
dialog,
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_file_dialog_open(
|
||||||
|
dialog,
|
||||||
|
parent,
|
||||||
|
NULL,
|
||||||
|
file_dialog_on_file_selected,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
g_object_unref(
|
||||||
|
dialog
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ struct MainWindow
|
||||||
GtkWidget *action_bar;
|
GtkWidget *action_bar;
|
||||||
GtkWidget *new_investigation_button;
|
GtkWidget *new_investigation_button;
|
||||||
GtkWidget *open_investigation_button;
|
GtkWidget *open_investigation_button;
|
||||||
GtkWidget *demo_task_button;
|
GtkWidget *import_evidence_button;
|
||||||
GtkWidget *content_paned;
|
GtkWidget *content_paned;
|
||||||
GtkWidget *main_paned;
|
GtkWidget *main_paned;
|
||||||
GtkWidget *status_label;
|
GtkWidget *status_label;
|
||||||
|
|
@ -80,17 +80,18 @@ struct MainWindow
|
||||||
gpointer
|
gpointer
|
||||||
open_investigation_user_data;
|
open_investigation_user_data;
|
||||||
|
|
||||||
|
MainWindowImportEvidenceCallback
|
||||||
|
import_evidence_callback;
|
||||||
|
|
||||||
|
gpointer
|
||||||
|
import_evidence_user_data;
|
||||||
|
|
||||||
MainWindowQuitCallback
|
MainWindowQuitCallback
|
||||||
quit_callback;
|
quit_callback;
|
||||||
|
|
||||||
gpointer
|
gpointer
|
||||||
quit_user_data;
|
quit_user_data;
|
||||||
|
|
||||||
MainWindowDemoTaskCallback
|
|
||||||
demo_task_callback;
|
|
||||||
|
|
||||||
gpointer
|
|
||||||
demo_task_user_data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -146,12 +147,12 @@ static void main_window_on_open_investigation_clicked(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Transmet la demande de tâche de démonstration au contrôleur.
|
* @brief Transmet la demande d'import d'une preuve au contrôleur.
|
||||||
*
|
*
|
||||||
* @param button Bouton ayant reçu le clic.
|
* @param button Bouton ayant reçu le clic.
|
||||||
* @param user_data Pointeur vers MainWindow.
|
* @param user_data Pointeur vers MainWindow.
|
||||||
*/
|
*/
|
||||||
static void main_window_on_demo_task_clicked(
|
static void main_window_on_import_evidence_clicked(
|
||||||
GtkButton *button,
|
GtkButton *button,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
)
|
)
|
||||||
|
|
@ -161,13 +162,13 @@ static void main_window_on_demo_task_clicked(
|
||||||
(void) button;
|
(void) button;
|
||||||
|
|
||||||
if (main_window == NULL ||
|
if (main_window == NULL ||
|
||||||
main_window->demo_task_callback == NULL)
|
main_window->import_evidence_callback == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
main_window->demo_task_callback(
|
main_window->import_evidence_callback(
|
||||||
main_window->demo_task_user_data
|
main_window->import_evidence_user_data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,6 +198,54 @@ static void main_window_on_quit_clicked(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée un bouton d'action compact avec une icône.
|
||||||
|
*
|
||||||
|
* @param icon_name Nom de l'icône symbolique GTK.
|
||||||
|
* @param tooltip_text Texte de l'infobulle.
|
||||||
|
*
|
||||||
|
* @return Nouveau bouton GTK.
|
||||||
|
*/
|
||||||
|
static GtkWidget *main_window_create_action_button(
|
||||||
|
const char *icon_name,
|
||||||
|
const char *tooltip_text
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GtkWidget *button = NULL;
|
||||||
|
|
||||||
|
if (icon_name == NULL ||
|
||||||
|
icon_name[0] == '\0')
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
button =
|
||||||
|
gtk_button_new_from_icon_name(
|
||||||
|
icon_name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (button == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_add_css_class(
|
||||||
|
button,
|
||||||
|
"flat"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tooltip_text != NULL &&
|
||||||
|
tooltip_text[0] != '\0')
|
||||||
|
{
|
||||||
|
gtk_widget_set_tooltip_text(
|
||||||
|
button,
|
||||||
|
tooltip_text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
MainWindow *main_window_new(
|
MainWindow *main_window_new(
|
||||||
GtkApplication *application,
|
GtkApplication *application,
|
||||||
TaskManager *task_manager
|
TaskManager *task_manager
|
||||||
|
|
@ -206,6 +255,7 @@ MainWindow *main_window_new(
|
||||||
GtkWidget *sidebar_widget = NULL;
|
GtkWidget *sidebar_widget = NULL;
|
||||||
GtkWidget *workspace_widget = NULL;
|
GtkWidget *workspace_widget = NULL;
|
||||||
GtkWidget *task_panel_widget = NULL;
|
GtkWidget *task_panel_widget = NULL;
|
||||||
|
GtkWidget *action_spacer = NULL;
|
||||||
|
|
||||||
if (application == NULL ||
|
if (application == NULL ||
|
||||||
task_manager == NULL)
|
task_manager == NULL)
|
||||||
|
|
@ -252,7 +302,7 @@ MainWindow *main_window_new(
|
||||||
*/
|
*/
|
||||||
main_window->action_bar = gtk_box_new(
|
main_window->action_bar = gtk_box_new(
|
||||||
GTK_ORIENTATION_HORIZONTAL,
|
GTK_ORIENTATION_HORIZONTAL,
|
||||||
8
|
4
|
||||||
);
|
);
|
||||||
|
|
||||||
gtk_widget_set_margin_start(
|
gtk_widget_set_margin_start(
|
||||||
|
|
@ -276,18 +326,46 @@ MainWindow *main_window_new(
|
||||||
);
|
);
|
||||||
|
|
||||||
main_window->new_investigation_button =
|
main_window->new_investigation_button =
|
||||||
gtk_button_new_with_label(
|
main_window_create_action_button(
|
||||||
"Nouvelle enquête"
|
"document-new-symbolic",
|
||||||
|
"Créer une nouvelle enquête"
|
||||||
);
|
);
|
||||||
|
|
||||||
main_window->open_investigation_button =
|
main_window->open_investigation_button =
|
||||||
gtk_button_new_with_label(
|
main_window_create_action_button(
|
||||||
|
"document-open-symbolic",
|
||||||
"Ouvrir une enquête"
|
"Ouvrir une enquête"
|
||||||
);
|
);
|
||||||
|
|
||||||
main_window->demo_task_button =
|
main_window->import_evidence_button =
|
||||||
gtk_button_new_with_label(
|
main_window_create_action_button(
|
||||||
"Tâche de test"
|
"document-save-symbolic",
|
||||||
|
"Importer une preuve"
|
||||||
|
);
|
||||||
|
|
||||||
|
main_window->quit_button =
|
||||||
|
main_window_create_action_button(
|
||||||
|
"application-exit-symbolic",
|
||||||
|
"Quitter Labfy Investigation"
|
||||||
|
);
|
||||||
|
|
||||||
|
action_spacer =
|
||||||
|
gtk_box_new(
|
||||||
|
GTK_ORIENTATION_HORIZONTAL,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_hexpand(
|
||||||
|
action_spacer,
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Aucun import n'est autorisé sans enquête ouverte.
|
||||||
|
*/
|
||||||
|
gtk_widget_set_sensitive(
|
||||||
|
main_window->import_evidence_button,
|
||||||
|
FALSE
|
||||||
);
|
);
|
||||||
|
|
||||||
main_window->quit_button =
|
main_window->quit_button =
|
||||||
|
|
@ -307,7 +385,12 @@ MainWindow *main_window_new(
|
||||||
|
|
||||||
gtk_box_append(
|
gtk_box_append(
|
||||||
GTK_BOX(main_window->action_bar),
|
GTK_BOX(main_window->action_bar),
|
||||||
main_window->demo_task_button
|
main_window->import_evidence_button
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(main_window->action_bar),
|
||||||
|
action_spacer
|
||||||
);
|
);
|
||||||
|
|
||||||
gtk_box_append(
|
gtk_box_append(
|
||||||
|
|
@ -334,10 +417,10 @@ MainWindow *main_window_new(
|
||||||
);
|
);
|
||||||
|
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
main_window->demo_task_button,
|
main_window->import_evidence_button,
|
||||||
"clicked",
|
"clicked",
|
||||||
G_CALLBACK(
|
G_CALLBACK(
|
||||||
main_window_on_demo_task_clicked
|
main_window_on_import_evidence_clicked
|
||||||
),
|
),
|
||||||
main_window
|
main_window
|
||||||
);
|
);
|
||||||
|
|
@ -795,9 +878,9 @@ void main_window_set_open_investigation_callback(
|
||||||
main_window->open_investigation_user_data = user_data;
|
main_window->open_investigation_user_data = user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_window_set_demo_task_callback(
|
void main_window_set_import_evidence_callback(
|
||||||
MainWindow *main_window,
|
MainWindow *main_window,
|
||||||
MainWindowDemoTaskCallback callback,
|
MainWindowImportEvidenceCallback callback,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
@ -806,8 +889,28 @@ void main_window_set_demo_task_callback(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
main_window->demo_task_callback = callback;
|
main_window->import_evidence_callback =
|
||||||
main_window->demo_task_user_data = user_data;
|
callback;
|
||||||
|
|
||||||
|
main_window->import_evidence_user_data =
|
||||||
|
user_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_window_set_import_evidence_enabled(
|
||||||
|
MainWindow *main_window,
|
||||||
|
gboolean enabled
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (main_window == NULL ||
|
||||||
|
main_window->import_evidence_button == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_set_sensitive(
|
||||||
|
main_window->import_evidence_button,
|
||||||
|
enabled
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_window_set_quit_callback(
|
void main_window_set_quit_callback(
|
||||||
|
|
|
||||||
|
|
@ -146,11 +146,6 @@ void sidebar_set_tree_model(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sidebar == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
investigation_tree_view_set_model(
|
investigation_tree_view_set_model(
|
||||||
sidebar->tree_view,
|
sidebar->tree_view,
|
||||||
tree_model
|
tree_model
|
||||||
|
|
|
||||||
798
tests/test_evidence_import_task.c
Normal file
798
tests/test_evidence_import_task.c
Normal file
|
|
@ -0,0 +1,798 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file test_evidence_import_task.c
|
||||||
|
* @brief Tests de la tâche asynchrone d’import d’une preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "core/evidence_import_task.h"
|
||||||
|
|
||||||
|
#include "core/background_task.h"
|
||||||
|
#include "core/task_manager.h"
|
||||||
|
#include "dao/evidence_dao.h"
|
||||||
|
#include "database/database.h"
|
||||||
|
#include "models/evidence_record.h"
|
||||||
|
#include "core/evidence_importer_test.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
#define TEST_RELATIVE_DIRECTORY \
|
||||||
|
"01_Preuves_Originales/Documents"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contexte utilisé pour attendre la fin asynchrone.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GMainLoop *main_loop;
|
||||||
|
|
||||||
|
gboolean completed;
|
||||||
|
gboolean timed_out;
|
||||||
|
} TestCompletionContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Environnement temporaire d’un test.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *root_directory;
|
||||||
|
char *database_path;
|
||||||
|
|
||||||
|
char *source_directory;
|
||||||
|
char *evidence_directory;
|
||||||
|
char *destination_directory;
|
||||||
|
|
||||||
|
TaskManager *task_manager;
|
||||||
|
} TestEvidenceImportTaskFixture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Quitte la boucle principale lorsque la tâche se termine.
|
||||||
|
*/
|
||||||
|
static void test_evidence_import_task_completed(
|
||||||
|
BackgroundTask *task,
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
TestCompletionContext *context =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
assert(task != NULL);
|
||||||
|
assert(context != NULL);
|
||||||
|
|
||||||
|
context->completed = TRUE;
|
||||||
|
|
||||||
|
g_main_loop_quit(
|
||||||
|
context->main_loop
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Empêche un test asynchrone de rester bloqué.
|
||||||
|
*/
|
||||||
|
static gboolean test_evidence_import_task_timeout(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
TestCompletionContext *context =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
assert(context != NULL);
|
||||||
|
|
||||||
|
context->timed_out = TRUE;
|
||||||
|
|
||||||
|
g_main_loop_quit(
|
||||||
|
context->main_loop
|
||||||
|
);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attend la fin d’une tâche avec un timeout.
|
||||||
|
*/
|
||||||
|
static void test_evidence_import_task_wait(
|
||||||
|
TestCompletionContext *context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
guint timeout_source_id = 0;
|
||||||
|
|
||||||
|
assert(context != NULL);
|
||||||
|
assert(context->main_loop != NULL);
|
||||||
|
|
||||||
|
timeout_source_id =
|
||||||
|
g_timeout_add_seconds(
|
||||||
|
5,
|
||||||
|
test_evidence_import_task_timeout,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(timeout_source_id != 0);
|
||||||
|
|
||||||
|
g_main_loop_run(
|
||||||
|
context->main_loop
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!context->timed_out)
|
||||||
|
{
|
||||||
|
assert(
|
||||||
|
g_source_remove(
|
||||||
|
timeout_source_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!context->timed_out);
|
||||||
|
assert(context->completed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compte les fichiers présents dans la destination.
|
||||||
|
*/
|
||||||
|
static guint test_evidence_import_task_count_destination_entries(
|
||||||
|
const TestEvidenceImportTaskFixture *fixture
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GDir *directory = NULL;
|
||||||
|
|
||||||
|
const char *entry_name = NULL;
|
||||||
|
|
||||||
|
guint entry_count = 0;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
assert(fixture != NULL);
|
||||||
|
|
||||||
|
directory =
|
||||||
|
g_dir_open(
|
||||||
|
fixture->destination_directory,
|
||||||
|
0,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(directory != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
while ((entry_name = g_dir_read_name(directory)) != NULL)
|
||||||
|
{
|
||||||
|
assert(entry_name[0] != '\0');
|
||||||
|
|
||||||
|
entry_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dir_close(
|
||||||
|
directory
|
||||||
|
);
|
||||||
|
|
||||||
|
return entry_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée une enquête temporaire.
|
||||||
|
*/
|
||||||
|
static TestEvidenceImportTaskFixture
|
||||||
|
test_evidence_import_task_fixture_create(void)
|
||||||
|
{
|
||||||
|
TestEvidenceImportTaskFixture fixture =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
fixture.root_directory =
|
||||||
|
g_dir_make_tmp(
|
||||||
|
"labfy-evidence-import-task-test-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(fixture.root_directory != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
fixture.database_path =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.root_directory,
|
||||||
|
"Enquete.sqlite",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture.source_directory =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.root_directory,
|
||||||
|
"sources",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture.evidence_directory =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.root_directory,
|
||||||
|
"01_Preuves_Originales",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture.destination_directory =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.evidence_directory,
|
||||||
|
"Documents",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(fixture.database_path != NULL);
|
||||||
|
assert(fixture.source_directory != NULL);
|
||||||
|
assert(fixture.evidence_directory != NULL);
|
||||||
|
assert(fixture.destination_directory != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_mkdir(
|
||||||
|
fixture.source_directory,
|
||||||
|
0700
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_mkdir(
|
||||||
|
fixture.evidence_directory,
|
||||||
|
0700
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_mkdir(
|
||||||
|
fixture.destination_directory,
|
||||||
|
0700
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
database_initialize(
|
||||||
|
fixture.database_path,
|
||||||
|
"Enquete_EvidenceImportTask",
|
||||||
|
fixture.root_directory
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture.task_manager =
|
||||||
|
task_manager_new();
|
||||||
|
|
||||||
|
assert(fixture.task_manager != NULL);
|
||||||
|
|
||||||
|
return fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Détruit une fixture déjà débarrassée de ses fichiers.
|
||||||
|
*/
|
||||||
|
static void test_evidence_import_task_fixture_clear(
|
||||||
|
TestEvidenceImportTaskFixture *fixture
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assert(fixture != NULL);
|
||||||
|
|
||||||
|
task_manager_free(
|
||||||
|
fixture->task_manager
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_remove(
|
||||||
|
fixture->database_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_rmdir(
|
||||||
|
fixture->destination_directory
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_rmdir(
|
||||||
|
fixture->evidence_directory
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_rmdir(
|
||||||
|
fixture->source_directory
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_rmdir(
|
||||||
|
fixture->root_directory
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
fixture->destination_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
fixture->evidence_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
fixture->source_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
fixture->database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
fixture->root_directory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le refus des paramètres invalides.
|
||||||
|
*/
|
||||||
|
static void test_evidence_import_task_invalid_arguments(void)
|
||||||
|
{
|
||||||
|
EvidenceImportTaskRequest request =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
BackgroundTask *task = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
task =
|
||||||
|
evidence_import_task_start(
|
||||||
|
NULL,
|
||||||
|
&request,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(task == NULL);
|
||||||
|
assert(error != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
error->domain ==
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
error->code ==
|
||||||
|
EVIDENCE_IMPORT_TASK_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie un import asynchrone complet.
|
||||||
|
*/
|
||||||
|
static void test_evidence_import_task_success(void)
|
||||||
|
{
|
||||||
|
TestEvidenceImportTaskFixture fixture =
|
||||||
|
test_evidence_import_task_fixture_create();
|
||||||
|
|
||||||
|
TestCompletionContext completion_context =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
EvidenceImportTaskRequest request =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
BackgroundTask *task = NULL;
|
||||||
|
|
||||||
|
EvidenceRecord *evidence_record = NULL;
|
||||||
|
|
||||||
|
Database *database = NULL;
|
||||||
|
EvidenceDao *evidence_dao = NULL;
|
||||||
|
|
||||||
|
char *source_path = NULL;
|
||||||
|
char *destination_path = NULL;
|
||||||
|
|
||||||
|
guint64 evidence_count = 0;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
source_path =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.source_directory,
|
||||||
|
"preuve_asynchrone.txt",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(source_path != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_file_set_contents(
|
||||||
|
source_path,
|
||||||
|
"preuve asynchrone",
|
||||||
|
-1,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
completion_context.main_loop =
|
||||||
|
g_main_loop_new(
|
||||||
|
NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(completion_context.main_loop != NULL);
|
||||||
|
|
||||||
|
request.database_path =
|
||||||
|
fixture.database_path;
|
||||||
|
|
||||||
|
request.source_path =
|
||||||
|
source_path;
|
||||||
|
|
||||||
|
request.destination_directory =
|
||||||
|
fixture.destination_directory;
|
||||||
|
|
||||||
|
request.relative_directory =
|
||||||
|
TEST_RELATIVE_DIRECTORY;
|
||||||
|
|
||||||
|
request.type_identifier =
|
||||||
|
"document";
|
||||||
|
|
||||||
|
request.source =
|
||||||
|
"Test automatisé EvidenceImportTask.";
|
||||||
|
|
||||||
|
request.description =
|
||||||
|
"Import réalisé depuis un thread secondaire.";
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_evidence_import_task_count_destination_entries(
|
||||||
|
&fixture
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
task =
|
||||||
|
evidence_import_task_start(
|
||||||
|
fixture.task_manager,
|
||||||
|
&request,
|
||||||
|
test_evidence_import_task_completed,
|
||||||
|
&completion_context,
|
||||||
|
NULL,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(task != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
task_manager_get_count(
|
||||||
|
fixture.task_manager
|
||||||
|
) == 1
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_import_task_wait(
|
||||||
|
&completion_context
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_evidence_import_task_count_destination_entries(
|
||||||
|
&fixture
|
||||||
|
) == 1
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
background_task_get_state(
|
||||||
|
task
|
||||||
|
) ==
|
||||||
|
BACKGROUND_TASK_STATE_COMPLETED
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
background_task_get_progress(
|
||||||
|
task
|
||||||
|
) == 1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
background_task_dup_error(
|
||||||
|
task
|
||||||
|
) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_record =
|
||||||
|
background_task_get_result(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(evidence_record != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
strcmp(
|
||||||
|
evidence_record_get_original_name(
|
||||||
|
evidence_record
|
||||||
|
),
|
||||||
|
"preuve_asynchrone.txt"
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_record_get_integrity_status(
|
||||||
|
evidence_record
|
||||||
|
) ==
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID
|
||||||
|
);
|
||||||
|
|
||||||
|
destination_path =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.destination_directory,
|
||||||
|
evidence_record_get_internal_name(
|
||||||
|
evidence_record
|
||||||
|
),
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(destination_path != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_file_test(
|
||||||
|
destination_path,
|
||||||
|
G_FILE_TEST_IS_REGULAR
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le worker a fermé sa connexion.
|
||||||
|
* Une nouvelle connexion permet de vérifier la persistance.
|
||||||
|
*/
|
||||||
|
database =
|
||||||
|
database_open(
|
||||||
|
fixture.database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database != NULL);
|
||||||
|
|
||||||
|
evidence_dao =
|
||||||
|
evidence_dao_new(
|
||||||
|
database,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(evidence_dao != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_dao_count(
|
||||||
|
evidence_dao,
|
||||||
|
&evidence_count,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
assert(evidence_count == 1);
|
||||||
|
|
||||||
|
evidence_dao_free(
|
||||||
|
evidence_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_remove(
|
||||||
|
destination_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_remove(
|
||||||
|
source_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
destination_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
source_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_main_loop_unref(
|
||||||
|
completion_context.main_loop
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* La tâche reste encore possédée par le manager.
|
||||||
|
*/
|
||||||
|
background_task_unref(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_import_task_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie l’annulation après la copie de la preuve.
|
||||||
|
*/
|
||||||
|
static void test_evidence_import_task_cancelled_after_copy(void)
|
||||||
|
{
|
||||||
|
TestEvidenceImportTaskFixture fixture =
|
||||||
|
test_evidence_import_task_fixture_create();
|
||||||
|
|
||||||
|
TestCompletionContext completion_context =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
EvidenceImportTaskRequest request =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
BackgroundTask *task = NULL;
|
||||||
|
|
||||||
|
char *source_path = NULL;
|
||||||
|
|
||||||
|
guint64 evidence_count = 42;
|
||||||
|
|
||||||
|
Database *database = NULL;
|
||||||
|
EvidenceDao *evidence_dao = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
source_path =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.source_directory,
|
||||||
|
"preuve_annulee.txt",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(source_path != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_file_set_contents(
|
||||||
|
source_path,
|
||||||
|
"preuve annulée après copie",
|
||||||
|
-1,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
completion_context.main_loop =
|
||||||
|
g_main_loop_new(
|
||||||
|
NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(completion_context.main_loop != NULL);
|
||||||
|
|
||||||
|
request.database_path =
|
||||||
|
fixture.database_path;
|
||||||
|
|
||||||
|
request.source_path =
|
||||||
|
source_path;
|
||||||
|
|
||||||
|
request.destination_directory =
|
||||||
|
fixture.destination_directory;
|
||||||
|
|
||||||
|
request.relative_directory =
|
||||||
|
TEST_RELATIVE_DIRECTORY;
|
||||||
|
|
||||||
|
request.type_identifier =
|
||||||
|
"document";
|
||||||
|
|
||||||
|
evidence_importer_test_reset_hooks();
|
||||||
|
|
||||||
|
evidence_importer_test_set_cancel_after_copy(
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
task =
|
||||||
|
evidence_import_task_start(
|
||||||
|
fixture.task_manager,
|
||||||
|
&request,
|
||||||
|
test_evidence_import_task_completed,
|
||||||
|
&completion_context,
|
||||||
|
NULL,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(task != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
test_evidence_import_task_wait(
|
||||||
|
&completion_context
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
background_task_get_state(
|
||||||
|
task
|
||||||
|
) ==
|
||||||
|
BACKGROUND_TASK_STATE_CANCELLED
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_evidence_import_task_count_destination_entries(
|
||||||
|
&fixture
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
database =
|
||||||
|
database_open(
|
||||||
|
fixture.database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database != NULL);
|
||||||
|
|
||||||
|
evidence_dao =
|
||||||
|
evidence_dao_new(
|
||||||
|
database,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(evidence_dao != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_dao_count(
|
||||||
|
evidence_dao,
|
||||||
|
&evidence_count,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
assert(evidence_count == 0);
|
||||||
|
|
||||||
|
evidence_dao_free(
|
||||||
|
evidence_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le fichier original reste intact.
|
||||||
|
*/
|
||||||
|
assert(
|
||||||
|
g_file_test(
|
||||||
|
source_path,
|
||||||
|
G_FILE_TEST_IS_REGULAR
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_importer_test_reset_hooks();
|
||||||
|
|
||||||
|
background_task_unref(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
g_main_loop_unref(
|
||||||
|
completion_context.main_loop
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_remove(
|
||||||
|
source_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
source_path
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_import_task_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
test_evidence_import_task_invalid_arguments();
|
||||||
|
test_evidence_import_task_success();
|
||||||
|
test_evidence_import_task_cancelled_after_copy();
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"EvidenceImportTask : premiers tests valides.\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue