From fbb80d00d8ac456451963d52af24fcccbbc1d751 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 8 Sep 2019 09:47:41 +0200
Subject: Updated the database protocol for bookmarks.

---
 plugins/pychrysalide/analysis/binary.c             |  58 +++
 plugins/pychrysalide/analysis/db/item.c            |  45 +++
 plugins/pychrysalide/analysis/db/item.h            |   3 +
 plugins/pychrysalide/analysis/db/items/Makefile.am |   1 +
 plugins/pychrysalide/analysis/db/items/bookmark.c  | 397 +++++++++++++++++++++
 plugins/pychrysalide/analysis/db/items/bookmark.h  |  45 +++
 plugins/pychrysalide/analysis/db/items/module.c    |   2 +
 src/analysis/binary.c                              |  20 +-
 src/analysis/db/cdb.c                              |  10 +
 src/analysis/db/client.c                           |  44 ++-
 src/analysis/db/client.h                           |   5 +-
 src/analysis/db/items/bookmark.c                   |  59 +--
 src/analysis/db/items/bookmark.h                   |  30 +-
 src/analysis/db/protocol.h                         |  47 +--
 src/common/packed.c                                |  29 ++
 src/common/packed.h                                |   3 +
 16 files changed, 720 insertions(+), 78 deletions(-)
 create mode 100644 plugins/pychrysalide/analysis/db/items/bookmark.c
 create mode 100644 plugins/pychrysalide/analysis/db/items/bookmark.h

diff --git a/plugins/pychrysalide/analysis/binary.c b/plugins/pychrysalide/analysis/binary.c
index e137f87..98b20dc 100644
--- a/plugins/pychrysalide/analysis/binary.c
+++ b/plugins/pychrysalide/analysis/binary.c
@@ -38,12 +38,16 @@
 #include "../access.h"
 #include "../helpers.h"
 #include "../format/executable.h"
+#include "db/item.h"
 
 
 
 /* Crée un nouvel objet Python de type 'LoadedBinary'. */
 static PyObject *py_loaded_binary_new(PyTypeObject *, PyObject *, PyObject *);
 
+/* Demande l'intégration d'une modification dans une collection. */
+static PyObject *py_loaded_binary_add_to_collection(PyObject *, PyObject *);
+
 /* Fournit le nom associé à l'élément binaire. */
 static PyObject *py_loaded_binary_get_name(PyObject *, void *);
 
@@ -96,6 +100,59 @@ static PyObject *py_loaded_binary_new(PyTypeObject *type, PyObject *args, PyObje
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = objet représentant un binaire chargé.                 *
+*                args = arguments fournis pour l'opération.                   *
+*                                                                             *
+*  Description : Demande l'intégration d'une modification dans une collection.*
+*                                                                             *
+*  Retour      : Bilan partiel de l'opération demandée.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_loaded_binary_add_to_collection(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    GDbItem *item;                          /* Elément à intégrer          */
+    int ret;                                /* Bilan de lecture des args.  */
+    GLoadedBinary *binary;                  /* Binaire en cours d'analyse  */
+    bool status;                            /* Bilan de l'opération        */
+
+#define LOADED_BINARY_ADD_TO_COLLECTION_METHOD PYTHON_METHOD_DEF            \
+(                                                                           \
+    add_to_collection, "$self, item, /",                                    \
+    METH_VARARGS, py_loaded_binary,                                         \
+    "Ask a server to include the given item into the update database."      \
+    "\n"                                                                    \
+    "The server type (internal or remote) depends on the collection type"   \
+    " linked to the item and the user configuration."                       \
+    "\n"                                                                    \
+    "The item has to be a subclass of pychrysalide.analysis.db.DbItem."     \
+    "\n"                                                                    \
+    "The method returns True if the item has been successfully forwarded"   \
+    " to a server, False otherwise."                                        \
+)
+
+    ret = PyArg_ParseTuple(args, "O&", convert_to_db_item, &item);
+    if (!ret) return NULL;
+
+    binary = G_LOADED_BINARY(pygobject_get(self));
+
+    g_object_ref(G_OBJECT(item));
+
+    status = g_loaded_binary_add_to_collection(binary, item);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
@@ -246,6 +303,7 @@ static PyObject *py_loaded_binary_get_disassembled_cache(PyObject *self, void *c
 PyTypeObject *get_python_loaded_binary_type(void)
 {
     static PyMethodDef py_loaded_binary_methods[] = {
+        LOADED_BINARY_ADD_TO_COLLECTION_METHOD,
         { NULL }
     };
 
diff --git a/plugins/pychrysalide/analysis/db/item.c b/plugins/pychrysalide/analysis/db/item.c
index 0544d86..981e0c0 100644
--- a/plugins/pychrysalide/analysis/db/item.c
+++ b/plugins/pychrysalide/analysis/db/item.c
@@ -188,3 +188,48 @@ bool ensure_python_db_item_is_registered(void)
     return true;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en élément pour base de données.          *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_db_item(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_db_item_type());
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to database item");
+            break;
+
+        case 1:
+            *((GDbItem **)dst) = G_DB_ITEM(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/db/item.h b/plugins/pychrysalide/analysis/db/item.h
index 376371b..09a6a07 100644
--- a/plugins/pychrysalide/analysis/db/item.h
+++ b/plugins/pychrysalide/analysis/db/item.h
@@ -37,6 +37,9 @@ PyTypeObject *get_python_db_item_type(void);
 /* Prend en charge l'objet 'pychrysalide.analysis.db.DbItem'. */
 bool ensure_python_db_item_is_registered(void);
 
+/* Tente de convertir en élément pour base de données. */
+int convert_to_db_item(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEM_H */
diff --git a/plugins/pychrysalide/analysis/db/items/Makefile.am b/plugins/pychrysalide/analysis/db/items/Makefile.am
index fbb3e22..bea86de 100644
--- a/plugins/pychrysalide/analysis/db/items/Makefile.am
+++ b/plugins/pychrysalide/analysis/db/items/Makefile.am
@@ -2,6 +2,7 @@
 noinst_LTLIBRARIES = libpychrysaanalysisdbitems.la
 
 libpychrysaanalysisdbitems_la_SOURCES =	\
+	bookmark.h bookmark.c				\
 	comment.h comment.c					\
 	module.h module.c
 
diff --git a/plugins/pychrysalide/analysis/db/items/bookmark.c b/plugins/pychrysalide/analysis/db/items/bookmark.c
new file mode 100644
index 0000000..8a33357
--- /dev/null
+++ b/plugins/pychrysalide/analysis/db/items/bookmark.c
@@ -0,0 +1,397 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bookmark.c - équivalent Python du fichier "analysis/db/items/bookmark.c"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "bookmark.h"
+
+
+#include <malloc.h>
+#include <pygobject.h>
+
+
+#include <analysis/db/items/bookmark.h>
+#include <plugins/dt.h>
+
+
+#include "../item.h"
+#include "../../../access.h"
+#include "../../../helpers.h"
+#include "../../../arch/vmpa.h"
+
+
+
+/* Crée un nouvel objet Python de type 'DbBookmark'. */
+static PyObject *py_db_bookmark_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_db_bookmark_init(PyObject *, PyObject *, PyObject *);
+
+/* Fournit l'adresse associée à un signet. */
+static PyObject *py_db_bookmark_get_address(PyObject *, void *);
+
+/* Fournit le commentaire associé à un signet. */
+static PyObject *py_db_bookmark_get_comment(PyObject *, void *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type de l'objet à instancier.                         *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Crée un nouvel objet Python de type 'DbBookmark'.            *
+*                                                                             *
+*  Retour      : Instance Python mise en place.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_db_bookmark_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyObject *result;                       /* Objet à retourner           */
+    PyTypeObject *base;                     /* Type de base à dériver      */
+    bool first_time;                        /* Evite les multiples passages*/
+    GType gtype;                            /* Nouveau type de processeur  */
+    bool status;                            /* Bilan d'un enregistrement   */
+
+    /* Validations diverses */
+
+    base = get_python_db_bookmark_type();
+
+    if (type == base)
+        goto simple_way;
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_DB_BOOKMARK, type->tp_name, NULL, NULL, NULL);
+
+    if (first_time)
+    {
+        status = register_class_for_dynamic_pygobject(gtype, type, base);
+
+        if (!status)
+        {
+            result = NULL;
+            goto exit;
+        }
+
+    }
+
+    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
+
+ simple_way:
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet à initialiser (théoriquement).                  *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Initialise une instance sur la base du dérivé de GObject.    *
+*                                                                             *
+*  Retour      : 0 en cas de succès, -1 sinon.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_db_bookmark_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    int result;                             /* Bilan à renvoyer            */
+    vmpa2t addr;                            /* Emplacement ciblé           */
+    const char *comment;                    /* Commentaire éventuel associé*/
+    int ret;                                /* Bilan de lecture des args.  */
+    PyObject *new_args;                     /* Nouveaux arguments épurés   */
+    PyObject *new_kwds;                     /* Nouveau dictionnaire épuré  */
+    GDbBookmark *bookmark;                  /* Version GLib du signet      */
+    bool status;                            /* Bilan de l'initialisation   */
+
+#define DB_BOOKMARK_DOC                                                         \
+    "DbBookmark provides support for bookmarks inside the disassembled code.\n" \
+    "\n"                                                                        \
+    "Instances can be created using the following constructor:\n"               \
+    "\n"                                                                        \
+    "    DbBookmark(addr, comment=None)"                                        \
+    "\n"                                                                        \
+    "Where addr is a location of type pychrysalide.arch.vmpa and"               \
+    " comment is a string or None."
+
+    result = -1;
+
+    /* Récupération des paramètres */
+
+    comment = NULL;
+
+    ret = PyArg_ParseTuple(args, "O&|s", convert_any_to_vmpa, &addr, &comment);
+    if (!ret) goto exit;
+
+    /* Initialisation d'un objet GLib */
+
+    new_args = PyTuple_New(0);
+    new_kwds = PyDict_New();
+
+    ret = PyGObject_Type.tp_init(self, new_args, new_kwds);
+
+    Py_DECREF(new_kwds);
+    Py_DECREF(new_args);
+
+    if (ret == -1) goto exit;
+
+    /* Eléments de base */
+
+    bookmark = G_DB_BOOKMARK(pygobject_get(self));
+
+    status = g_db_bookmark_fill(bookmark, &addr, comment);
+    if (!status) goto exit;
+
+    result = 0;
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit l'adresse associée à un signet.                      *
+*                                                                             *
+*  Retour      : Adresse mémoire.                                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_db_bookmark_get_address(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GDbBookmark *bookmark;                  /* Signet à consulter          */
+    const vmpa2t *addr;                     /* Localisation de ce signet   */
+
+#define DB_BOOKMARK_ADDRESS_ATTRIB PYTHON_GET_DEF_FULL  \
+(                                                       \
+    address, py_db_bookmark,                            \
+    "Location of the bookmark."                         \
+)
+
+    bookmark = G_DB_BOOKMARK(pygobject_get(self));
+
+    addr = g_db_bookmark_get_address(bookmark);
+
+    result = build_from_internal_vmpa(addr);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit le commentaire associé à un signet.                  *
+*                                                                             *
+*  Retour      : Commentaire existant ou None.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_db_bookmark_get_comment(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GDbBookmark *bookmark;                  /* Signet à consulter          */
+    const char *comment;                    /* Contenu textuel associé     */
+
+#define DB_BOOKMARK_COMMENT_ATTRIB PYTHON_GET_DEF_FULL                          \
+(                                                                               \
+    comment, py_db_bookmark,                                                    \
+    "Comment linked to the bookmark or None if the bookmark has been unset."    \
+)
+
+    bookmark = G_DB_BOOKMARK(pygobject_get(self));
+
+    comment = g_db_bookmark_get_comment(bookmark);
+
+    if (comment != NULL)
+        result = PyUnicode_FromString(comment);
+
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_db_bookmark_type(void)
+{
+    static PyMethodDef py_db_bookmark_methods[] = {
+        { NULL }
+    };
+
+    static PyGetSetDef py_db_bookmark_getseters[] = {
+        DB_BOOKMARK_ADDRESS_ATTRIB,
+        DB_BOOKMARK_COMMENT_ATTRIB,
+        { NULL }
+    };
+
+    static PyTypeObject py_db_bookmark_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.analysis.db.items.DbBookmark",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+
+        .tp_doc         = DB_BOOKMARK_DOC,
+
+        .tp_methods     = py_db_bookmark_methods,
+        .tp_getset      = py_db_bookmark_getseters,
+
+        .tp_init        = py_db_bookmark_init,
+        .tp_new         = py_db_bookmark_new,
+
+    };
+
+    return &py_db_bookmark_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide...db.items.DbBookmark'.*
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_db_bookmark_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'DbBookmark'    */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_db_bookmark_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.analysis.db.items");
+
+        dict = PyModule_GetDict(module);
+
+        if (!ensure_python_db_item_is_registered())
+            return false;
+
+        if (!register_class_for_pygobject(dict, G_TYPE_DB_BOOKMARK, type, get_python_db_item_type()))
+            return false;
+
+    }
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en signet de collection.                  *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_db_bookmark(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_db_bookmark_type());
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to collection bookmark");
+            break;
+
+        case 1:
+            *((GDbBookmark **)dst) = G_DB_BOOKMARK(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/db/items/bookmark.h b/plugins/pychrysalide/analysis/db/items/bookmark.h
new file mode 100644
index 0000000..bcf1c11
--- /dev/null
+++ b/plugins/pychrysalide/analysis/db/items/bookmark.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * bookmark.h - prototypes pour l'équivalent Python du fichier "analysis/db/items/bookmark.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_BOOKMARK_H
+#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_BOOKMARK_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_db_bookmark_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.analysis.db.items.DbBookmark'. */
+bool ensure_python_db_bookmark_is_registered(void);
+
+/* Tente de convertir en signet de collection. */
+int convert_to_db_bookmark(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_BOOKMARK_H */
diff --git a/plugins/pychrysalide/analysis/db/items/module.c b/plugins/pychrysalide/analysis/db/items/module.c
index 1f9e580..fcf636f 100644
--- a/plugins/pychrysalide/analysis/db/items/module.c
+++ b/plugins/pychrysalide/analysis/db/items/module.c
@@ -28,6 +28,7 @@
 #include <assert.h>
 
 
+#include "bookmark.h"
 #include "comment.h"
 #include "../../../helpers.h"
 
@@ -88,6 +89,7 @@ bool populate_analysis_db_items_module(void)
 
     result = true;
 
+    if (result) result = ensure_python_db_bookmark_is_registered();
     if (result) result = ensure_python_db_comment_is_registered();
 
     assert(result);
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index cf680c3..639d6cc 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -1068,7 +1068,7 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo
     DBStorage storage;                      /* Forme d'enregistrement      */
     GHubClient *client;                     /* Liaison à utiliser          */
     packed_buffer out_pbuf;                 /* Tampon d'émission           */
-    int fd;                                 /* Identifiant du canal de com.*/
+    SSL *tls_fd;                            /* Canal de communication SSL  */
 
     feature = g_db_item_get_feature(item);
 
@@ -1099,14 +1099,14 @@ bool _g_loaded_binary_add_to_collection(GLoadedBinary *binary, GDbItem *item, bo
         {
             init_packed_buffer(&out_pbuf);
 
-            fd = g_hub_client_get_fd(client);
+            tls_fd = g_hub_client_get_ssl_fd(client);
 
             result = g_db_collection_pack(collec, &out_pbuf, DBA_ADD_ITEM, item);
 
-            g_hub_client_put_fd(client);
-
             if (result)
-                result = send_packed_buffer(&out_pbuf, fd);
+                result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+            g_hub_client_put_ssl_fd(client, tls_fd);
 
             exit_packed_buffer(&out_pbuf);
 
@@ -1144,7 +1144,7 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f
     DBStorage storage;                      /* Forme d'enregistrement      */
     GHubClient *client;                     /* Liaison à utiliser          */
     packed_buffer out_pbuf;                 /* Tampon d'émission           */
-    int fd;                                 /* Identifiant du canal de com.*/
+    SSL *tls_fd;                            /* Canal de communication SSL  */
 
     collec = g_loaded_binary_find_collection(binary, feature);
     if (collec == NULL) return false;
@@ -1168,14 +1168,14 @@ bool _g_loaded_binary_remove_from_collection(GLoadedBinary *binary, DBFeatures f
 
         init_packed_buffer(&out_pbuf);
 
-        fd = g_hub_client_get_fd(client);
+        tls_fd = g_hub_client_get_ssl_fd(client);
 
         result = g_db_collection_pack(collec, &out_pbuf, DBA_REM_ITEM, item);
 
-        g_hub_client_put_fd(client);
-
         if (result)
-            result = send_packed_buffer(&out_pbuf, fd);
+            result = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+
+        g_hub_client_put_ssl_fd(client, tls_fd);
 
         exit_packed_buffer(&out_pbuf);
 
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index 74e8501..597242f 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -939,9 +939,19 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
                                                       sizeof(uint32_t), true);
                         if (!status) goto gcap_bad_reply;
 
+                        status = extend_packed_buffer(&out_pbuf, (uint8_t []) { 0x1 }, sizeof(uint8_t), true);
+                        if (!status) goto gcap_bad_reply;
+
                         status = pack_all_collection_updates(archive->collections, &out_pbuf);
                         if (!status) goto gcap_bad_reply;
 
+                        status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_ALL_ITEMS },
+                                                      sizeof(uint32_t), true);
+                        if (!status) goto gcap_bad_reply;
+
+                        status = extend_packed_buffer(&out_pbuf, (uint8_t []) { 0x0 }, sizeof(uint8_t), true);
+                        if (!status) goto gcap_bad_reply;
+
                         status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
                         if (!status) goto gcap_bad_reply;
 
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 9252ccc..2bfa978 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -31,7 +31,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <openssl/err.h>
-#include <openssl/ssl.h>
 
 
 #include <i18n.h>
@@ -682,6 +681,7 @@ static void *g_hub_client_update(GHubClient *client)
     uint32_t command;                       /* Commande de la requête      */
     DBError error;                          /* Bilan d'une commande passée */
     GDbCollection *collec;                  /* Collection visée au final   */
+    uint8_t tmp8;                           /* Valeur sur 8 bits           */
     char *msg;                              /* Message d'erreur à imprimer */
 
     /**
@@ -740,6 +740,8 @@ static void *g_hub_client_update(GHubClient *client)
             status = ssl_recv_packed_buffer(&in_pbuf, client->tls_fd);
             if (!status) goto gdcu_bad_exchange;
 
+ next_command:
+
             status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
             if (!status) goto gdcu_bad_exchange;
 
@@ -785,11 +787,18 @@ static void *g_hub_client_update(GHubClient *client)
                     break;
 
                 case DBC_SET_ALL_ITEMS:
-                    client->can_get_updates = true;
+
+                    status = extract_packed_buffer(&in_pbuf, &tmp8, sizeof(uint8_t), true);
+                    if (!status) goto gdcu_bad_exchange;
+
+                    client->can_get_updates = (tmp8 == 0x1);
                     break;
 
             }
 
+            if (has_more_data_in_packed_buffer(&in_pbuf))
+                goto next_command;
+
             continue;
 
  gdcu_bad_exchange:
@@ -882,11 +891,25 @@ void g_hub_client_stop(GHubClient *client)
 *                                                                             *
 ******************************************************************************/
 
-int g_hub_client_get_fd(GHubClient *client)
+SSL *g_hub_client_get_ssl_fd(GHubClient *client)
 {
+    SSL *result;                            /* Canal à retourner           */
+#ifndef NDEBUG
+    int ret;                                /* Validation de transmission  */
+#endif
+
     g_mutex_lock(&client->sending_lock);
 
-    return client->fd;
+    result = client->tls_fd;
+
+#ifndef NDEBUG
+    ret = SSL_up_ref(result);
+    assert(ret == 1);
+#else
+    SSL_up_ref(result);
+#endif
+
+    return result;
 
 }
 
@@ -894,6 +917,7 @@ int g_hub_client_get_fd(GHubClient *client)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : client = client pour les accès distants à manipuler.         *
+*                tls_fd = canal de communication SSL.                         *
 *                                                                             *
 *  Description : Marque le canal de communication comme disponible.           *
 *                                                                             *
@@ -903,10 +927,12 @@ int g_hub_client_get_fd(GHubClient *client)
 *                                                                             *
 ******************************************************************************/
 
-void g_hub_client_put_fd(GHubClient *client)
+void g_hub_client_put_ssl_fd(GHubClient *client, SSL *tls_fd)
 {
     g_mutex_unlock(&client->sending_lock);
 
+    SSL_free(tls_fd);
+
 }
 
 
@@ -927,13 +953,13 @@ bool g_hub_client_save(GHubClient *client)
     bool result;                            /* Bilan partiel à remonter    */
     int sent;                               /* Quantité de données traitées*/
 
-    g_hub_client_get_fd(client);
+    g_hub_client_get_ssl_fd(client);
 
     sent = SSL_write(client->tls_fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t));
 
     result = (sent == sizeof(uint32_t));
 
-    g_hub_client_put_fd(client);
+    g_hub_client_put_ssl_fd(client, client->tls_fd);
 
     return result;
 
@@ -960,14 +986,14 @@ bool g_hub_client_set_last_active(GHubClient *client, timestamp_t timestamp)
 
     init_packed_buffer(&out_pbuf);
 
-    g_hub_client_get_fd(client);
+    g_hub_client_get_ssl_fd(client);
 
     result = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_SET_LAST_ACTIVE }, sizeof(uint32_t), true);
 
     if (result)
         result = pack_timestamp(&timestamp, &out_pbuf);
 
-    g_hub_client_put_fd(client);
+    g_hub_client_put_ssl_fd(client, client->tls_fd);
 
     if (result)
         result = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h
index 66ca6ab..2915f77 100644
--- a/src/analysis/db/client.h
+++ b/src/analysis/db/client.h
@@ -27,6 +27,7 @@
 
 #include <glib-object.h>
 #include <stdbool.h>
+#include <openssl/ssl.h>
 
 
 #include "collection.h"
@@ -64,10 +65,10 @@ bool g_hub_client_start_remote(GHubClient *, const char *, const char *, bool);
 void g_hub_client_stop(GHubClient *);
 
 /* Identifie le canal de communication pour envois au serveur. */
-int g_hub_client_get_fd(GHubClient *);
+SSL *g_hub_client_get_ssl_fd(GHubClient *);
 
 /* Marque le canal de communication comme disponible. */
-void g_hub_client_put_fd(GHubClient *);
+void g_hub_client_put_ssl_fd(GHubClient *, SSL *);
 
 /* Effectue une demande de sauvegarde de l'état courant. */
 bool g_hub_client_save(GHubClient *);
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index 1dc299b..266b04c 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -266,12 +266,47 @@ static void g_db_bookmark_finalize(GDbBookmark *bookmark)
 GDbBookmark *g_db_bookmark_new(const vmpa2t *addr, const char *comment)
 {
     GDbBookmark *result;                    /* Instance à retourner        */
+    bool status;                            /* Bilan de l'initialisation   */
 
     result = g_object_new(G_TYPE_DB_BOOKMARK, NULL);
 
-    copy_vmpa(&result->addr, addr);
+    status = g_db_bookmark_fill(result, addr, comment);
+    if (!status) goto error;
 
-    g_db_bookmark_set_comment(result, comment);
+    return result;
+
+ error:
+
+    g_object_unref(G_OBJECT(result));
+
+    return NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : bookmark = signet à initialiser.                             *
+*                addr     = adresse inamovible localisant une position donnée.*
+*                comment  = commentaire construit ou NULL.                    *
+*                                                                             *
+*  Description : Initialise la définition d'un signet dans une zone de texte. *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_db_bookmark_fill(GDbBookmark *bookmark, const vmpa2t *addr, const char *comment)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    copy_vmpa(&bookmark->addr, addr);
+
+    dup_into_rle_string(&bookmark->comment, comment);
 
     return result;
 
@@ -601,26 +636,6 @@ const char *g_db_bookmark_get_comment(const GDbBookmark *bookmark)
 }
 
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : bookmark = informations à consulter.                         *
-*                comment  = commentaire construit ou NULL.                    *
-*                                                                             *
-*  Description : Définit le commentaire associé à un signet.                  *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_db_bookmark_set_comment(GDbBookmark *bookmark, const char *comment)
-{
-    dup_into_rle_string(&bookmark->comment, comment);
-
-}
-
-
 
 /* ---------------------------------------------------------------------------------- */
 /*                        DEFINITION DE LA COLLECTION ASSOCIEE                        */
diff --git a/src/analysis/db/items/bookmark.h b/src/analysis/db/items/bookmark.h
index a8526f7..47a7955 100644
--- a/src/analysis/db/items/bookmark.h
+++ b/src/analysis/db/items/bookmark.h
@@ -36,12 +36,12 @@
 /* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */
 
 
-#define G_TYPE_DB_BOOKMARK               g_db_bookmark_get_type()
-#define G_DB_BOOKMARK(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_db_bookmark_get_type(), GDbBookmark))
-#define G_IS_DB_BOOKMARK(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_db_bookmark_get_type()))
-#define G_DB_BOOKMARK_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_BOOKMARK, GDbBookmarkClass))
-#define G_IS_DB_BOOKMARK_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_BOOKMARK))
-#define G_DB_BOOKMARK_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_BOOKMARK, GDbBookmarkClass))
+#define G_TYPE_DB_BOOKMARK            g_db_bookmark_get_type()
+#define G_DB_BOOKMARK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DB_BOOKMARK, GDbBookmark))
+#define G_IS_DB_BOOKMARK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DB_BOOKMARK))
+#define G_DB_BOOKMARK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_BOOKMARK, GDbBookmarkClass))
+#define G_IS_DB_BOOKMARK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_BOOKMARK))
+#define G_DB_BOOKMARK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_BOOKMARK, GDbBookmarkClass))
 
 
 /* Signet à l'intérieur d'une zone de texte (instance) */
@@ -57,26 +57,26 @@ GType g_db_bookmark_get_type(void);
 /* Crée une définition d'un signet dans une zone de texte. */
 GDbBookmark *g_db_bookmark_new(const vmpa2t *, const char *);
 
+/* Initialise la définition d'un signet dans une zone de texte. */
+bool g_db_bookmark_fill(GDbBookmark *, const vmpa2t *, const char *);
+
 /* Fournit l'adresse associée à un signet. */
 const vmpa2t *g_db_bookmark_get_address(GDbBookmark *);
 
 /* Fournit le commentaire associé à un signet. */
 const char *g_db_bookmark_get_comment(const GDbBookmark *);
 
-/* Définit le commentaire associé à un signet. */
-void g_db_bookmark_set_comment(GDbBookmark *, const char *);
-
 
 
 /* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */
 
 
-#define G_TYPE_BM_COLLECTION               g_bookmark_collection_get_type()
-#define G_BM_COLLECTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_bookmark_collection_get_type(), GBookmarkCollection))
-#define G_IS_BM_COLLECTION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_bookmark_collection_get_type()))
-#define G_BM_COLLECTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BM_COLLECTION, GBookmarkCollectionClass))
-#define G_IS_BM_COLLECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BM_COLLECTION))
-#define G_BM_COLLECTION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BM_COLLECTION, GBookmarkCollectionClass))
+#define G_TYPE_BM_COLLECTION            g_bookmark_collection_get_type()
+#define G_BM_COLLECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BM_COLLECTION, GBookmarkCollection))
+#define G_IS_BM_COLLECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BM_COLLECTION))
+#define G_BM_COLLECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BM_COLLECTION, GBookmarkCollectionClass))
+#define G_IS_BM_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BM_COLLECTION))
+#define G_BM_COLLECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BM_COLLECTION, GBookmarkCollectionClass))
 
 
 /* Collection dédiée aux signets (instance) */
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index 1c03d62..5c3eed6 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -114,7 +114,28 @@ typedef enum _DBCommand
 {
     DBC_HELO,                               /* Connexion initiale C -> S   */
     DBC_WELCOME,                            /* Réponse initiale S -> C     */
+
+    /**
+     * Gestion de la commande 'DBC_SAVE'.
+     *
+     * Le client connecté envoie un paquet de la forme suivante :
+     *
+     *    [ Ordre de sauvegarde : DBC_SAVE            ]
+     *
+     * Le serveur s'exécute et renvoie un bilan :
+     *
+     *    [ 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 */
+
     DBC_COLLECTION,                         /* Implication d'une collection*/
 
     /**
@@ -131,6 +152,7 @@ typedef enum _DBCommand
      * De son côté, le serveur répond par une requête :
      *
      *    [ Notification de maj : DBC_SET_ALL_ITEMS     ]
+     *    [ marqueur de démarrage : octet 0x1           ]
      *
      * Dans la foulée, il enverra ensuite les éléments avec des paquets classiques :
      *
@@ -138,6 +160,11 @@ typedef enum _DBCommand
      *    [ Action : DBA_ADD_ITEM                       ]
      *    ...
      *
+     * La séquence se termine par une requête finale :
+     *
+     *    [ 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.
@@ -202,26 +229,6 @@ typedef enum _DBError
 
 
 
-/**
- * Gestion de la commande 'DBC_SAVE'.
- *
- * Le client connecté envoie un paquet de la forme suivante :
- *
- *    [ Ordre de sauvegarde : DBC_SAVE            ]
- *
- * Le serveur s'exécute et renvoie un bilan :
- *
- *    [ 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.
- *
- */
-
-
 
 
 
diff --git a/src/common/packed.c b/src/common/packed.c
index e06e4bb..163ed3b 100644
--- a/src/common/packed.c
+++ b/src/common/packed.c
@@ -30,6 +30,9 @@
 #include <string.h>
 
 
+#include "../core/logs.h"
+
+
 
 /* Taille d'allocation en cas de besoin */
 #define PACKET_BLOCK_SIZE 1000
@@ -124,6 +127,29 @@ size_t get_packed_buffer_payload_length(const packed_buffer *pbuf)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : pbuf = paquet de données à consulter.                        *
+*                                                                             *
+*  Description : Détermine si des données sont disponibles en lecture.        *
+*                                                                             *
+*  Retour      : true si des données peuvent être dépilées, false sinon.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool has_more_data_in_packed_buffer(const packed_buffer *pbuf)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = (pbuf->pos < pbuf->used);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : pbuf = paquet de données à compléter.                        *
 *                buf  = nouvelles données à ajouter.                          *
 *                len  = quantité de ces données.                              *
@@ -430,6 +456,7 @@ bool ssl_recv_packed_buffer(packed_buffer *pbuf, SSL *fd)
     int got;                                /* Quantité de données traitées*/
 
     got = SSL_read(fd, &used, sizeof(uint32_t));
+    if (got <= 0) LOG_ERROR_OPENSSL;
 
     result = (got == sizeof(uint32_t));
 
@@ -446,6 +473,7 @@ bool ssl_recv_packed_buffer(packed_buffer *pbuf, SSL *fd)
         pbuf->used = used;
 
         got = SSL_read(fd, pbuf->data + pbuf->pos, used);
+        if (got <= 0) LOG_ERROR_OPENSSL;
 
         result = (got == used);
 
@@ -480,6 +508,7 @@ bool ssl_send_packed_buffer(packed_buffer *pbuf, SSL *fd)
     quantity = sizeof(uint32_t) + pbuf->used;
 
     sent = SSL_write(fd, pbuf->data, quantity);
+    if (sent <= 0) LOG_ERROR_OPENSSL;
 
     result = (quantity == sent);
 
diff --git a/src/common/packed.h b/src/common/packed.h
index 5c724e0..4403ad0 100644
--- a/src/common/packed.h
+++ b/src/common/packed.h
@@ -59,6 +59,9 @@ void exit_packed_buffer(packed_buffer *);
 /* Indique le nombre d'octets de la charge utile d'un paquet. */
 size_t get_packed_buffer_payload_length(const packed_buffer *);
 
+/* Détermine si des données sont disponibles en lecture. */
+bool has_more_data_in_packed_buffer(const packed_buffer *);
+
 /* Ajoute des données à un paquet en amont à un envoi. */
 bool extend_packed_buffer(packed_buffer *, const void *, size_t, bool);
 
-- 
cgit v0.11.2-87-g4458