From b1c08dd388a86d9a9d7c379ca143ae85310c3c68 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 20 Oct 2019 15:01:24 +0200
Subject: Provided a way to update snapshots name and description.

---
 plugins/pychrysalide/analysis/db/client.c | 145 ++++++++++++++++++++++++++--
 src/analysis/db/cdb.c                     |  28 ++++++
 src/analysis/db/client.c                  | 153 ++++++++++++++++++++++++++++++
 src/analysis/db/client.h                  |   6 ++
 src/analysis/db/misc/snapshot.c           |  52 ++++++++++
 src/analysis/db/misc/snapshot.h           |   6 ++
 src/analysis/db/protocol.h                |  59 ++++++------
 src/analysis/db/snapshot.c                | 135 +++++++++++++++++++++++++-
 src/analysis/db/snapshot.h                |   6 ++
 9 files changed, 552 insertions(+), 38 deletions(-)

diff --git a/plugins/pychrysalide/analysis/db/client.c b/plugins/pychrysalide/analysis/db/client.c
index f9ce001..80e15b8 100644
--- a/plugins/pychrysalide/analysis/db/client.c
+++ b/plugins/pychrysalide/analysis/db/client.c
@@ -56,6 +56,12 @@ static PyObject *py_hub_client_save(PyObject *, PyObject *);
 /* Active les éléments en amont d'un horodatage donné. */
 static PyObject *py_hub_client_set_last_active(PyObject *, PyObject *);
 
+/* Définit la désignation d'un instantané donné. */
+static PyObject *py_hub_client_set_snapshot_name(PyObject *, PyObject *);
+
+/* Définit la désignation d'un instantané donné. */
+static PyObject *py_hub_client_set_snapshot_desc(PyObject *, PyObject *);
+
 /* Fournit la liste des instantanés existants. */
 static PyObject *py_hub_client_get_snapshots(PyObject *, void *);
 
@@ -92,7 +98,8 @@ static PyObject *py_hub_client_new(PyTypeObject *type, PyObject *args, PyObject
     GHubClient *client;                     /* Serveur mis en place        */
 
 #define HUB_CLIENT_DOC                                                                  \
-    "HubClient provides binary updates to a given server.\n"                            \
+    "HubClient provides and receives binary updates to and from a connected"            \
+    " to a server.\n"                                                                   \
     "\n"                                                                                \
     "Such clients must be authenticated and communications are encrypted using TLS.\n"  \
     "\n"                                                                                \
@@ -101,10 +108,20 @@ static PyObject *py_hub_client_new(PyTypeObject *type, PyObject *args, PyObject
     "    HubClient(hash, list)"                                                         \
     "\n"                                                                                \
     "Where hash is a SHA256 fingerprint of the studied binary and list is a list of"    \
-    " pychrysalide.analysis.db.DbCollection instances.\n"                               \
+    " pychrysalide.analysis.db.DbCollection instances ; this kind of list can be"       \
+    " retrived with the pychrysalide.analysis.LoadedBinary.collections attribute."      \
+    "\n"                                                                                \
+    "HubClient instances emit the following signals:\n"                                 \
+    "* 'snapshots-updated'\n"                                                           \
+    "    This signal is emitted when the snapshot list has evolved.\n"                  \
     "\n"                                                                                \
-    "This kind of list can be retrived with the"                                        \
-    " pychrysalide.analysis.LoadedBinary.collections attribute."
+    "    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."
 
     ret = PyArg_ParseTuple(args, "sO", &hash, &list);
     if (!ret) return NULL;
@@ -256,8 +273,6 @@ static PyObject *py_hub_client_stop(PyObject *self, PyObject *args)
 *                                                                             *
 *  Retour      : True si la commande a bien été envoyée, False sinon.         *
 *                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
@@ -272,7 +287,7 @@ static PyObject *py_hub_client_save(PyObject *self, PyObject *args)
 (                                                                           \
     save, "$self, /",                                                       \
     METH_NOARGS, py_hub_client,                                             \
-    "Ask the server for saving the current state of the analyzed binary,"   \
+    "Ask the server for saving the current state of the analyzed binary"    \
     " and returns the status of the request transmission."                  \
 )
 
@@ -297,8 +312,6 @@ static PyObject *py_hub_client_save(PyObject *self, PyObject *args)
 *                                                                             *
 *  Retour      : True si la commande a bien été envoyée, False sinon.         *
 *                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
@@ -340,6 +353,118 @@ static PyObject *py_hub_client_set_last_active(PyObject *self, PyObject *args)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = client à manipuler.                                   *
+*                args = arguments d'appel à consulter.                        *
+*                                                                             *
+*  Description : Définit la désignation d'un instantané donné.                *
+*                                                                             *
+*  Retour      : True si la commande a bien été envoyée, False sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_hub_client_set_snapshot_name(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    const char *raw_id;                     /* Identifiant brut            */
+    const char *text;                       /* Texte fourni à transmettre  */
+    int ret;                                /* Bilan de lecture des args.  */
+    snapshot_id_t id;                       /* Identifiant utilisable      */
+    bool status;                            /* Bilan d'opération           */
+    GHubClient *client;                     /* Version native du serveur   */
+
+#define HUB_CLIENT_SET_SNAPSHOT_NAME_METHOD PYTHON_METHOD_DEF               \
+(                                                                           \
+    set_snapshot_name, "$self, id, name, /",                                \
+    METH_VARARGS, py_hub_client,                                            \
+    "Ask the server for defining a new name of for a snapshot using its"    \
+    " identifier and returns the status of the request transmission."       \
+    "\n"                                                                    \
+    "A 'snapshots-updated' signal is emitted once the request has been"     \
+    " processed with success."                                              \
+)
+
+    ret = PyArg_ParseTuple(args, "ss", &raw_id, &text);
+    if (!ret) return NULL;
+
+    status = init_snapshot_id_from_text(&id, raw_id);
+    if (!status)
+    {
+        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier."));
+        return NULL;
+    }
+
+    client = G_HUB_CLIENT(pygobject_get(self));
+
+    status = g_hub_client_set_snapshot_name(client, &id, text);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = client à manipuler.                                   *
+*                args = arguments d'appel à consulter.                        *
+*                                                                             *
+*  Description : Définit la désignation d'un instantané donné.                *
+*                                                                             *
+*  Retour      : True si la commande a bien été envoyée, False sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_hub_client_set_snapshot_desc(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    const char *raw_id;                     /* Identifiant brut            */
+    const char *text;                       /* Texte fourni à transmettre  */
+    int ret;                                /* Bilan de lecture des args.  */
+    snapshot_id_t id;                       /* Identifiant utilisable      */
+    bool status;                            /* Bilan d'opération           */
+    GHubClient *client;                     /* Version native du serveur   */
+
+#define HUB_CLIENT_SET_SNAPSHOT_DESC_METHOD PYTHON_METHOD_DEF               \
+(                                                                           \
+    set_snapshot_desc, "$self, id, desc, /",                                \
+    METH_VARARGS, py_hub_client,                                            \
+    "Ask the server for defining a new description for a snapshot using"    \
+    " its identifier and returns the status of the request transmission."   \
+    "\n"                                                                    \
+    "A 'snapshots-updated' signal is emitted once the request has been"     \
+    " processed with success."                                              \
+)
+
+    ret = PyArg_ParseTuple(args, "ss", &raw_id, &text);
+    if (!ret) return NULL;
+
+    status = init_snapshot_id_from_text(&id, raw_id);
+    if (!status)
+    {
+        PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier."));
+        return NULL;
+    }
+
+    client = G_HUB_CLIENT(pygobject_get(self));
+
+    status = g_hub_client_set_snapshot_desc(client, &id, text);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
@@ -584,6 +709,8 @@ PyTypeObject *get_python_hub_client_type(void)
         HUB_CLIENT_STOP_METHOD,
         HUB_CLIENT_SAVE_METHOD,
         HUB_CLIENT_SET_LAST_ACTIVE_METHOD,
+        HUB_CLIENT_SET_SNAPSHOT_NAME_METHOD,
+        HUB_CLIENT_SET_SNAPSHOT_DESC_METHOD,
         { NULL }
     };
 
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index d569719..125f69d 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -1007,6 +1007,8 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
 
                     case DBC_GET_SNAPSHOTS:
 
+ force_snapshots_update:
+
                         init_packed_buffer(&out_pbuf);
 
                         status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SNAPSHOTS_UPDATED },
@@ -1060,6 +1062,32 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
                     case DBC_SET_CUR_SNAPSHOT:
 
 
+
+
+                        break;
+
+                    case DBC_SET_SNAPSHOT_NAME:
+
+                        error = g_db_snapshot_set_name(archive->snapshot, &in_pbuf);
+
+                        if (error == DBE_NONE)
+                            goto force_snapshots_update;
+
+                        else if (error == DBE_BAD_EXCHANGE)
+                            goto gcap_bad_exchange;
+
+                        break;
+
+                    case DBC_SET_SNAPSHOT_DESC:
+
+                        error = g_db_snapshot_set_desc(archive->snapshot, &in_pbuf);
+
+                        if (error == DBE_NONE)
+                            goto force_snapshots_update;
+
+                        else if (error == DBE_BAD_EXCHANGE)
+                            goto gcap_bad_exchange;
+
                         break;
 
                     default:
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 15ec27f..9558f85 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -92,6 +92,11 @@ struct _GHubClientClass
 {
     GObjectClass parent;                    /* A laisser en premier        */
 
+    /* Signaux */
+
+    void (* snapshots_updated) (GHubClient *);
+    void (* snapshot_changed) (GHubClient *);
+
 };
 
 
@@ -152,6 +157,22 @@ static void g_hub_client_class_init(GHubClientClass *klass)
     object->dispose = (GObjectFinalizeFunc/* ! */)g_hub_client_dispose;
     object->finalize = (GObjectFinalizeFunc)g_hub_client_finalize;
 
+    g_signal_new("snapshots-updated",
+                 G_TYPE_HUB_CLIENT,
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET(GHubClientClass, snapshots_updated),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
+    g_signal_new("snapshot-changed",
+                 G_TYPE_HUB_CLIENT,
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET(GHubClientClass, snapshot_changed),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+
 }
 
 
@@ -188,6 +209,7 @@ static void g_hub_client_init(GHubClient *client)
     client->snap_count = 0;
     g_mutex_init(&client->snap_lock);
 
+    setup_empty_snapshot_id(&client->current);
     client->has_current = false;
     g_mutex_init(&client->cur_lock);
 
@@ -857,6 +879,12 @@ static void *g_hub_client_update(GHubClient *client)
                     client->can_get_updates = (tmp8 == 0x1);
                     break;
 
+                case DBC_GET_SNAPSHOTS:
+                    log_variadic_message(LMT_INFO,
+                                         _("This command is not available on this side: 0x%08x"), command);
+                    goto gdcu_bad_exchange;
+                    break;
+
                 case DBC_SNAPSHOTS_UPDATED:
 
                     status = g_hub_client_update_snapshots(client, &in_pbuf);
@@ -878,6 +906,8 @@ static void *g_hub_client_update(GHubClient *client)
                     break;
 
                 case DBC_SET_CUR_SNAPSHOT:
+                case DBC_SET_SNAPSHOT_NAME:
+                case DBC_SET_SNAPSHOT_DESC:
                     log_variadic_message(LMT_INFO,
                                          _("This command is not available on this side: 0x%08x"), command);
                     goto gdcu_bad_exchange;
@@ -987,6 +1017,9 @@ static bool g_hub_client_update_snapshots(GHubClient *client, packed_buffer *pbu
 
     g_mutex_unlock(&client->snap_lock);
 
+    if (result)
+        g_signal_emit_by_name(client, "snapshots-updated");
+
     return result;
 
 }
@@ -1023,6 +1056,8 @@ static bool g_hub_client_update_current_snapshot(GHubClient *client, packed_buff
 
         g_mutex_unlock(&client->cur_lock);
 
+        g_signal_emit_by_name(client, "snapshot-changed");
+
     }
 
     return result;
@@ -1416,3 +1451,121 @@ bool g_hub_client_set_current_snapshot(GHubClient *client, const snapshot_id_t *
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : client = client pour les accès distants à manipuler.         *
+*                id     = identifiant d'instantané à traiter.                 *
+*                name   = désignation humaine pour l'instantané.              *
+*                                                                             *
+*  Description : Définit la désignation d'un instantané donné.                *
+*                                                                             *
+*  Retour      : true si la commande a bien été envoyée, false sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_hub_client_set_snapshot_name(GHubClient *client, const snapshot_id_t *id, const char *name)
+{
+    bool result;                            /* Bilan partiel à remonter    */
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+    SSL *tls_fd;                            /* Canal de communication SSL  */
+    rle_string string;                      /* Chaîne à transmettre        */
+
+    init_packed_buffer(&out_pbuf);
+
+    tls_fd = g_hub_client_get_ssl_fd(client);
+
+    if (tls_fd == NULL)
+        result = false;
+
+    else
+    {
+        result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_SNAPSHOT_NAME }, sizeof(uint32_t), true);
+
+        if (result)
+            result = pack_snapshot_id(id, &out_pbuf);
+
+        if (result)
+        {
+            init_static_rle_string(&string, name);
+
+            result = pack_rle_string(&string, &out_pbuf);
+
+            exit_rle_string(&string);
+
+        }
+
+        if (result)
+            result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+        g_hub_client_put_ssl_fd(client, tls_fd);
+
+    }
+
+    exit_packed_buffer(&out_pbuf);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : client = client pour les accès distants à manipuler.         *
+*                id     = identifiant d'instantané à traiter.                 *
+*                desc   = description humaine pour l'instantané.              *
+*                                                                             *
+*  Description : Définit la description d'un instantané donné.                *
+*                                                                             *
+*  Retour      : true si la commande a bien été envoyée, false sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_hub_client_set_snapshot_desc(GHubClient *client, const snapshot_id_t *id, const char *desc)
+{
+    bool result;                            /* Bilan partiel à remonter    */
+    packed_buffer out_pbuf;                 /* Tampon d'émission           */
+    SSL *tls_fd;                            /* Canal de communication SSL  */
+    rle_string string;                      /* Chaîne à transmettre        */
+
+    init_packed_buffer(&out_pbuf);
+
+    tls_fd = g_hub_client_get_ssl_fd(client);
+
+    if (tls_fd == NULL)
+        result = false;
+
+    else
+    {
+        result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_SNAPSHOT_DESC }, sizeof(uint32_t), true);
+
+        if (result)
+            result = pack_snapshot_id(id, &out_pbuf);
+
+        if (result)
+        {
+            init_static_rle_string(&string, desc);
+
+            result = pack_rle_string(&string, &out_pbuf);
+
+            exit_rle_string(&string);
+
+        }
+
+        if (result)
+            result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+        g_hub_client_put_ssl_fd(client, tls_fd);
+
+    }
+
+    exit_packed_buffer(&out_pbuf);
+
+    return result;
+
+}
diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h
index 039631e..5ad4ed0 100644
--- a/src/analysis/db/client.h
+++ b/src/analysis/db/client.h
@@ -83,6 +83,12 @@ bool g_hub_client_get_current_snapshot(GHubClient *, snapshot_id_t *);
 /* Définit l'identifiant de l'instantané courant. */
 bool g_hub_client_set_current_snapshot(GHubClient *, const snapshot_id_t *);
 
+/* Définit la désignation d'un instantané donné. */
+bool g_hub_client_set_snapshot_name(GHubClient *, const snapshot_id_t *, const char *);
+
+/* Définit la description d'un instantané donné. */
+bool g_hub_client_set_snapshot_desc(GHubClient *, const snapshot_id_t *, const char *);
+
 
 
 #endif  /* _ANALYSIS_DB_CLIENT_H */
diff --git a/src/analysis/db/misc/snapshot.c b/src/analysis/db/misc/snapshot.c
index c441ead..723ba75 100644
--- a/src/analysis/db/misc/snapshot.c
+++ b/src/analysis/db/misc/snapshot.c
@@ -509,3 +509,55 @@ bool pack_snapshot_info(const snapshot_info_t *info, packed_buffer *pbuf)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info = informations à mettre à jour.                         *
+*                name = nouvelle désignation à considérer.                    *
+*                                                                             *
+*  Description : Change la désignation dans les informations d'un instantané. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void set_snapshot_info_name(snapshot_info_t *info, const char *name)
+{
+    if (info->name == NULL)
+        free(info->name);
+
+    if (name == NULL)
+        info->name = NULL;
+    else
+        info->name = strdup(name);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info = informations à mettre à jour.                         *
+*                desc = nouvelle description à considérer.                    *
+*                                                                             *
+*  Description : Change la description dans les informations d'un instantané. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void set_snapshot_info_desc(snapshot_info_t *info, const char *desc)
+{
+    if (info->desc == NULL)
+        free(info->desc);
+
+    if (desc == NULL)
+        info->desc = NULL;
+    else
+        info->desc = strdup(desc);
+
+}
diff --git a/src/analysis/db/misc/snapshot.h b/src/analysis/db/misc/snapshot.h
index 8f9a598..3f55b50 100644
--- a/src/analysis/db/misc/snapshot.h
+++ b/src/analysis/db/misc/snapshot.h
@@ -122,6 +122,12 @@ bool unpack_snapshot_info(snapshot_info_t *, packed_buffer *);
 /* Exporte la description d'un identifiant d'instantané. */
 bool pack_snapshot_info(const snapshot_info_t *, packed_buffer *);
 
+/* Change la désignation dans les informations d'un instantané. */
+void set_snapshot_info_name(snapshot_info_t *, const char *);
+
+/* Change la description dans les informations d'un instantané. */
+void set_snapshot_info_desc(snapshot_info_t *, const char *);
+
 
 
 #endif  /* _ANALYSIS_DB_MISC_SNAPSHOT_H */
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index 273be8e..b57c25c 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -129,11 +129,6 @@ typedef enum _DBCommand
      *    [ Ordre de sauvegarde : DBC_SAVE            ]
      *    [ Statut d'exécution ; cf. DBError          ]
      *
-     * Les traitements se réalisent dans :
-     *  - g_db_client_save() pour la partie client en émission ;
-     *  - g_cdb_archive_process() pour la partie serveur ;
-     *  - g_db_client_update() pour la partie client en réception.
-     *
      */
 
     DBC_SAVE,                               /* Enregistrement de l'archive */
@@ -167,10 +162,6 @@ typedef enum _DBCommand
      *    [ Notification de maj : DBC_SET_ALL_ITEMS     ]
      *    [ marqueur de fin : octet 0x0                 ]
      *
-     * Les traitements se réalisent dans :
-     *  - g_db_client_update() pour la partie client ;
-     *  - g_cdb_archive_process() pour la partie serveur.
-     *
      */
 
     DBC_GET_ALL_ITEMS,                      /* Mise à jour à la connexion  */
@@ -191,10 +182,6 @@ typedef enum _DBCommand
      *    [ Action : DBA_CHANGE_STATE                   ]
      *    [ <élément dont le statut a évolué>           ]
      *
-     * Les traitements se réalisent dans :
-     *  - g_db_collection_disable_at() pour la partie serveur ;
-     *  - g_db_collection_update_item_state() pour la partie client.
-     *
      */
 
     DBC_SET_LAST_ACTIVE,                    /* Définition du dernier actif */   // REMME
@@ -208,9 +195,6 @@ typedef enum _DBCommand
      *
      *    [ Gestion d'instantané : DBC_GET_SNAPSHOTS            ]
      *
-     * La définition d'un nouvel identifiant d'instantané courant se réalise dans :
-     *  - g_hub_client_update() pour la partie client ;
-     *  - g_cdb_archive_process() pour la partie serveur.
      */
 
     DBC_GET_SNAPSHOTS,
@@ -224,9 +208,6 @@ typedef enum _DBCommand
      *    [ <liste de descriptions d'instantanés>               ]
      *    [ Marqueur de fin : SNAPSHOT_END_MARK                 ]
      *
-     * La définition d'un nouvel identifiant d'instantané courant se réalise dans :
-     *  - g_cdb_archive_process() pour la partie serveur ;
-     *  - g_hub_client_update() pour la partie client.
      */
 
     DBC_SNAPSHOTS_UPDATED,                  /* Identification d'instantanés*/
@@ -238,9 +219,6 @@ typedef enum _DBCommand
      *
      *    [ Gestion d'instantané : DBC_GET_CUR_SNAPSHOT         ]
      *
-     * La définition d'un nouvel identifiant d'instantané courant se réalise dans :
-     *  - g_hub_client_update() pour la partie client ;
-     *  - g_cdb_archive_process() pour la partie serveur.
      */
 
     DBC_GET_CUR_SNAPSHOT,                   /* Demande d'identification    */
@@ -253,9 +231,6 @@ typedef enum _DBCommand
      *    [ Gestion d'instantané : DBC_CUR_SNAPSHOT_UPDATED     ]
      *    [ <identifiant d'instantané>                          ]
      *
-     * La définition d'un nouvel identifiant d'instantané courant se réalise dans :
-     *  - g_cdb_archive_process() pour la partie serveur ;
-     *  - g_hub_client_update() pour la partie client.
      */
 
     DBC_CUR_SNAPSHOT_UPDATED,               /* Mise à jour de l'instantané */
@@ -268,13 +243,40 @@ typedef enum _DBCommand
      *    [ Gestion d'instantané : DBC_SET_CUR_SNAPSHOT         ]
      *    [ <identifiant d'instantané>                          ]
      *
-     * La définition d'un nouvel identifiant d'instantané courant se réalise dans :
-     *  - g_hub_client_set_current_snapshot() pour la partie client ;
-     *  - 
      */
 
     DBC_SET_CUR_SNAPSHOT,                   /* Définition de l'instantané  */
 
+    /**
+     * Gestion de la commande 'DBC_SET_SNAPSHOT_NAME'.
+     *
+     * Le client connecté envoie un paquet de la forme suivante :
+     *
+     *    [ Gestion d'instantané : DBC_SET_SNAPSHOT_NAME        ]
+     *    [ <identifiant d'instantané>                          ]
+     *    [ <chaîne de caractères>                              ]
+     *
+     * Le serveur renvoie ensuite automatiquement un paquet
+     * de type 'DBC_SNAPSHOTS_UPDATED'.
+     */
+
+    DBC_SET_SNAPSHOT_NAME,                  /* Désignation de l'instantané */
+
+    /**
+     * Gestion de la commande 'DBC_SET_SNAPSHOT_DESC'.
+     *
+     * Le client connecté envoie un paquet de la forme suivante :
+     *
+     *    [ Gestion d'instantané : DBC_SET_SNAPSHOT_DESC        ]
+     *    [ <identifiant d'instantané>                          ]
+     *    [ <chaîne de caractères>                              ]
+     *
+     * Le serveur renvoie ensuite automatiquement un paquet
+     * de type 'DBC_SNAPSHOTS_UPDATED'.
+     */
+
+    DBC_SET_SNAPSHOT_DESC,                  /* Description de l'instantané */
+
     DBC_COUNT
 
 } DBCommand;
@@ -300,6 +302,7 @@ typedef enum _DBError
     DBE_DB_LOADING_ERROR,                   /* Erreur pendant le chargement*/
 
     DBE_XML_ERROR,                          /* Erreur lors d'une définition*/
+    DBE_SNAPSHOT_NOT_FOUND,                 /* Instantané non trouvé       */
 
     DBE_COUNT
 
diff --git a/src/analysis/db/snapshot.c b/src/analysis/db/snapshot.c
index 79128ef..2cd50f6 100644
--- a/src/analysis/db/snapshot.c
+++ b/src/analysis/db/snapshot.c
@@ -942,6 +942,9 @@ bool g_db_snapshot_fill(GDbSnapshot *snap, struct archive *archive)
 
         node = find_snapshot_node(snap->nodes, &node_id);
 
+        if (node == NULL)
+            break;
+
         if (!setup_snapshot_node_db_path(node, snap->tmpdir, snap->hash))
             break;
 
@@ -1059,7 +1062,7 @@ sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *snap, const snapshot_id_t
 
     if (node == NULL)
     {
-        log_variadic_message(LMT_ERROR, _("Snapshot not found for id '%s'"), *id);
+        log_variadic_message(LMT_ERROR, _("Snapshot not found for id '%s'"), snapshot_id_as_string(id));
         result = NULL;
     }
 
@@ -1105,3 +1108,133 @@ bool g_db_snapshot_pack_all(const GDbSnapshot *snap, packed_buffer *pbuf)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : snap    = gestionnaire d'instantanés à consulter.            *
+*                pbuf = paquet de données où venir puiser les infos.          *
+*                                                                             *
+*  Description : Actualise la désignation d'un instantané donné.              *
+*                                                                             *
+*  Retour      : Bilan de l'opération sous forme de code d'erreur.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+DBError g_db_snapshot_set_name(const GDbSnapshot *snap, packed_buffer *pbuf)
+{
+    DBError result;                         /* Conclusion à retourner      */
+    snapshot_id_t id;                       /* Identifiant d'instantané    */
+    bool status;                            /* Bilan d'une récupération    */
+    rle_string string;                      /* Chaîne à transmettre        */
+    snapshot_node_t *node;                  /* Instantané trouvé           */
+
+    result = DBE_NONE;
+
+    /* Lecture des arguments */
+
+    setup_empty_snapshot_id(&id);
+
+    status = unpack_snapshot_id(&id, pbuf);
+    if (!status)
+    {
+        result = DBE_BAD_EXCHANGE;
+        goto bad_exchange;
+    }
+
+    setup_empty_rle_string(&string);
+
+    status = unpack_rle_string(&string, pbuf);
+    if (!status)
+    {
+        result = DBE_BAD_EXCHANGE;
+        goto bad_exchange;
+    }
+
+    /* Traitement */
+
+    node = find_snapshot_node(snap->nodes, &id);
+
+    if (node == NULL)
+    {
+        log_variadic_message(LMT_ERROR, _("Snapshot not found for id '%s'"), snapshot_id_as_string(&id));
+        result = DBE_SNAPSHOT_NOT_FOUND;
+    }
+
+    else
+        set_snapshot_info_name(&node->info, get_rle_string(&string));
+
+    exit_rle_string(&string);
+
+ bad_exchange:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : snap    = gestionnaire d'instantanés à consulter.            *
+*                pbuf = paquet de données où venir puiser les infos.          *
+*                                                                             *
+*  Description : Actualise la description d'un instantané donné.              *
+*                                                                             *
+*  Retour      : Bilan de l'opération sous forme de code d'erreur.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+DBError g_db_snapshot_set_desc(const GDbSnapshot *snap, packed_buffer *pbuf)
+{
+    DBError result;                         /* Conclusion à retourner      */
+    snapshot_id_t id;                       /* Identifiant d'instantané    */
+    bool status;                            /* Bilan d'une récupération    */
+    rle_string string;                      /* Chaîne à transmettre        */
+    snapshot_node_t *node;                  /* Instantané trouvé           */
+
+    result = DBE_NONE;
+
+    /* Lecture des arguments */
+
+    setup_empty_snapshot_id(&id);
+
+    status = unpack_snapshot_id(&id, pbuf);
+    if (!status)
+    {
+        result = DBE_BAD_EXCHANGE;
+        goto bad_exchange;
+    }
+
+    setup_empty_rle_string(&string);
+
+    status = unpack_rle_string(&string, pbuf);
+    if (!status)
+    {
+        result = DBE_BAD_EXCHANGE;
+        goto bad_exchange;
+    }
+
+    /* Traitement */
+
+    node = find_snapshot_node(snap->nodes, &id);
+
+    if (node == NULL)
+    {
+        log_variadic_message(LMT_ERROR, _("Snapshot not found for id '%s'"), snapshot_id_as_string(&id));
+        result = DBE_SNAPSHOT_NOT_FOUND;
+    }
+
+    else
+        set_snapshot_info_desc(&node->info, get_rle_string(&string));
+
+    exit_rle_string(&string);
+
+ bad_exchange:
+
+    return result;
+
+}
diff --git a/src/analysis/db/snapshot.h b/src/analysis/db/snapshot.h
index 543d184..457e8c2 100644
--- a/src/analysis/db/snapshot.h
+++ b/src/analysis/db/snapshot.h
@@ -77,6 +77,12 @@ sqlite3 *g_db_snapshot_get_database(const GDbSnapshot *, const snapshot_id_t *);
 /* Collecte les descriptions de l'ensemble des instantanés. */
 bool g_db_snapshot_pack_all(const GDbSnapshot *, packed_buffer *);
 
+/* Actualise la désignation d'un instantané donné. */
+DBError g_db_snapshot_set_name(const GDbSnapshot *, packed_buffer *);
+
+/* Actualise la description d'un instantané donné. */
+DBError g_db_snapshot_set_desc(const GDbSnapshot *, packed_buffer *);
+
 
 
 #endif  /* _ANALYSIS_DB_SNAPSHOT_H */
-- 
cgit v0.11.2-87-g4458