From 1865cce4d51b9c7a6fb718f4e2c034a57365ad1b Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 31 May 2021 01:40:39 +0200
Subject: Create a command to list remote binaries.

---
 plugins/pychrysalide/analysis/db/admin.c | 116 +++++++++++++++--
 src/analysis/db/admin.c                  | 209 +++++++++++++++++++++++++++++++
 src/analysis/db/admin.h                  |   6 +
 src/analysis/db/controller.c             | 122 +++++++++++-------
 src/analysis/db/protocol.h               |  20 ++-
 tests/analysis/db/conn.py                |  20 ++-
 6 files changed, 425 insertions(+), 68 deletions(-)

diff --git a/plugins/pychrysalide/analysis/db/admin.c b/plugins/pychrysalide/analysis/db/admin.c
index 52027ac..a4694e6 100644
--- a/plugins/pychrysalide/analysis/db/admin.c
+++ b/plugins/pychrysalide/analysis/db/admin.c
@@ -42,6 +42,12 @@
 /* Crée un nouvel objet Python de type 'AdminClient'. */
 static PyObject *py_admin_client_new(PyTypeObject *, PyObject *, PyObject *);
 
+/* Effectue une demande de liste de binaires existants. */
+static PyObject *py_admin_client_request_existing_binaries(PyObject *, PyObject *);
+
+/* Fournit la liste des instantanés existants. */
+static PyObject *py_admin_client_get_existing_binaries(PyObject *, void *);
+
 
 
 /******************************************************************************
@@ -63,9 +69,9 @@ static PyObject *py_admin_client_new(PyTypeObject *type, PyObject *args, PyObjec
     PyObject *result;                       /* Instance à retourner        */
     GAdminClient *client;                   /* Serveur mis en place        */
 
-#define ADMIN_CLIENT_DOC                                                              \
-    "AdminClient provides and receives binary updates to and from a connected"        \
-    " to a server.\n"                                                                   \
+#define ADMIN_CLIENT_DOC                                                                \
+    "AdminClient provides control of the registered binary contents available from a"   \
+    " server.\n"                                                                        \
     "\n"                                                                                \
     "Such clients must be authenticated and communications are encrypted using TLS.\n"  \
     "\n"                                                                                \
@@ -74,16 +80,9 @@ static PyObject *py_admin_client_new(PyTypeObject *type, PyObject *args, PyObjec
     "    AdminClient()"                                                                 \
     "\n"                                                                                \
     "AdminClient instances emit the following signals:\n"                               \
-    "* 'snapshots-updated'\n"                                                           \
-    "    This signal is emitted when the snapshot list has evolved.\n"                  \
-    "\n"                                                                                \
-    "    Handlers are expected to have only one argument: the client managing the"      \
-    "    updated snapshots.\n"                                                          \
-    "* 'snapshot-changed'\n"                                                            \
-    "    This signal is emitted when the identifier of the current snapshot changed.\n" \
-    "\n"                                                                                \
-    "    Handlers are expected to have only one argument: the client managing the"      \
-    "    snapshots."
+    "* 'existing-binaries-updated'\n"                                                   \
+    "    This signal is emitted when the list of existing binaries on server side"      \
+    " has been updated following a user request.\n"                                     \
 
     client = g_admin_client_new();
 
@@ -101,6 +100,95 @@ static PyObject *py_admin_client_new(PyTypeObject *type, PyObject *args, PyObjec
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = client à manipuler.                                   *
+*                args = arguments d'appel non utilisés ici.                   *
+*                                                                             *
+*  Description : Effectue une demande de liste de binaires existants.         *
+*                                                                             *
+*  Retour      : True si la commande a bien été envoyée, False sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_admin_client_request_existing_binaries(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    GAdminClient *client;                   /* Version native du serveur   */
+    bool status;                            /* Bilan de l'opération        */
+
+#define ADMIN_CLIENT_REQUEST_EXISTING_BINARIES_METHOD PYTHON_METHOD_DEF \
+(                                                                       \
+    request_existing_binaries, "$self, /",                              \
+    METH_NOARGS, py_admin_client,                                       \
+    "Ask the server for a list of all existing analyzed binaries"       \
+    " and returns the status of the request transmission."              \
+    "\n"                                                                \
+    "A *existing-binaries-updated* signal is emitted when the"          \
+    " pychrysalide.analysis.db.AdminClient.existing_binaries attribute" \
+    " gets ready for reading."                                          \
+)
+
+    client = G_ADMIN_CLIENT(pygobject_get(self));
+
+    status = g_admin_client_request_existing_binaries(client);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit la liste des instantanés existants.                  *
+*                                                                             *
+*  Retour      : Liste de binaires en place, vide si aucun.                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_admin_client_get_existing_binaries(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Valeur à retourner          */
+    GAdminClient *client;                   /* Version native du serveur   */
+    size_t count;                           /* Taille de cette liste       */
+    char **binaries;                        /* Liste des binaires présents */
+    size_t i;                               /* Boucle de parcours          */
+
+#define ADMIN_CLIENT_EXISTING_BINARIES_ATTRIB PYTHON_GET_DEF_FULL       \
+(                                                                       \
+    existing_binaries, py_admin_client,                                 \
+    "Provide the list of all exisiting binaries on the server side.\n"  \
+    "\n"                                                                \
+    "The returned value is a tuple of strings or an empty tuple."       \
+)
+
+    client = G_ADMIN_CLIENT(pygobject_get(self));
+
+    binaries = g_admin_client_get_existing_binaries(client, &count);
+
+    result = PyTuple_New(count);
+
+    for (i = 0; i < count; i++)
+        PyTuple_SetItem(result, i, PyUnicode_FromString(binaries[i]));
+
+    if (binaries != NULL)
+        free(binaries);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Fournit un accès à une définition de type à diffuser.        *
@@ -114,10 +202,12 @@ static PyObject *py_admin_client_new(PyTypeObject *type, PyObject *args, PyObjec
 PyTypeObject *get_python_admin_client_type(void)
 {
     static PyMethodDef py_admin_client_methods[] = {
+        ADMIN_CLIENT_REQUEST_EXISTING_BINARIES_METHOD,
         { NULL }
     };
 
     static PyGetSetDef py_admin_client_getseters[] = {
+        ADMIN_CLIENT_EXISTING_BINARIES_ATTRIB,
         { NULL }
     };
 
diff --git a/src/analysis/db/admin.c b/src/analysis/db/admin.c
index 355f8c0..771a912 100644
--- a/src/analysis/db/admin.c
+++ b/src/analysis/db/admin.c
@@ -25,10 +25,13 @@
 
 
 #include <assert.h>
+#include <malloc.h>
 #include <poll.h>
+#include <string.h>
 
 
 #include "client-int.h"
+#include "../../common/leb128.h"
 #include "../../core/logs.h"
 
 
@@ -38,6 +41,10 @@ struct _GAdminClient
 {
     GHubClient parent;                      /* A laisser en premier        */
 
+    char **binaries;                        /* Liste  de binaires existants*/
+    size_t binaries_count;                  /* Taille de cette liste       */
+    GMutex binaries_lock;                   /* Concurrence des accès       */
+
 };
 
 /* Description de client à l'écoute (classe) */
@@ -45,6 +52,10 @@ struct _GAdminClientClass
 {
     GHubClientClass parent;                 /* A laisser en premier        */
 
+    /* Signaux */
+
+    void (* existing_binaries_updated) (GAdminClient *);
+
 };
 
 
@@ -63,6 +74,9 @@ static void g_admin_client_finalize(GAdminClient *);
 /* Assure l'accueil des nouvelles mises à jour. */
 static void *g_admin_client_update(GAdminClient *);
 
+/* Met à jour la liste des binaires existants. */
+static bool g_admin_client_update_existing_binaries(GAdminClient *, packed_buffer *);
+
 
 
 /* Indique le type défini pour une description de client à l'écoute. */
@@ -96,6 +110,14 @@ static void g_admin_client_class_init(GAdminClientClass *klass)
     client->role = CRL_ADMIN;
     client->recv_func = (GThreadFunc)g_admin_client_update;
 
+    g_signal_new("existing-binaries-updated",
+                 G_TYPE_ADMIN_CLIENT,
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET(GAdminClientClass, existing_binaries_updated),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
 }
 
 
@@ -113,6 +135,9 @@ static void g_admin_client_class_init(GAdminClientClass *klass)
 
 static void g_admin_client_init(GAdminClient *client)
 {
+    client->binaries = NULL;
+    client->binaries_count = 0;
+    g_mutex_init(&client->binaries_lock);
 
 }
 
@@ -152,6 +177,19 @@ static void g_admin_client_dispose(GAdminClient *client)
 
 static void g_admin_client_finalize(GAdminClient *client)
 {
+    size_t i;                               /* Boucle de parcours          */
+
+    if (client->binaries != NULL)
+    {
+        for (i = 0; i < client->binaries_count; i++)
+            free(client->binaries[i]);
+
+        free(client->binaries);
+
+    }
+
+    g_mutex_clear(&client->binaries_lock);
+
     G_OBJECT_CLASS(g_admin_client_parent_class)->finalize(G_OBJECT(client));
 
 }
@@ -256,6 +294,11 @@ static void *g_admin_client_update(GAdminClient *client)
 
             switch (command)
             {
+                case DBC_EXISTING_BINARIES:
+                    status = g_admin_client_update_existing_binaries(client, &in_pbuf);
+                    if (!status) goto bad_exchange;
+                    break;
+
                 default:
                     log_variadic_message(LMT_INFO,
                                          _("This command is not available on this side: 0x%08x"), command);
@@ -290,3 +333,169 @@ static void *g_admin_client_update(GAdminClient *client)
     return NULL;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : client = client pour les accès distants à manipuler.         *
+*                                                                             *
+*  Description : Effectue une demande de liste de binaires existants.         *
+*                                                                             *
+*  Retour      : true si la commande a bien été envoyée, false sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_admin_client_request_existing_binaries(GAdminClient *client)
+{
+    bool result;                            /* Bilan partiel à remonter    */
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+    SSL *tls_fd;                            /* Canal de communication SSL  */
+
+    init_packed_buffer(&out_pbuf);
+
+    tls_fd = g_hub_client_get_ssl_fd(G_HUB_CLIENT(client));
+
+    if (tls_fd == NULL)
+        result = false;
+
+    else
+    {
+        result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_LIST_BINARIES }, sizeof(uint32_t), true);
+
+        if (result)
+            result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+        g_hub_client_put_ssl_fd(G_HUB_CLIENT(client), tls_fd);
+
+    }
+
+    exit_packed_buffer(&out_pbuf);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : client = client pour les accès distants à manipuler.         *
+*                pbuf   = données présentes à traiter.                        *
+*                                                                             *
+*  Description : Met à jour la liste des binaires existants.                  *
+*                                                                             *
+*  Retour      : true si l'opération s'est déroulée sans encombre, ou false.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_admin_client_update_existing_binaries(GAdminClient *client, packed_buffer *pbuf)
+{
+    bool result;                            /* Validité à retourner        */
+    size_t i;                               /* Boucle de parcours          */
+    uleb128_t count;                        /* Nombre d'éléments détectés  */
+    rle_string name;                        /* Nom à exporter              */
+
+    result = true;
+
+    g_mutex_lock(&client->binaries_lock);
+
+    if (client->binaries != NULL)
+    {
+        for (i = 0; i < client->binaries_count; i++)
+            free(client->binaries[i]);
+
+        free(client->binaries);
+
+        client->binaries = NULL;
+        client->binaries_count = 0;
+
+    }
+
+    result = unpack_uleb128(&count, pbuf);
+    if (!result) goto exit;
+
+    client->binaries_count = count;
+
+    if (count > 0)
+    {
+        client->binaries = calloc(client->binaries_count, sizeof(char *));
+
+        for (i = 0; i < client->binaries_count; i++)
+        {
+            result = unpack_rle_string(&name, pbuf);
+            if (!result) break;
+
+            client->binaries[i] = strdup(name.data);
+
+            exit_rle_string(&name);
+
+        }
+
+        if (i < client->binaries_count)
+        {
+            for (i = 0; i < client->binaries_count; i++)
+                if (client->binaries[i] != NULL)
+                    free(client->binaries[i]);
+
+            free(client->binaries);
+
+            client->binaries = NULL;
+            client->binaries_count = 0;
+
+        }
+
+    }
+
+ exit:
+
+    g_mutex_unlock(&client->binaries_lock);
+
+    if (result)
+        g_signal_emit_by_name(client, "existing-binaries-updated");
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : client = client pour les accès distants à manipuler.         *
+*                count  = taille de la liste retournée. [OUT]                 *
+*                                                                             *
+*  Description : Fournit la liste des instantanés existants.                  *
+*                                                                             *
+*  Retour      : Liste de binaires en place ou NULL si aucun.                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char **g_admin_client_get_existing_binaries(GAdminClient *client, size_t *count)
+{
+    char **result;                          /* Liste à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = NULL;
+    *count = 0;
+
+    g_mutex_lock(&client->binaries_lock);
+
+    if (client->binaries_count > 0)
+    {
+        result = malloc(client->binaries_count * sizeof(char *));
+        *count = client->binaries_count;
+
+        for (i = 0; i < client->binaries_count; i++)
+            result[i] = strdup(client->binaries[i]);
+
+    }
+
+    g_mutex_unlock(&client->binaries_lock);
+
+    return result;
+
+}
diff --git a/src/analysis/db/admin.h b/src/analysis/db/admin.h
index f5a6b5d..31366ae 100644
--- a/src/analysis/db/admin.h
+++ b/src/analysis/db/admin.h
@@ -57,6 +57,12 @@ GType g_admin_client_get_type(void);
 /* Prépare un client pour une connexion à une BD. */
 GAdminClient *g_admin_client_new(void);
 
+/* Effectue une demande de liste de binaires existants. */
+bool g_admin_client_request_existing_binaries(GAdminClient *);
+
+/* Fournit la liste des instantanés existants. */
+char **g_admin_client_get_existing_binaries(GAdminClient *, size_t *);
+
 
 
 #endif  /* _ANALYSIS_DB_ADMIN_H */
diff --git a/src/analysis/db/controller.c b/src/analysis/db/controller.c
index 46b628d..a27c20a 100644
--- a/src/analysis/db/controller.c
+++ b/src/analysis/db/controller.c
@@ -26,6 +26,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <dirent.h>
 #include <malloc.h>
 #include <poll.h>
 #include <pthread.h>
@@ -36,6 +37,8 @@
 
 
 #include "backend-int.h"
+#include "misc/rlestr.h"
+#include "../../common/leb128.h"
 #include "../../common/packed.h"
 #include "../../core/logs.h"
 
@@ -80,6 +83,9 @@ static void *g_cdb_controller_process(GCdbController *);
 /* Prend en compte une connexion nouvelle d'un utilisateur. */
 static void g_cdb_controller_add_client(GCdbController *, SSL *, const char *, const char *);
 
+/* Envoie au client la liste des binaires présents. */
+static bool g_cdb_controller_send_existing_binaries(GCdbController *, packed_buffer_t *);
+
 
 
 /* Indique le type défini pour une gestion d'archives. */
@@ -238,12 +244,10 @@ static void *g_cdb_controller_process(GCdbController *controller)
     GServerBackend *base;                   /* Base de l'instance          */
     struct pollfd fds[3];                   /* Surveillance des flux       */
     int ret;                                /* Bilan d'un appel            */
-    packed_buffer in_pbuf;                  /* Tampon de réception         */
-    uint32_t tmp32;                         /* Valeur sur 32 bits          */
+    packed_buffer_t in_pbuf;                /* Tampon de réception         */
     bool status;                            /* Bilan de lecture initiale   */
     uint32_t command;                       /* Commande de la requête      */
-    DBError error;                          /* Bilan d'une opération       */
-    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+    packed_buffer_t out_pbuf;               /* Tampon d'émission           */
     char *msg;                              /* Erreur à faire remonter     */
 
     base = G_SERVER_BACKEND(controller);
@@ -305,27 +309,23 @@ static void *g_cdb_controller_process(GCdbController *controller)
 
             switch (command)
             {
-                case DBC_LIST_ARCHIVES:
-
-                    /*
-                    error = g_cdb_controller_write(archive);
+                case DBC_LIST_BINARIES:
 
-                        init_packed_buffer(&out_pbuf);
+                    init_packed_buffer(&out_pbuf);
 
-                        status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SAVE },
-                                                      sizeof(uint32_t), true);
-                        if (!status) goto reply_error;
+                    status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_EXISTING_BINARIES },
+                                                  sizeof(uint32_t), true);
+                    if (!status) goto reply_error;
 
-                        status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
-                        if (!status) goto reply_error;
+                    status = g_cdb_controller_send_existing_binaries(controller, &out_pbuf);
+                    if (!status) goto reply_error;
 
-                        status = ssl_send_packed_buffer(&out_pbuf, controller->tls_fd);
-                        if (!status) goto reply_error;
-                        */
+                    status = ssl_send_packed_buffer(&out_pbuf, controller->tls_fd);
+                    if (!status) goto reply_error;
 
-                        exit_packed_buffer(&out_pbuf);
+                    exit_packed_buffer(&out_pbuf);
 
-                        break;
+                    break;
 
                 default:
                     asprintf(&msg, _("Bad protocol command: 0x%08x"), command);
@@ -397,16 +397,12 @@ static void g_cdb_controller_add_client(GCdbController *controller, SSL *fd, con
 }
 
 
-
-
-
-#if 0
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : controller = archive à connecter avec un utilisateur.           *
-*                pbuf    = paquet à consituer pour un envoi unique. [OUT]     *
+*  Paramètres  : controller = administration d'archives d'analyse.            *
+*                pbuf       = paquet à consituer pour un envoi unique. [OUT]  *
 *                                                                             *
-*  Description : Envoie à tous les clients la nouvelle liste d'instantanés.   *
+*  Description : Envoie au client la liste des binaires présents.             *
 *                                                                             *
 *  Retour      : Bilan de constitution de la réponse.                         *
 *                                                                             *
@@ -414,36 +410,72 @@ static void g_cdb_controller_add_client(GCdbController *controller, SSL *fd, con
 *                                                                             *
 ******************************************************************************/
 
-static bool g_cdb_controller_send_snapshot_update(GCdbController *controller, packed_buffer *pbuf)
+static bool g_cdb_controller_send_existing_binaries(GCdbController *controller, packed_buffer_t *pbuf)
 {
     bool result;                            /* Bilan à retourner           */
-    bool do_send;                           /* Réalisation de l'émission   */
-    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+    DIR *directory;                         /* Répertoire de travail       */
+    uleb128_t count;                        /* Nombre d'éléments détectés  */
+    packed_buffer_t items;                  /* Liste des éléments trouvés  */
+    struct dirent *item;                    /* Propriétés d'un élément     */
+    rle_string name;                        /* Nom à exporter              */
+    bool status;                            /* Bilan d'une inscription     */
+    int ret;                                /* Bilan de fermture           */
+
+    result = false;
+
+    directory = opendir(controller->basedir);
+    if (directory == NULL)
+    {
+        LOG_ERROR_N("opendir");
 
-    do_send = (pbuf == NULL);
+        if (errno == ENOENT)
+        {
+            count = 0;
+            result = pack_uleb128(&count, pbuf);
+        }
 
-    if (pbuf == NULL)
-        pbuf = &out_pbuf;
+        goto bad_dir;
 
-    init_packed_buffer(pbuf);
+    }
 
-    result = extend_packed_buffer(pbuf, (uint32_t []) { DBC_SNAPSHOTS_UPDATED },
-                                  sizeof(uint32_t), true);
-    if (!result) goto bad_reply;
+    count = 0;
+    init_packed_buffer(&items);
 
-    result = g_db_snapshot_pack_all(archive->snapshot, pbuf);
-    if (!result) goto bad_reply;
+    for (item = readdir(directory); item != NULL; item = readdir(directory))
+    {
+        if (item->d_type != DT_DIR)
+            continue;
 
-    result = extend_packed_buffer(pbuf, SNAPSHOT_END_MARK, SNAP_ID_HEX_SZ, false);
-    if (!result) goto bad_reply;
+        if (strcmp(item->d_name, ".") == 0 || strcmp(item->d_name, "..") == 0)
+            continue;
 
- bad_reply:
+        init_static_rle_string(&name, item->d_name);
 
-    if (do_send || !result)
-        exit_packed_buffer(pbuf);
+        status = pack_rle_string(&name, &items);
+
+        exit_rle_string(&name);
+
+        if (!status)
+            goto reg_error;
+
+        count++;
+
+    }
+
+    result = pack_uleb128(&count, pbuf);
+
+    if (result)
+        result = include_packed_buffer(pbuf, &items);
+
+ reg_error:
+
+    exit_packed_buffer(&items);
+
+    ret = closedir(directory);
+    if (ret == -1) LOG_ERROR_N("closedir");
+
+ bad_dir:
 
     return result;
 
 }
-
-#endif
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index 41e3ae7..4bef28e 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -126,8 +126,6 @@ typedef enum _DBAction
 typedef enum _DBCommand
 {
     /**
-     * Gestion des commandes 'DBC_HELO' et 'DBC_WELCOME'.
-     *
      * Le client envoie un tout premier paquet de la forme suivante :
      *
      *    [ Ordre de sauvegarde : DBC_HELO            ]
@@ -148,11 +146,21 @@ typedef enum _DBCommand
 
     /* ------------------------ Commandes pour administrateur ------------------------ */
 
+    /**
+     * Le client envoie une requête pour lister les binaires de la forme suivante :
+     *
+     *    [ Demande de liste : DBC_LIST_BINARIES      ]
+     *
+     * Le serveur liste tous les répertoires présents et renvoie cette liste :
+     *
+     *    [ Marqueur de liste : DBC_EXISTING_BINARIES ]
+     *    [ Quantité d'éléments en ULEB128            ]
+     *    [ Noms en chaîne RLE...                     ]
+     *
+     */
 
-
-    DBC_LIST_ARCHIVES,                      /* Fourniture des identifiants */
-
-
+    DBC_LIST_BINARIES,                      /* Fourniture des identifiants */
+    DBC_EXISTING_BINARIES,                  /* Eléments présents           */
 
 
     /* ------------------------ Commandes pour analyste ------------------------ */
diff --git a/tests/analysis/db/conn.py b/tests/analysis/db/conn.py
index 39c660a..f388f60 100644
--- a/tests/analysis/db/conn.py
+++ b/tests/analysis/db/conn.py
@@ -6,6 +6,7 @@ from pychrysalide.analysis.db import HubServer
 import os
 import shutil
 import tempfile
+import threading
 
 
 class TestDbConnection(ChrysalideTestCase):
@@ -113,13 +114,24 @@ class TestDbConnection(ChrysalideTestCase):
 
         #print(ret)
 
-        admin = AdminClient()
 
-        #print(admin)
 
 
+        admin = AdminClient()
+
         ret = admin.start('localhost', '9999')
+        self.assertTrue(ret)
 
-        #print('FINAL::', ret)
+        def _on_existing_binaries_updated(adm, evt):
+            evt.set()
 
-        #print(server)
+        event = threading.Event()
+
+        admin.connect('existing-binaries-updated', _on_existing_binaries_updated, event)
+
+        ret = admin.request_existing_binaries()
+        self.assertTrue(ret)
+
+        event.wait()
+
+        self.assertEqual(len(admin.existing_binaries), 0)
-- 
cgit v0.11.2-87-g4458