summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog42
-rw-r--r--src/Makefile.am2
-rw-r--r--src/analysis/binary.c46
-rw-r--r--src/analysis/binary.h8
-rwxr-xr-xsrc/analysis/db/Makefile.am1
-rw-r--r--src/analysis/db/cdb.c22
-rw-r--r--src/analysis/db/cdb.h5
-rw-r--r--src/analysis/db/client.c30
-rw-r--r--src/analysis/db/client.h3
-rw-r--r--src/analysis/db/collection.c429
-rw-r--r--src/analysis/db/collection.h26
-rw-r--r--src/analysis/db/core.c207
-rw-r--r--src/analysis/db/core.h70
-rw-r--r--src/analysis/db/item-int.h22
-rw-r--r--src/analysis/db/item.c260
-rw-r--r--src/analysis/db/item.h24
-rw-r--r--src/analysis/db/items/bookmark.c40
-rw-r--r--src/analysis/db/items/comment.c13
-rw-r--r--src/analysis/db/items/switcher.c22
-rwxr-xr-xsrc/analysis/db/misc/Makefile.am3
-rw-r--r--src/analysis/db/misc/timestamp.c263
-rw-r--r--src/analysis/db/misc/timestamp.h80
-rw-r--r--src/analysis/db/protocol.h33
-rw-r--r--src/gui/panels/bookmarks.c64
-rw-r--r--src/gui/panels/history.c335
25 files changed, 1577 insertions, 473 deletions
diff --git a/ChangeLog b/ChangeLog
index 5c8bbd4..02dc216 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+15-07-28 Cyrille Bagard <nocbos@gmail.com>
+
+ * src/analysis/binary.c:
+ * src/analysis/binary.h:
+ Provide a direct access to the connected client.
+
+ * src/analysis/db/cdb.c:
+ * src/analysis/db/cdb.h:
+ * src/analysis/db/client.c:
+ * src/analysis/db/client.h:
+ * src/analysis/db/collection.c:
+ * src/analysis/db/collection.h:
+ Begin to manage collection items as active or inactive using timestamps.
+
+ * src/analysis/db/core.c:
+ * src/analysis/db/core.h:
+ Deleted entries.
+
+ * src/analysis/db/item.c:
+ * src/analysis/db/item.h:
+ * src/analysis/db/item-int.h:
+ * src/analysis/db/items/bookmark.c:
+ * src/analysis/db/items/comment.c:
+ * src/analysis/db/items/switcher.c:
+ * src/analysis/db/Makefile.am:
+ Remove the 'core.[ch]' files from libanalysisdb_la_SOURCES.
+
+ * src/analysis/db/misc/Makefile.am:
+ Add the 'timestamp.[ch]' files to libanalysisdbmisc_la_SOURCES.
+
+ * src/analysis/db/misc/timestamp.c:
+ * src/analysis/db/misc/timestamp.h:
+ New entries: manage timestamps.
+
+ * src/analysis/db/protocol.h:
+ * src/gui/panels/bookmarks.c:
+ * src/gui/panels/history.c:
+ Begin to manage collection items as active or inactive using timestamps.
+
+ * src/Makefile.am:
+ Add the rt library to libchrysadisass_la_LDFLAGS.
+
15-07-25 Cyrille Bagard <nocbos@gmail.com>
* src/gtkext/easygtk.c:
diff --git a/src/Makefile.am b/src/Makefile.am
index e82ecfb..30772c9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -27,7 +27,7 @@ libchrysacore_la_LIBADD = \
libchrysadisass_la_SOURCES =
libchrysadisass_la_LDFLAGS = $(LIBGTK_LIBS) $(LIBXML_LIBS) \
- -Lcommon/.libs -lcommon -L.libs -lchrysaglibext
+ -Lcommon/.libs -lcommon -L.libs -lchrysaglibext -lrt
libchrysadisass_la_LIBADD = \
analysis/libanalysis.la \
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index ea18425..c6ae4e5 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -728,6 +728,50 @@ bool g_loaded_binary_connect(GLoadedBinary *binary)
/******************************************************************************
* *
+* Paramètres : binary = élément binaire à consulter. *
+* *
+* Description : Fournit le client assurant la liaison avec un serveur. *
+* *
+* Retour : Client connecté ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GDbClient *g_loaded_binary_get_db_client(const GLoadedBinary *binary)
+{
+ GDbClient *result; /* Instance à retourner */
+
+ result = binary->local;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : binary = élément binaire à consulter. *
+* *
+* Description : Fournit l'ensemble des collections utilisées par un binaire. *
+* *
+* Retour : Collections en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GList *g_loaded_binary_get_all_collections(const GLoadedBinary *binary)
+{
+ return binary->collections;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : binary = élément binaire à consulter. *
* feature = fonctionnalité assurée par la collection visée. *
* *
@@ -739,7 +783,7 @@ bool g_loaded_binary_connect(GLoadedBinary *binary)
* *
******************************************************************************/
-GDbCollection *g_loaded_binary_find_collection(GLoadedBinary *binary, DBFeatures feature)
+GDbCollection *g_loaded_binary_find_collection(const GLoadedBinary *binary, DBFeatures feature)
{
GDbCollection *result; /* Collection à retourner */
diff --git a/src/analysis/binary.h b/src/analysis/binary.h
index b67881c..fb37310 100644
--- a/src/analysis/binary.h
+++ b/src/analysis/binary.h
@@ -29,7 +29,7 @@
#include <stdbool.h>
#include "db/collection.h"
-#include "db/item.h"
+#include "db/client.h"
#include "db/protocol.h"
#include "../arch/processor.h"
#include "../common/xml.h"
@@ -115,10 +115,14 @@ bool g_loaded_binary_connect(GLoadedBinary *);
/* -------------------------- MANIPULATION DES COLLECTIONS -------------------------- */
+/* Fournit le client assurant la liaison avec un serveur. */
+GDbClient *g_loaded_binary_get_db_client(const GLoadedBinary *);
+/* Fournit l'ensemble des collections utilisées par un binaire. */
+GList *g_loaded_binary_get_all_collections(const GLoadedBinary *);
/* Trouve une collection assurant une fonctionnalité donnée. */
-GDbCollection *g_loaded_binary_find_collection(GLoadedBinary *, DBFeatures);
+GDbCollection *g_loaded_binary_find_collection(const GLoadedBinary *, DBFeatures);
/* Demande l'intégration d'une modification dans une collection. */
bool _g_loaded_binary_add_to_collection(GLoadedBinary *, DBFeatures, GDbItem *, bool);
diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am
index 2e8e0f1..797025c 100755
--- a/src/analysis/db/Makefile.am
+++ b/src/analysis/db/Makefile.am
@@ -6,7 +6,6 @@ libanalysisdb_la_SOURCES = \
client.h client.c \
collection-int.h \
collection.h collection.c \
- core.h core.c \
item-int.h \
item.h item.c \
protocol.h \
diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index 96e69d5..70e0dc5 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -140,8 +140,9 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *);
/* ------------------------- ACCES A LA BASE DE DONNEES SQL ------------------------- */
+
/* Crée la base de données correspondant à l'archive. */
-static bool g_cdb_archive_create_db(const GCdbArchive *, const core_db_info *);
+static bool g_cdb_archive_create_db(const GCdbArchive *);
@@ -333,7 +334,7 @@ GCdbArchive *g_cdb_archive_new(const char *owner, const rle_string *hash, const
if (errno != ENOENT) goto gcan_error;
g_cdb_archive_create_xml_desc(result, user);
- g_cdb_archive_create_db(result, NULL);
+ g_cdb_archive_create_db(result);
*error = g_cdb_archive_write(result);
@@ -623,7 +624,8 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has
static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string *user)
{
bool result; /* Bilan à retourner */
- char tmp[sizeof(XSTR(UINT32_MAX))]; /* Stockage temporaire */
+ timestamp_t timestamp; /* Date de création */
+ char tmp[sizeof(XSTR(UINT64_MAX))]; /* Stockage temporaire */
result = create_new_xml_file(&archive->xdoc, &archive->context);
if (!result) return false;
@@ -640,7 +642,8 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string
result &= add_content_to_node(archive->xdoc, archive->context,
"/ChrysalideBinary/Creation/Author", user->data);
- snprintf(tmp, sizeof(tmp), "%" PRIu64, (uint64_t)time(NULL));
+ init_timestamp(&timestamp);
+ snprintf(tmp, sizeof(tmp), "%" PRIu64, timestamp);
result &= add_content_to_node(archive->xdoc, archive->context,
"/ChrysalideBinary/Creation/Date", tmp);
@@ -694,7 +697,6 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive)
/******************************************************************************
* *
* Paramètres : archive = archive à constituer. *
-* info = informations de base associées à la requête. *
* *
* Description : Crée la base de données correspondant à l'archive. *
* *
@@ -704,7 +706,7 @@ static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive)
* *
******************************************************************************/
-static bool g_cdb_archive_create_db(const GCdbArchive *archive, const core_db_info *info)
+static bool g_cdb_archive_create_db(const GCdbArchive *archive)
{
bool result; /* Bilan à retourner */
sqlite3 *db; /* Base de données à constituer*/
@@ -728,7 +730,6 @@ static bool g_cdb_archive_create_db(const GCdbArchive *archive, const core_db_in
{
collec = G_DB_COLLECTION(iter->data);
result = g_db_collection_create_db_table(collec, db);
- fprintf(stderr, "STATUS :: %d\n", result);
}
sqlite3_close(db);
@@ -953,6 +954,13 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
break;
+ case DBC_SET_LAST_ACTIVE:
+
+ status = update_activity_in_collections(archive->collections, fds[i].fd, archive->db);
+ if (!status) goto gcap_bad_exchange;
+
+ break;
+
default:
printf("bad command :: 0x%08x\n", command);
goto gcap_bad_exchange;
diff --git a/src/analysis/db/cdb.h b/src/analysis/db/cdb.h
index e9abb02..d6b03fb 100644
--- a/src/analysis/db/cdb.h
+++ b/src/analysis/db/cdb.h
@@ -32,11 +32,6 @@
#include "protocol.h"
#include "misc/rlestr.h"
-//////
-#include "client.h"
-#include "core.h"
-//////////
-
#define G_TYPE_CDB_ARCHIVE g_cdb_archive_get_type()
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index f0d3d4b..2a5a185 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -525,3 +525,33 @@ bool g_db_client_save(GDbClient *client)
return result;
}
+
+
+/******************************************************************************
+* *
+* Paramètres : client = client pour les accès distants à manipuler. *
+* timestamp = date du dernier élément à garder comme actif. *
+* *
+* Description : Active les éléments en amont d'un horodatage donné. *
+* *
+* Retour : true si la commande a bien été envoyée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_db_client_set_last_active(GDbClient *client, timestamp_t timestamp)
+{
+ bool result; /* Bilan partiel à remonter */
+
+ g_db_client_get_fd(client);
+
+ result = safe_send(client->fd, (uint32_t []) { htobe32(DBC_SET_LAST_ACTIVE) }, sizeof(uint32_t), 0);
+
+ result &= send_timestamp(&timestamp, client->fd, MSG_MORE);
+
+ g_db_client_put_fd(client);
+
+ return result;
+
+}
diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h
index 6e9f10b..0304786 100644
--- a/src/analysis/db/client.h
+++ b/src/analysis/db/client.h
@@ -68,6 +68,9 @@ void g_db_client_put_fd(GDbClient *);
/* Effectue une demande de sauvegarde de l'état courant. */
bool g_db_client_save(GDbClient *);
+/* Active les éléments en amont d'un horodatage donné. */
+bool g_db_client_set_last_active(GDbClient *, timestamp_t);
+
#endif /* _ANALYSIS_DB_CLIENT_H */
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index c3b9f2c..91f9872 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -68,6 +68,8 @@ static bool g_db_collection_setup_load(GDbCollection *, bound_value **, size_t *
/* Enregistre un élément de collection dans une base de données. */
static bool g_db_collection_store_item(const GDbCollection *, const GDbItem *, sqlite3 *);
+/* Met à jour un élément de collection dans une base de données. */
+static bool g_db_collection_store_updated_item(const GDbCollection *, const GDbItem *, sqlite3 *);
@@ -285,6 +287,9 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
item = g_object_new(collec->type, NULL);
+ if (db != NULL)
+ g_db_item_set_server_side(item);
+
status = g_db_item_recv(item, fd, 0);
if (!status) return false;
@@ -312,8 +317,13 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
case DBA_REM_ITEM:
break;
- case DBA_MOD_ITEM:
- result = g_db_collection_modify_item(collec, item);
+ case DBA_CHANGE_STATE:
+
+ if (db == NULL)
+ result = g_db_collection_update_item_activity(collec, item);
+ else
+ result = false;
+
break;
default:
@@ -322,6 +332,8 @@ bool g_db_collection_recv(GDbCollection *collec, int fd, sqlite3 *db)
}
+ g_object_unref(G_OBJECT(item));
+
return result;
}
@@ -511,7 +523,7 @@ bool g_db_collection_has_item(GDbCollection *collec, GDbItem *item)
printf(" --- has\n");
- found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare);
+ found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_with_timestamp);
printf(" --- has: %p\n", found);
@@ -539,33 +551,23 @@ bool g_db_collection_has_item(GDbCollection *collec, GDbItem *item)
bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
{
bool result; /* Bilan à faire remonter */
- GList *found; /* Test de présence existante */
+
+ result = true;
if (lock)
g_db_collection_wlock(collec);
- found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare);
-
- if (found != NULL)
- result = g_db_collection_modify_item(collec, item);
-
- else
- {
- g_object_ref(G_OBJECT(item));
- collec->items = g_list_append(collec->items, item);
-
- g_object_ref(G_OBJECT(item));
- collec->sorted = g_list_insert_sorted(collec->sorted, item, (GCompareFunc)g_db_item_compare);
+ g_object_ref(G_OBJECT(item));
+ collec->items = g_list_append(collec->items, item);
- g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item);
+ g_object_ref(G_OBJECT(item));
+ collec->sorted = g_list_insert_sorted(collec->sorted, item, (GCompareFunc)g_db_item_compare_with_timestamp);
+ g_signal_emit_by_name(collec, "content-changed", DBA_ADD_ITEM, item);
- printf(" ==== CONTENT CHANGED (-> %u) !!!\n", g_list_length(collec->items));
+ printf(" ==== CONTENT CHANGED (-> %u) !!!\n", g_list_length(collec->items));
- result = true;
-
- }
if (lock)
g_db_collection_wunlock(collec);
@@ -578,10 +580,10 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
/******************************************************************************
* *
* Paramètres : collec = ensemble d'éléments à considérer. *
-* item = élément de collection à copier. *
+* item = élément de collection à manipuler. *
* lock = indique si le verrou d'écriture doit être posé. *
* *
-* Description : Procède à la modification d'un élément dans la collection. *
+* Description : Met à jour le statut d'activité d'un élément de collection. *
* *
* Retour : Bilan de l'exécution de l'opération. *
* *
@@ -589,26 +591,127 @@ bool _g_db_collection_add_item(GDbCollection *collec, GDbItem *item, bool lock)
* *
******************************************************************************/
-bool _g_db_collection_modify_item(GDbCollection *collec, GDbItem *item, bool lock)
+bool _g_db_collection_update_item_activity(GDbCollection *collec, GDbItem *item, bool lock)
{
bool result; /* Bilan à faire remonter */
GList *found; /* Test de présence existante */
+ GDbItem *internal; /* Elément interne à modifier */
- found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare);
+ if (lock)
+ g_db_collection_wlock(collec);
+ found = g_list_find_custom(collec->items, item, (GCompareFunc)g_db_item_compare_without_timestamp);
+ result = (found != NULL);
- result = true;
+ if (result)
+ {
+ internal = G_DB_ITEM(found->data);
+
+ g_db_item_set_activity(internal, (timestamp_t []) { g_db_item_get_timestamp(item) + 1 });
+
+ g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, internal);
+
+ }
+
+ if (lock)
+ g_db_collection_wunlock(collec);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = ensemble d'éléments à considérer. *
+* timestamp = date du dernier élément à garder comme actif. *
+* inactive = date du premier élément inactif rencontré. [OUT] *
+* db = base de données à mettre à jour. *
+* *
+* Description : Active les éléments en amont d'un horodatage donné. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GList *g_db_collection_set_last_active(GDbCollection *collec, timestamp_t timestamp, timestamp_t *inactive, sqlite3 *db)
+{
+ GList *result; /* Liste d'inactifs à renvoyer */
+ GList *i; /* Parcours des éléments */
+ GDbItem *item; /* Elément à traiter */
+ timestamp_t stamp; /* Horodatage de l'élément */
+ result = NULL;
+ for (i = g_list_first(collec->items); i != NULL; i = g_list_next(i))
+ {
+ item = G_DB_ITEM(i->data);
+ stamp = g_db_item_get_timestamp(item);
+ if (timestamp_is_younger(stamp, timestamp))
+ {
+ if (!g_db_item_is_active(item))
+ {
+ g_db_item_set_activity(item, NULL);
+ /* ... */g_db_collection_store_updated_item(collec, item, db);
+ g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
+ }
+ }
+
+ else
+ {
+ if (!g_db_item_is_active(item))
+ {
+ if (timestamp_is_younger(stamp, *inactive))
+ *inactive = stamp;
+ }
+
+ else
+ result = g_list_append(result, item);
+
+ }
+
+ }
return result;
}
+/******************************************************************************
+* *
+* Paramètres : collec = ensemble d'éléments à considérer. *
+* item = élément à désactiver. *
+* timestamp = date du premier élément inactif rencontré. [OUT] *
+* *
+* Description : Désactive les éléments en aval d'un horodatage donné. *
+* *
+* Retour : true si l'élément a été traité, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_db_collection_set_inactive(GDbCollection *collec, GDbItem *item, timestamp_t *timestamp)
+{
+ /* Si cette collection n'est pas concernée, on ne bouge pas ! */
+ if (G_OBJECT_TYPE(G_OBJECT(item)) != collec->type) return false;
+
+ assert(g_db_item_is_active(item));
+
+ g_db_item_set_activity(item, timestamp);
+
+ g_signal_emit_by_name(collec, "content-changed", DBA_CHANGE_STATE, item);
+
+ return true;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* MANIPULATIONS AVEC UNE BASE DE DONNEES */
@@ -630,8 +733,6 @@ bool _g_db_collection_modify_item(GDbCollection *collec, GDbItem *item, bool loc
bool g_db_collection_create_db_table(const GDbCollection *collec, sqlite3 *db)
{
- fprintf(stderr, "CREATE '%s'\n", collec->name);
-
return G_DB_COLLECTION_GET_CLASS(collec)->create_table(collec, db);
}
@@ -653,12 +754,11 @@ bool g_db_collection_create_db_table(const GDbCollection *collec, sqlite3 *db)
static bool _g_db_collection_setup_load(GDbCollection *collec, bound_value **values, size_t *count)
{
- *count += 2;
- *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
-
- (*values)[*count - 2].name = "created";
+ if (!setup_load_of_timestamp(NULL, "created", values, count))
+ return false;
- (*values)[*count - 1].name = "modified";
+ if (!setup_load_of_timestamp(NULL, "timestamp", values, count))
+ return false;
if (!setup_load_of_rle_string(NULL, "author", values, count))
return false;
@@ -666,9 +766,6 @@ static bool _g_db_collection_setup_load(GDbCollection *collec, bound_value **val
if (!setup_load_of_rle_string(NULL, "tool", values, count))
return false;
- if (!setup_load_of_rle_string(NULL, "label", values, count))
- return false;
-
return true;
}
@@ -796,6 +893,8 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db)
new = g_object_new(G_DB_COLLECTION(collec)->type, NULL);
+ g_db_item_set_server_side(new);
+
result = g_db_item_load(new, values, count);
result &= g_db_collection_add_item(G_DB_COLLECTION(collec), new);
@@ -931,13 +1030,157 @@ static bool g_db_collection_store_item(const GDbCollection *collec, const GDbIte
free(sql);
- printf("INSERT ? %d\n", result);
-
return result;
}
+/******************************************************************************
+* *
+* Paramètres : collec = ensemble d'éléments à considérer. *
+* item = élément de collection à enregistrer. *
+* db = base de données à mettre à jour. *
+* *
+* Description : Met à jour un élément de collection dans une base de données.*
+* *
+* Retour : Bilan de l'exécution de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_db_collection_store_updated_item(const GDbCollection *collec, const GDbItem *item, sqlite3 *db)
+{
+ bool result; /* Conclusion à faire remonter */
+ bound_value *values; /* Champs de table à inclure */
+ size_t count; /* Nombre de ces champs */
+ char *sql; /* Requête SQL à construire */
+ bool first; /* Première valeur ? */
+ size_t i; /* Boucle de parcours */
+ sqlite3_stmt *stmt; /* Déclaration mise en place */
+ int ret; /* Bilan d'un appel à SQLite */
+ int index; /* Indice de valeur attachée */
+ const bound_value *timestamp; /* Valeur de l'horodatage */
+
+ if (!g_db_item_prepare_db_statement(item, &values, &count))
+ return false;
+
+ result = false;
+
+ /* Préparation de la requête */
+
+ sql = strdup("UPDATE ");
+ sql = stradd(sql, collec->name);
+
+ sql = stradd(sql, " SET timestamp = ? ");
+
+ sql = stradd(sql, "WHERE ");
+
+ first = true;
+
+ for (i = 0; i < count; i++)
+ {
+ if (strcmp(values[i].name, "timestamp") == 0)
+ continue;
+
+ if (first)
+ first = false;
+ else
+ sql = stradd(sql, " AND ");
+
+ sql = stradd(sql, values[i].name);
+
+ sql = stradd(sql, " = ");
+
+ if (values[i].type == SQLITE_RAW)
+ sql = stradd(sql, values[i].cstring);
+ else
+ sql = stradd(sql, "?");
+
+ }
+
+ sql = stradd(sql, ";");
+
+ fprintf(stderr, "UPDATE SQL '%s'\n", sql);
+
+ ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ if (ret != SQLITE_OK)
+ {
+ fprintf(stderr, "Can't prepare INSERT statment '%s' (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ /* Attribution des valeurs */
+
+ index = 1;
+
+ timestamp = find_bound_value(values, count, "timestamp");
+ assert(timestamp->type == SQLITE_INT64);
+
+ ret = sqlite3_bind_int64(stmt, index, values[i].integer64);
+ index++;
+
+ if (ret != SQLITE_OK)
+ {
+ fprintf(stderr, "Can't bind value for parameter nb %d in '%s' (ret=%d): %s\n",
+ index - 1, sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (strcmp(values[i].name, "timestamp") == 0)
+ continue;
+
+ switch (values[i].type)
+ {
+ case SQLITE_INT64:
+ ret = sqlite3_bind_int64(stmt, index, values[i].integer64);
+ index++;
+ break;
+
+ case SQLITE_TEXT:
+ ret = sqlite3_bind_text(stmt, index, values[i].string, -1, values[i].delete);
+ index++;
+ break;
+
+ default:
+ ret = SQLITE_OK;
+ break;
+
+ }
+
+ if (ret != SQLITE_OK)
+ {
+ fprintf(stderr, "Can't bind value for parameter nb %d in '%s' (ret=%d): %s\n",
+ index - 1, sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ }
+
+ /* Exécution finale */
+
+ ret = sqlite3_step(stmt);
+
+ if (ret != SQLITE_DONE)
+ {
+ fprintf(stderr, "UPDATE statement '%s' didn't return DONE (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
+ goto gdcsi_exit;
+ }
+
+ sqlite3_finalize(stmt);
+
+ result = true;
+
+ gdcsi_exit:
+
+ free(sql);
+
+ return result;
+
+}
+
/* ---------------------------------------------------------------------------------- */
@@ -1007,3 +1250,113 @@ GDbCollection *find_collection_in_list(GList *list, uint32_t id)
return (iter != NULL ? result : NULL);
}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de collectons à parcourir. *
+* write = précise le type d'accès prévu (lecture/écriture). *
+* lock = indique le sens du verrouillage à mener. *
+* *
+* Description : Met à disposition un encadrement des accès aux éléments. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void lock_unlock_collections(GList *list, bool write, bool lock)
+{
+ GList *iter; /* Boucle de parcours */
+
+ for (iter = g_list_first(list);
+ iter != NULL;
+ iter = g_list_next(iter))
+ {
+ g_db_collection_lock_unlock(G_DB_COLLECTION(iter->data), write, lock);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : list = ensemble de collectons à traiter. *
+* fd = canal de communication ouvert en lecture. *
+* db = base de données à mettre à jour. *
+* *
+* Description : Met à jour les statuts d'activité des éléments. *
+* *
+* Retour : Bilan du déroulement des opérations. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool update_activity_in_collections(GList *list, int fd, sqlite3 *db)
+{
+ bool result; /* Résultat global à renvoyer */
+ bool status; /* Bilan de lecture initiale */
+ timestamp_t timestamp; /* Horodatage de limite */
+ timestamp_t inactive; /* Date du premier inactif */
+ GList *remaining; /* Eléments restants à traiter */
+ GList *c; /* Boucle de parcours #1 */
+ GDbCollection *collec; /* Collection à manipuler */
+ GList *got; /* Eléments restants à traiter */
+ GList *i; /* Boucle de parcours #2 */
+ GDbItem *item; /* Elément collecté à manipuler*/
+
+ status = recv_timestamp(&timestamp, fd, 0);
+ if (!status) return false;
+
+ inactive = TIMESTAMP_ALL_ACTIVE;
+
+ remaining = NULL;
+
+ wlock_collections(list);
+
+ for (c = g_list_first(list); c != NULL; c = g_list_next(c))
+ {
+ collec = G_DB_COLLECTION(c->data);
+
+ got = g_db_collection_set_last_active(collec, timestamp, &inactive, db);
+ remaining = g_list_concat(remaining, got);
+
+ }
+
+ gint sort_with_timestamp(GDbItem *a, GDbItem *b)
+ {
+ return g_db_item_cmp(a, b, false);
+ }
+
+ remaining = g_list_sort(remaining, (GCompareFunc)sort_with_timestamp);
+
+ result = true;
+
+ for (i = g_list_last(remaining); i != NULL && result; i = g_list_previous(i))
+ {
+ item = G_DB_ITEM(i->data);
+
+ for (c = g_list_first(list); c != NULL && result; c = g_list_next(c))
+ {
+ collec = G_DB_COLLECTION(c->data);
+
+ if (g_db_collection_set_inactive(collec, item, &inactive))
+ {
+ result = g_db_collection_store_updated_item(collec, item, db);
+ break;
+ }
+
+ }
+
+ }
+
+ wunlock_collections(list);
+
+ g_list_free(remaining);
+
+ return result;
+
+}
diff --git a/src/analysis/db/collection.h b/src/analysis/db/collection.h
index e550009..ac3e60f 100644
--- a/src/analysis/db/collection.h
+++ b/src/analysis/db/collection.h
@@ -84,14 +84,12 @@ bool g_db_collection_send_all_updates(GDbCollection *, int);
/* Met à disposition un encadrement des accès aux éléments. */
void g_db_collection_lock_unlock(GDbCollection *, bool, bool);
-
#define g_db_collection_wlock(col) g_db_collection_lock_unlock(col, true, true);
#define g_db_collection_wunlock(col) g_db_collection_lock_unlock(col, true, false);
#define g_db_collection_rlock(col) g_db_collection_lock_unlock(col, false, true);
#define g_db_collection_runlock(col) g_db_collection_lock_unlock(col, false, false);
-
/* Renvoie la liste des éléments rassemblés. */
GList *g_db_collection_list_items(const GDbCollection *);
@@ -104,11 +102,17 @@ bool g_db_collection_has_item(GDbCollection *, GDbItem *);
/* Procède à l'ajout d'un nouvel élément dans la collection. */
bool _g_db_collection_add_item(GDbCollection *, GDbItem *, bool);
-/* Procède à la modification d'un élément dans la collection. */
-bool _g_db_collection_modify_item(GDbCollection *, GDbItem *, bool);
+/* Met à jour le statut d'activité d'un élément de collection. */
+bool _g_db_collection_update_item_activity(GDbCollection *, GDbItem *, bool);
#define g_db_collection_add_item(c, i) _g_db_collection_add_item(c, i, true)
-#define g_db_collection_modify_item(c, i) _g_db_collection_modify_item(c, i, true)
+#define g_db_collection_update_item_activity(c, i) _g_db_collection_update_item_activity(c, i, true)
+
+/* Active les éléments en amont d'un horodatage donné. */
+GList *g_db_collection_set_last_active(GDbCollection *, timestamp_t, timestamp_t *, sqlite3 *);
+
+/* Désactive les éléments en aval d'un horodatage donné. */
+bool g_db_collection_set_inactive(GDbCollection *, GDbItem *, timestamp_t *);
@@ -132,6 +136,18 @@ void attach_binary_to_collections(GList *, GLoadedBinary *);
/* Recherche une collection correspondant à un type donné. */
GDbCollection *find_collection_in_list(GList *, uint32_t);
+/* Met à disposition un encadrement des accès aux éléments. */
+void lock_unlock_collections(GList *, bool, bool);
+
+#define wlock_collections(lst) lock_unlock_collections(lst, true, true);
+#define wunlock_collections(lst) lock_unlock_collections(lst, true, false);
+
+#define rlock_collections(lst) lock_unlock_collections(lst, false, true);
+#define runlock_collections(lst) lock_unlock_collections(lst, false, false);
+
+/* Met à jour les statuts d'activité des éléments. */
+bool update_activity_in_collections(GList *, int, sqlite3 *);
+
#endif /* _ANALYSIS_DB_COLLECTION_H */
diff --git a/src/analysis/db/core.c b/src/analysis/db/core.c
deleted file mode 100644
index 81ea117..0000000
--- a/src/analysis/db/core.c
+++ /dev/null
@@ -1,207 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * core.c - prototypes pour les informations de base pour tout élément ajouté
- *
- * Copyright (C) 2014 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * OpenIDA 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.
- *
- * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "core.h"
-
-
-#include <endian.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-
-#include "../../common/io.h"
-
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Détermine une fois pour toute la désignation de l'usager. *
-* *
-* Retour : Nom statique déterminé. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-const char *get_local_author_name(void)
-{
- static char result[MAX_DB_AUTHOR_LEN]; /* Désignation à retourner */
- char *chrysalide_user; /* Eventuel nom spécifique */
- char *logname; /* Nom depuis l'environnement */
- char hostname[HOST_NAME_MAX]; /* Nom de la machine courante */
- int ret; /* Bilan d'un appel */
-
- if (result[0] == '\0')
- {
- chrysalide_user = getenv("CHRYSALIDE_USER");
-
- if (chrysalide_user != NULL)
- {
- strncpy(result, chrysalide_user, MAX_DB_AUTHOR_LEN - 1);
- result[MAX_DB_AUTHOR_LEN - 1] = '\0';
- }
- else
- {
- logname = getenv("LOGNAME");
- if (logname == NULL)
- logname = "";
-
- ret = gethostname(hostname, HOST_NAME_MAX);
- if (ret != 0)
- hostname[0] = '\0';
-
- if (logname != NULL && hostname[0] != '\0')
- snprintf(result, MAX_DB_AUTHOR_LEN, "%s@%s", logname, hostname);
-
- else if (logname != NULL && hostname[0] == '\0')
- snprintf(result, MAX_DB_AUTHOR_LEN, "%s", logname);
-
- else if (logname == NULL && hostname[0] != '\0')
- snprintf(result, MAX_DB_AUTHOR_LEN, "@%s", hostname);
-
- else
- snprintf(result, MAX_DB_AUTHOR_LEN, "anonymous");
-
- }
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : info = informations à constituer. [OUT] *
-* type = type de l'élément à mettre en place. *
-* user = provenance des informations ou NULL si machine. *
-* *
-* Description : Initialise le coeur des informations d'un élément ajouté. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void init_core_db_info(core_db_info *info, uint64_t type, const char *user)
-{
- info->type = type;
-
- strncpy(info->user, user, MAX_DB_AUTHOR_LEN - 1);
- info->user[MAX_DB_AUTHOR_LEN - 1] = '\0';
-
- info->created = time(NULL);
- info->modified = info->created;
-
- info->saved = 0;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : info = informations à constituer. [OUT] *
-* type = type de l'élément, lu en avance de phase. *
-* fd = flux ouvert en lecture pour l'importation. *
-* *
-* Description : Importe le coeur des informations d'un élément ajouté. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool load_core_db_info(core_db_info *info, uint64_t type, int fd)
-{
-#if 0
- ssize_t got; /* Quantité de données reçues */
- uint64_t val64; /* Valeur sur 64 bits */
-
- info->type = type;
-
- got = safe_recv(fd, info->user, MAX_DB_AUTHOR_LEN, MSG_WAITALL);
- if (got != MAX_DB_AUTHOR_LEN) return false;
-
- info->user[MAX_DB_AUTHOR_LEN - 1] = '\0';
-
- got = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL);
- if (got != sizeof(uint64_t)) return false;
-
- info->created = be64toh(val64);
-
- got = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL);
- if (got != sizeof(uint64_t)) return false;
-
- info->modified = be64toh(val64);
-
- info->saved = info->modified;
-#endif
- return true;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : info = informations à sauvegarer. *
-* fd = flux ouvert en écriture pour l'exportation. *
-* *
-* Description : Exporte le coeur des informations d'un élément ajouté. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool store_core_db_info(core_db_info *info, int fd)
-{
-#if 0
- ssize_t got; /* Quantité de données reçues */
-
- got = safe_send(fd, (uint64_t []) { htobe64(info->type) }, sizeof(uint64_t), MSG_WAITALL);
- if (got != sizeof(uint64_t)) return false;
-
- got = safe_send(fd, info->user, MAX_DB_AUTHOR_LEN, MSG_WAITALL);
- if (got != MAX_DB_AUTHOR_LEN) return false;
-
- got = safe_send(fd, (uint64_t []) { htobe64(info->created) }, sizeof(uint64_t), MSG_WAITALL);
- if (got != sizeof(uint64_t)) return false;
-
- got = safe_send(fd, (uint64_t []) { htobe64(info->modified) }, sizeof(uint64_t), MSG_WAITALL);
- if (got != sizeof(uint64_t)) return false;
-
- info->saved = time(NULL);
-#endif
- return true;
-
-}
diff --git a/src/analysis/db/core.h b/src/analysis/db/core.h
deleted file mode 100644
index b53b250..0000000
--- a/src/analysis/db/core.h
+++ /dev/null
@@ -1,70 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * core.h - prototypes pour les informations de base pour tout élément ajouté
- *
- * Copyright (C) 2014 Cyrille Bagard
- *
- * This file is part of Chrysalide.
- *
- * OpenIDA 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.
- *
- * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef _ANALYSIS_DB_CORE_H
-#define _ANALYSIS_DB_CORE_H
-
-
-#include <inttypes.h>
-#include <stdbool.h>
-
-
-
-/**
- * Taille maximale pour un nom d'auteur.
- * On considère comme exemple large '"Nom Prénom" xxx@yyy.tld'
- */
-#define MAX_DB_AUTHOR_LEN 128
-
-
-/* Informations de base pour tout élément ajouté */
-typedef struct _core_db_info
-{
- uint64_t type; /* Type de l'élément */
- char hash[65]; /* Empreinte SHA256 */
-
- char user[MAX_DB_AUTHOR_LEN]; /* Auteur humain ou NULL */
-
- uint64_t created; /* Date de création */
- uint64_t modified; /* Date de modification */
-
- uint64_t saved; /* Statut de l'élément */
-
-} core_db_info;
-
-
-/* Détermine une fois pour toute la désignation de l'usager. */
-const char *get_local_author_name(void);
-
-/* Initialise le coeur des informations d'un élément ajouté. */
-void init_core_db_info(core_db_info *, uint64_t, const char *);
-
-/* Importe le coeur des informations d'un élément ajouté. */
-bool load_core_db_info(core_db_info *, uint64_t, int);
-
-/* Exporte le coeur des informations d'un élément ajouté. */
-bool store_core_db_info(core_db_info *, int);
-
-
-
-#endif /* _ANALYSIS_DB_CORE_H */
diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h
index 12c69f3..1af1048 100644
--- a/src/analysis/db/item-int.h
+++ b/src/analysis/db/item-int.h
@@ -36,12 +36,18 @@
+/* Effectue la comparaison entre deux éléments de collection. */
+typedef gint (* cmp_db_item_fc) (GDbItem *, GDbItem *, bool);
+
/* Importe la définition d'une base d'éléments pour collection. */
typedef bool (* recv_db_item_fc) (GDbItem *, int, int);
/* Exporte la définition d'une base d'éléments pour collection. */
typedef bool (* send_db_item_fc) (const GDbItem *, int, int);
+/* Construit la description humaine d'un signet sur un tampon. */
+typedef void (* build_item_label_fc) (GDbItem *);
+
/* Exécute un élément de collection sur un binaire. */
typedef bool (* run_item_fc) (GDbItem *, GLoadedBinary *);
@@ -57,13 +63,15 @@ struct _GDbItem
{
GObject parent; /* A laisser en premier */
- uint64_t created; /* Date de création */
- uint64_t modified; /* Date de modification */
+ bool server_side; /* Instance côté serveur */
+
+ timestamp_t created; /* Date de création */
+ timestamp_t timestamp; /* Date dernière activité */
rle_string author; /* Utilisateur d'origine */
rle_string tool; /* Eventuel outil automatique ?*/
- rle_string label; /* Représentation humaine */
+ char *label; /* Représentation humaine */
bool is_volatile; /* Pas besoin de sauvegarde ? */
@@ -78,10 +86,12 @@ struct _GDbItemClass
{
GObjectClass parent; /* A laisser en premier */
- GCompareFunc cmp; /* Comparaison entre éléments */
+ cmp_db_item_fc cmp; /* Comparaison entre éléments */
recv_db_item_fc recv; /* Réception depuis le réseau */
send_db_item_fc send; /* Emission depuis le réseau */
+
+ build_item_label_fc build_label; /* Construction de description */
run_item_fc apply; /* Application de l'élément */
run_item_fc cancel; /* Retrait de l'élément */
@@ -93,8 +103,8 @@ struct _GDbItemClass
/* Définition du tronc commun pour les créations SQLite */
#define SQLITE_DB_ITEM_CREATE \
- "created INTEGER, " \
- "modified INTEGER, " \
+ SQLITE_TIMESTAMP_CREATE("created") ", " \
+ SQLITE_TIMESTAMP_CREATE("timestamp") ", " \
SQLITE_RLESTR_CREATE("author") ", " \
SQLITE_RLESTR_CREATE("tool") ", " \
SQLITE_RLESTR_CREATE("label")
diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c
index d2f87c3..5463e85 100644
--- a/src/analysis/db/item.c
+++ b/src/analysis/db/item.c
@@ -26,6 +26,7 @@
#include <assert.h>
#include <malloc.h>
+#include <string.h>
#include <sqlite3.h>
@@ -47,9 +48,6 @@ static void g_db_item_dispose(GDbItem *);
/* Procède à la libération totale de la mémoire. */
static void g_db_item_finalize(GDbItem *);
-/* Effectue la comparaison entre deux éléments de collection. */
-static gint g_db_item_cmp(GDbItem *, GDbItem *);
-
/* Importe la définition d'une base d'éléments pour collection. */
static bool g_db_item_recv_from_fd(GDbItem *, int, int);
@@ -94,7 +92,7 @@ static void g_db_item_class_init(GDbItemClass *klass)
object->dispose = (GObjectFinalizeFunc/* ! */)g_db_item_dispose;
object->finalize = (GObjectFinalizeFunc)g_db_item_finalize;
- klass->cmp = (GCompareFunc)g_db_item_cmp;
+ klass->cmp = (cmp_db_item_fc)g_db_item_cmp;
klass->recv = (recv_db_item_fc)g_db_item_recv_from_fd;
klass->send = (send_db_item_fc)g_db_item_send_to_fd;
@@ -165,6 +163,12 @@ static void g_db_item_dispose(GDbItem *item)
static void g_db_item_finalize(GDbItem *item)
{
+ exit_rle_string(&item->author);
+ exit_rle_string(&item->tool);
+
+ if (item->label != NULL)
+ free(item->label);
+
G_OBJECT_CLASS(g_db_item_parent_class)->finalize(G_OBJECT(item));
}
@@ -172,8 +176,31 @@ static void g_db_item_finalize(GDbItem *item)
/******************************************************************************
* *
-* Paramètres : a = premier élément à analyser. *
-* b = second élément à analyser. *
+* Paramètres : item = élément de collection à traiter. *
+* *
+* Description : Indique à l'élément qu'il se trouve du côté serveur. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_db_item_set_server_side(GDbItem *item)
+{
+ init_timestamp(&item->created);
+ item->timestamp = item->created;
+
+ item->server_side = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à analyser. *
+* b = second élément à analyser. *
+* with = précise les horodatages à prendre en compte. *
* *
* Description : Effectue la comparaison entre deux éléments de collection. *
* *
@@ -183,35 +210,42 @@ static void g_db_item_finalize(GDbItem *item)
* *
******************************************************************************/
-static gint g_db_item_cmp(GDbItem *a, GDbItem *b)
+gint g_db_item_cmp(GDbItem *a, GDbItem *b, bool with)
{
gint result; /* Bilan à retourner */
- /**
- * A n'utiliser qu'en dernier recours, pour départager deux
- * éléments par un serveur NTP...
- */
+ if (with)
+ result = cmp_timestamp(&a->timestamp, &b->timestamp);
+ else
+ result = 0;
- if (a->modified > b->modified)
- result = 1;
+ if (result == 0)
+ result = cmp_timestamp(&a->created, &b->created);
- else if (a->modified < b->modified)
- result = -1;
+ if (result == 0)
+ result = strcmp(a->label, b->label);
- else
- {
- if (a->created > b->created)
- result = 1;
+ return result;
- else if (a->created < b->created)
- result = -1;
+}
- else
- result = cmp_rle_string(&a->label, &b->label);
- }
+/******************************************************************************
+* *
+* Paramètres : a = premier élément à analyser. *
+* b = second élément à analyser. *
+* *
+* Description : Effectue la comparaison entre deux éléments de collection. *
+* *
+* Retour : Bilan de la comparaison : -1, 0 ou 1. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- return result;
+gint g_db_item_compare_with_timestamp(GDbItem *a, GDbItem *b)
+{
+ return G_DB_ITEM_GET_CLASS(a)->cmp(a, b, true);
}
@@ -229,18 +263,18 @@ static gint g_db_item_cmp(GDbItem *a, GDbItem *b)
* *
******************************************************************************/
-gint g_db_item_compare(GDbItem *a, GDbItem *b)
+gint g_db_item_compare_without_timestamp(GDbItem *a, GDbItem *b)
{
- return G_DB_ITEM_GET_CLASS(a)->cmp(a, b);
+ return G_DB_ITEM_GET_CLASS(a)->cmp(a, b, false);
}
/******************************************************************************
* *
-* Paramètres : item = base d'éléments à charger. [OUT] *
-* fd = flux ouvert en lecture pour l'importation. *
-* flags = éventuelles options d'envoi supplémentaires. *
+* Paramètres : item = base d'éléments à charger. [OUT] *
+* fd = flux ouvert en lecture pour l'importation. *
+* flags = éventuelles options d'envoi supplémentaires. *
* *
* Description : Importe la définition d'une base d'éléments pour collection. *
* *
@@ -252,18 +286,17 @@ gint g_db_item_compare(GDbItem *a, GDbItem *b)
static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags)
{
- uint64_t val64; /* Valeur sur 64 bits */
bool status; /* Bilan d'une réception */
- status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags);
- if (!status) return false;
-
- item->created = be64toh(val64);
+ if (!item->server_side)
+ {
+ status = recv_timestamp(&item->created, fd, flags);
+ if (!status) return false;
- status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags);
- if (!status) return false;
+ status = recv_timestamp(&item->timestamp, fd, flags);
+ if (!status) return false;
- item->modified = be64toh(val64);
+ }
status = recv_rle_string(&item->author, fd, flags);
if (!status) return false;
@@ -271,9 +304,6 @@ static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags)
status = recv_rle_string(&item->tool, fd, flags);
if (!status) return false;
- status = recv_rle_string(&item->label, fd, flags);
- if (!status) return false;
-
return true;
}
@@ -295,7 +325,13 @@ static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags)
bool g_db_item_recv(GDbItem *item, int fd, int flags)
{
- return G_DB_ITEM_GET_CLASS(item)->recv(item, fd, flags);
+ bool result; /* Bilan à retourner */
+
+ result = G_DB_ITEM_GET_CLASS(item)->recv(item, fd, flags);
+
+ G_DB_ITEM_GET_CLASS(item)->build_label(item);
+
+ return result;
}
@@ -318,19 +354,20 @@ static bool g_db_item_send_to_fd(const GDbItem *item, int fd, int flags)
{
bool status; /* Bilan d'une émission */
- status = safe_send(fd, (uint64_t []) { htobe64(item->created) }, sizeof(uint64_t), MSG_MORE | flags);
- if (!status) return false;
+ if (item->server_side)
+ {
+ status = send_timestamp(&item->created, fd, MSG_MORE | flags);
+ if (!status) return false;
- status = safe_send(fd, (uint64_t []) { htobe64(item->modified) }, sizeof(uint64_t), MSG_MORE | flags);
- if (!status) return false;
+ status = send_timestamp(&item->timestamp, fd, MSG_MORE | flags);
+ if (!status) return false;
- status = send_rle_string(&item->author, fd, MSG_MORE | flags);
- if (!status) return false;
+ }
- status = send_rle_string(&item->tool, fd, MSG_MORE | flags);
+ status = send_rle_string(&item->author, fd, MSG_MORE | flags);
if (!status) return false;
- status = send_rle_string(&item->label, fd, flags);
+ status = send_rle_string(&item->tool, fd, flags);
if (!status) return false;
return true;
@@ -417,6 +454,86 @@ bool g_db_item_cancel(GDbItem *item, GLoadedBinary *binary)
/******************************************************************************
* *
+* Paramètres : item = élément de collection à consulter. *
+* *
+* Description : Décrit l'élément de collection en place. *
+* *
+* Retour : Chaîne de caractère correspondante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_db_item_get_label(const GDbItem *item)
+{
+ return item->label;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément de collection à consulter. *
+* *
+* Description : Fournit l'horodatage associé à l'élément de collection. *
+* *
+* Retour : Date d'activité de l'élément. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+timestamp_t g_db_item_get_timestamp(const GDbItem *item)
+{
+ return item->timestamp;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément de collection à mettre à jour. *
+* first = horodatage du premier élément désactivé ou NULL. *
+* *
+* Description : Active ou désactive un élément de collection en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_db_item_set_activity(GDbItem *item, timestamp_t *first)
+{
+ if (first == NULL)
+ item->timestamp = item->created;
+ else
+ item->timestamp = --(*first);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : item = élément de collection à consulter. *
+* *
+* Description : Indique si l'élément est activé ou désactivé. *
+* *
+* Retour : Etat de l'activité de l'élément. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_db_item_is_active(const GDbItem *item)
+{
+ return (cmp_timestamp(&item->created, &item->timestamp) == 0);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : item = base d'éléments à modifier. *
* is_volatile = état du besoin en sauvegarde. *
* *
@@ -477,31 +594,17 @@ bool g_db_item_is_volatile(const GDbItem *item)
static bool _g_db_item_prepare_db_statement(const GDbItem *item, bound_value **values, size_t *count)
{
bool result; /* Bilan à retourner */
- bound_value *value; /* Valeur à éditer / définir */
result = true;
- *count += 2;
- *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
-
- value = &(*values)[*count - 2];
-
- value->name = "created";
- value->type = SQLITE_INT64;
- value->integer64 = item->created;
+ result &= prepare_db_statement_for_timestamp(&item->created, "created", values, count);
- value = &(*values)[*count - 1];
-
- value->name = "modified";
- value->type = SQLITE_INT64;
- value->integer64 = item->modified;
+ result &= prepare_db_statement_for_timestamp(&item->timestamp, "timestamp", values, count);
result &= prepare_db_statement_for_rle_string(&item->author, "author", values, count);
result &= prepare_db_statement_for_rle_string(&item->tool, "tool", values, count);
- result &= prepare_db_statement_for_rle_string(&item->label, "label", values, count);
-
return result;
}
@@ -548,28 +651,17 @@ bool g_db_item_prepare_db_statement(const GDbItem *item, bound_value **values, s
static bool _g_db_item_load(GDbItem *item, const bound_value *values, size_t count)
{
bool result; /* Bilan global à retourner */
- const bound_value *value; /* Valeur à éditer / définir */
-
- value = find_bound_value(values, count, "created");
- if (value == NULL) return false;
- if (value->type != SQLITE_INT64) return false;
-
- item->created = value->integer64;
- value = find_bound_value(values, count, "modified");
- if (value == NULL) return false;
- if (value->type != SQLITE_INT64) return false;
+ result = true;
- item->modified = value->integer64;
+ result &= load_timestamp(&item->created, "created", values, count);
- result = true;
+ result &= load_timestamp(&item->timestamp, "timestamp", values, count);
result &= load_rle_string(&item->author, "author", values, count);
result &= load_rle_string(&item->tool, "tool", values, count);
- result &= load_rle_string(&item->label, "label", values, count);
-
return result;
}
@@ -591,6 +683,12 @@ static bool _g_db_item_load(GDbItem *item, const bound_value *values, size_t cou
bool g_db_item_load(GDbItem *item, const bound_value *values, size_t count)
{
- return G_DB_ITEM_GET_CLASS(item)->load(item, values, count);
+ bool result; /* Bilan à retourner */
+
+ result = G_DB_ITEM_GET_CLASS(item)->load(item, values, count);
+
+ G_DB_ITEM_GET_CLASS(item)->build_label(item);
+
+ return result;
}
diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h
index 09ac45c..7d3392c 100644
--- a/src/analysis/db/item.h
+++ b/src/analysis/db/item.h
@@ -29,6 +29,7 @@
#include <stdbool.h>
+#include "misc/timestamp.h"
#include "../../common/sqlite.h"
@@ -55,8 +56,17 @@ typedef struct _GDbItemClass GDbItemClass;
/* Indique le type défini pour une base d'élément de collection générique. */
GType g_db_item_get_type(void);
+/* Indique à l'élément qu'il se trouve du côté serveur. */
+void g_db_item_set_server_side(GDbItem *);
+
+/* Effectue la comparaison entre deux éléments de collection. */
+gint g_db_item_cmp(GDbItem *, GDbItem *, bool);
+
+/* Effectue la comparaison entre deux éléments de collection. */
+gint g_db_item_compare_with_timestamp(GDbItem *, GDbItem *);
+
/* Effectue la comparaison entre deux éléments de collection. */
-gint g_db_item_compare(GDbItem *, GDbItem *);
+gint g_db_item_compare_without_timestamp(GDbItem *, GDbItem *);
/* Importe la définition d'une base d'éléments pour collection. */
bool g_db_item_recv(GDbItem *, int, int);
@@ -70,6 +80,18 @@ bool g_db_item_apply(GDbItem *, GLoadedBinary *);
/* Annule une bascule d'affichage d'opérande sur un binaire. */
bool g_db_item_cancel(GDbItem *, GLoadedBinary *);
+/* Décrit l'élément de collection en place. */
+const char *g_db_item_get_label(const GDbItem *);
+
+/* Fournit l'horodatage associé à l'élément de collection. */
+timestamp_t g_db_item_get_timestamp(const GDbItem *);
+
+/* Active ou désactive un élément de collection en place. */
+void g_db_item_set_activity(GDbItem *, timestamp_t *);
+
+/* Indique si l'élément est activé ou désactivé. */
+bool g_db_item_is_active(const GDbItem *);
+
/* Définit si l'élément contient des données à oublier ou non. */
void g_db_item_set_volatile(GDbItem *, bool);
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index 8512406..ba64491 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -28,6 +28,9 @@
#include <sys/socket.h>
+#include <i18n.h>
+
+
#include "../collection-int.h"
#include "../item-int.h"
@@ -69,7 +72,7 @@ static void g_db_bookmark_dispose(GDbBookmark *);
static void g_db_bookmark_finalize(GDbBookmark *);
/* Effectue la comparaison entre deux signets de collection. */
-static gint g_db_bookmark_cmp(GDbBookmark *, GDbBookmark *);
+static gint g_db_bookmark_cmp(GDbBookmark *, GDbBookmark *, bool);
/* Importe la définition d'un signet dans un flux réseau. */
static bool g_db_bookmark_recv_from_fd(GDbBookmark *, int, int);
@@ -80,6 +83,9 @@ static bool g_db_bookmark_send_to_fd(const GDbBookmark *, int, int);
/* Exécute un signet sur un tampon de binaire chargé. */
static bool g_db_bookmark_run(GDbBookmark *, GLoadedBinary *, bool *, bool);
+/* Construit la description humaine d'un signet sur un tampon. */
+static void g_db_bookmark_build_label(GDbBookmark *);
+
/* Applique un signet sur un tampon de binaire chargé. */
static bool g_db_bookmark_apply(GDbBookmark *, GLoadedBinary *);
@@ -168,10 +174,12 @@ static void g_db_bookmark_class_init(GDbBookmarkClass *klass)
item = G_DB_ITEM_CLASS(klass);
- item->cmp = (GCompareFunc)g_db_bookmark_cmp;
+ item->cmp = (cmp_db_item_fc)g_db_bookmark_cmp;
item->recv = (recv_db_item_fc)g_db_bookmark_recv_from_fd;
item->send = (send_db_item_fc)g_db_bookmark_send_to_fd;
+
+ item->build_label = (build_item_label_fc)g_db_bookmark_build_label;
item->apply = (run_item_fc)g_db_bookmark_apply;
item->cancel = (run_item_fc)g_db_bookmark_cancel;
@@ -269,8 +277,9 @@ GDbBookmark *g_db_bookmark_new(const vmpa2t *addr, const char *comment)
/******************************************************************************
* *
-* Paramètres : a = premier élément à analyser. *
-* b = second élément à analyser. *
+* Paramètres : a = premier élément à analyser. *
+* b = second élément à analyser. *
+* with = précise les horodatages à prendre en compte. *
* *
* Description : Effectue la comparaison entre deux signets de collection. *
* *
@@ -280,7 +289,7 @@ GDbBookmark *g_db_bookmark_new(const vmpa2t *addr, const char *comment)
* *
******************************************************************************/
-static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b)
+static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b, bool with)
{
gint result; /* Bilan de la comparaison */
@@ -290,7 +299,7 @@ static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b)
result = cmp_rle_string(&a->comment, &b->comment);
if (result == 0)
- result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b));
+ result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b), with);
return result;
@@ -413,6 +422,25 @@ static bool g_db_bookmark_run(GDbBookmark *bookmark, GLoadedBinary *binary, bool
/******************************************************************************
* *
* Paramètres : bookmark = signet à manipuler. *
+* *
+* Description : Construit la description humaine d'un signet sur un tampon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_db_bookmark_build_label(GDbBookmark *bookmark)
+{
+ asprintf(&G_DB_ITEM(bookmark)->label, _("Bookmark \"%s\""), get_rle_string(&bookmark->comment));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : bookmark = signet à manipuler. *
* binary = binaire chargé en mémoire à modifier. *
* *
* Description : Applique un signet sur un tampon de binaire chargé. *
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index 1bed0ab..249620b 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -67,7 +67,7 @@ static void g_db_comment_dispose(GDbComment *);
static void g_db_comment_finalize(GDbComment *);
/* Effectue la comparaison entre deux commentaires enregistrés. */
-static gint g_db_comment_cmp(GDbComment *, GDbComment *);
+static gint g_db_comment_cmp(GDbComment *, GDbComment *, bool);
/* Importe la définition d'un commentaire dans un flux réseau. */
static bool g_db_comment_recv_from_fd(GDbComment *, int, int);
@@ -157,7 +157,7 @@ static void g_db_comment_class_init(GDbCommentClass *klass)
item = G_DB_ITEM_CLASS(klass);
- item->cmp = (GCompareFunc)g_db_comment_cmp;
+ item->cmp = (cmp_db_item_fc)g_db_comment_cmp;
item->recv = (recv_db_item_fc)g_db_comment_recv_from_fd;
item->send = (send_db_item_fc)g_db_comment_send_to_fd;
@@ -259,8 +259,9 @@ GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volat
/******************************************************************************
* *
-* Paramètres : a = premier élément à analyser. *
-* b = second élément à analyser. *
+* Paramètres : a = premier élément à analyser. *
+* b = second élément à analyser. *
+* with = précise les horodatages à prendre en compte. *
* *
* Description : Effectue la comparaison entre deux commentaires enregistrés. *
* *
@@ -270,7 +271,7 @@ GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volat
* *
******************************************************************************/
-static gint g_db_comment_cmp(GDbComment *a, GDbComment *b)
+static gint g_db_comment_cmp(GDbComment *a, GDbComment *b, bool with)
{
gint result; /* Bilan de la comparaison */
@@ -280,7 +281,7 @@ static gint g_db_comment_cmp(GDbComment *a, GDbComment *b)
result = cmp_rle_string(&a->text, &b->text);
if (result == 0)
- result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b));
+ result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b), with);
return 0;
diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c
index 2168e6b..67187aa 100644
--- a/src/analysis/db/items/switcher.c
+++ b/src/analysis/db/items/switcher.c
@@ -75,7 +75,7 @@ static void g_db_switcher_dispose(GDbSwitcher *);
static void g_db_switcher_finalize(GDbSwitcher *);
/* Effectue la comparaison entre deux signets de collection. */
-static gint g_db_switcher_cmp(GDbSwitcher *, GDbSwitcher *);
+static gint g_db_switcher_cmp(GDbSwitcher *, GDbSwitcher *, bool);
/* Importe la définition d'un signet dans un flux réseau. */
static bool g_db_switcher_recv_from_fd(GDbSwitcher *, int, int);
@@ -175,10 +175,11 @@ static void g_db_switcher_class_init(GDbSwitcherClass *klass)
item = G_DB_ITEM_CLASS(klass);
- item->cmp = (GCompareFunc)g_db_switcher_cmp;
+ item->cmp = (cmp_db_item_fc)g_db_switcher_cmp;
item->recv = (recv_db_item_fc)g_db_switcher_recv_from_fd;
item->send = (send_db_item_fc)g_db_switcher_send_to_fd;
+
item->apply = (run_item_fc)g_db_switcher_apply;
item->cancel = (run_item_fc)g_db_switcher_cancel;
@@ -190,7 +191,7 @@ static void g_db_switcher_class_init(GDbSwitcherClass *klass)
/******************************************************************************
* *
-* Paramètres : switcher = instance à initialiser. *
+* Paramètres : switcher = instance à initialiser. *
* *
* Description : Initialise une bascule d'affichage pour opérande numérique. *
* *
@@ -208,7 +209,7 @@ static void g_db_switcher_init(GDbSwitcher *switcher)
/******************************************************************************
* *
-* Paramètres : switcher = instance d'objet GLib à traiter. *
+* Paramètres : switcher = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
@@ -227,7 +228,7 @@ static void g_db_switcher_dispose(GDbSwitcher *switcher)
/******************************************************************************
* *
-* Paramètres : switcher = instance d'objet GLib à traiter. *
+* Paramètres : switcher = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -259,7 +260,7 @@ static void g_db_switcher_finalize(GDbSwitcher *switcher)
GDbSwitcher *g_db_switcher_new(const GArchInstruction *instr, const GImmOperand *imm, ImmOperandDisplay display)
{
- GDbSwitcher *result; /* Instance à retourner */
+ GDbSwitcher *result; /* Instance à retourner */
size_t count; /* Nombre d'opérandes à visiter*/
size_t i; /* Boucle de parcours */
const mrange_t *range; /* Localisation de l'instruct° */
@@ -299,8 +300,9 @@ GDbSwitcher *g_db_switcher_new(const GArchInstruction *instr, const GImmOperand
/******************************************************************************
* *
-* Paramètres : a = premier élément à analyser. *
-* b = second élément à analyser. *
+* Paramètres : a = premier élément à analyser. *
+* b = second élément à analyser. *
+* with = précise les horodatages à prendre en compte. *
* *
* Description : Effectue la comparaison entre deux signets de collection. *
* *
@@ -310,7 +312,7 @@ GDbSwitcher *g_db_switcher_new(const GArchInstruction *instr, const GImmOperand
* *
******************************************************************************/
-static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b)
+static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b, bool with)
{
gint result; /* Bilan de la comparaison */
@@ -337,7 +339,7 @@ static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b)
}
if (result == 0)
- result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b));
+ result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b), with);
return result;
diff --git a/src/analysis/db/misc/Makefile.am b/src/analysis/db/misc/Makefile.am
index b3829e3..dde6026 100755
--- a/src/analysis/db/misc/Makefile.am
+++ b/src/analysis/db/misc/Makefile.am
@@ -2,7 +2,8 @@
noinst_LTLIBRARIES = libanalysisdbmisc.la
libanalysisdbmisc_la_SOURCES = \
- rlestr.h rlestr.c
+ rlestr.h rlestr.c \
+ timestamp.h timestamp.c
libanalysisdbmisc_la_LIBADD =
diff --git a/src/analysis/db/misc/timestamp.c b/src/analysis/db/misc/timestamp.c
new file mode 100644
index 0000000..624c811
--- /dev/null
+++ b/src/analysis/db/misc/timestamp.c
@@ -0,0 +1,263 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rlestr.c - encodage par plage unique d'une chaîne de caractères
+ *
+ * Copyright (C) 2014 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA 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.
+ *
+ * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "timestamp.h"
+
+
+#include <endian.h>
+#include <malloc.h>
+#include <sqlite3.h>
+#include <time.h>
+
+
+#include "../../../common/io.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : timestamp = horodatage à initialiser. [OUT] *
+* *
+* Description : Obtient un horodatage initialisé au moment même. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void init_timestamp(timestamp_t *timestamp)
+{
+ struct timespec info; /* Détails sur l'époque */
+
+ clock_gettime(CLOCK_REALTIME, &info);
+
+ *timestamp = info.tv_sec * 1000000 + info.tv_nsec / 1000;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stamp = horodatage d'un élément à tester. *
+* limit = horodatage en limite d'activité (incluse). *
+* *
+* Description : Définit si un horodatage est plus récent qu'un autre ou non. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool timestamp_is_younger(timestamp_t stamp, timestamp_t limit)
+{
+ if (limit == TIMESTAMP_ALL_ACTIVE)
+ return true;
+
+ if (limit == TIMESTAMP_ALL_INACTIVE)
+ return false;
+
+ return (stamp <= limit);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : t1 = première chaîne à comparer. *
+* t2 = seconde chaîne à comparer. *
+* *
+* Description : Effectue la comparaison entre deux horodatages. *
+* *
+* Retour : Résultat de la comparaison : -1, 0 ou 1. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int cmp_timestamp(const timestamp_t *t1, const timestamp_t *t2)
+{
+ int result; /* Bilan à retourner */
+
+ if (*t1 < *t2)
+ result = -1;
+
+ else if (*t1 > *t2)
+ result = 1;
+
+ else
+ result = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : timestamp = informations à constituer. [OUT] *
+* fd = flux ouvert en lecture pour l'importation. *
+* flags = éventuelles options de réception supplémentaires.*
+* *
+* Description : Importe la définition d'un horodatage. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool recv_timestamp(timestamp_t *timestamp, int fd, int flags)
+{
+ uint64_t val64; /* Valeur sur 64 bits */
+ bool status; /* Bilan d'une opération */
+
+ status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags);
+ if (!status) return false;
+
+ *timestamp = be64toh(val64);
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : timestamp = informations à sauvegarer. *
+* fd = flux ouvert en écriture pour l'exportation. *
+* flags = éventuelles options d'envoi supplémentaires. *
+* *
+* Description : Exporte la définition d'un horodatage. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool send_timestamp(const timestamp_t *timestamp, int fd, int flags)
+{
+ bool status; /* Bilan d'une opération */
+
+ status = safe_send(fd, (uint64_t []) { htobe64(*timestamp) }, sizeof(uint64_t), flags);
+ if (!status) return false;
+
+ return true;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATIONS AVEC UNE BASE DE DONNEES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : timestamp = horodatage aux informations inutiles. *
+* name = désignation personnalisée du champ dans la BD. *
+* values = couples de champs et de valeurs à lier. [OUT] *
+* count = nombre de ces couples. [OUT] *
+* *
+* Description : Constitue les champs destinés à une insertion / modification.*
+* *
+* Retour : Bilan de l'opération : succès ou non. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool prepare_db_statement_for_timestamp(const timestamp_t *timestamp, const char *name, bound_value **values, size_t *count)
+{
+ bound_value *value; /* Valeur à éditer / définir */
+
+ *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value));
+ value = &(*values)[*count - 1];
+
+ value->name = name;
+ value->type = SQLITE_INT64;
+ value->integer64 = *timestamp;
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : timestamp = horodatage aux informations inutiles. *
+* name = désignation personnalisée du champ dans la BD. *
+* values = tableau d'éléments à compléter. [OUT] *
+* count = nombre de descriptions renseignées. [OUT] *
+* *
+* Description : Décrit les colonnes utiles à un horodatage. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool setup_load_of_timestamp(const timestamp_t *timestamp, const char *name, bound_value **values, size_t *count)
+{
+ *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value));
+
+ (*values)[*count - 1].name = name;
+
+ return true;
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : timestamp = horodatage à compléter. *
+* name = désignation personnalisée du champ dans la BD. *
+* values = tableau d'éléments à consulter. *
+* count = nombre de descriptions renseignées. *
+* *
+* Description : Charge les valeurs utiles pour un horodatage. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_timestamp(timestamp_t *timestamp, const char *name, const bound_value *values, size_t count)
+{
+ const bound_value *value; /* Valeur à intégrer */
+
+ value = find_bound_value(values, count, name);
+ if (value == NULL) return false;
+ if (value->type != SQLITE_INT64) return false;
+
+ *timestamp = value->integer64;
+
+ return true;
+
+}
diff --git a/src/analysis/db/misc/timestamp.h b/src/analysis/db/misc/timestamp.h
new file mode 100644
index 0000000..1efbb15
--- /dev/null
+++ b/src/analysis/db/misc/timestamp.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * timestamp.h - prototypes pour l'encodage par plage unique d'une chaîne de caractères
+ *
+ * Copyright (C) 2014 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA 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.
+ *
+ * OpenIDA 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_DB_MISC_TIMESTAMP_H
+#define _ANALYSIS_DB_MISC_TIMESTAMP_H
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+
+#include "../../../common/sqlite.h"
+
+
+
+/* Représentation d'un horodatage */
+typedef uint64_t timestamp_t;
+
+
+/* Valeurs particulières */
+#define TIMESTAMP_ALL_ACTIVE 0
+#define TIMESTAMP_ALL_INACTIVE 1
+
+
+/* Obtient un horodatage initialisé au moment même. */
+void init_timestamp(timestamp_t *);
+
+/* Définit si un horodatage est plus récent qu'un autre ou non. */
+bool timestamp_is_younger(timestamp_t, timestamp_t);
+
+/* Effectue la comparaison entre deux horodatages. */
+int cmp_timestamp(const timestamp_t *, const timestamp_t *);
+
+/* Importe la définition d'un horodatage. */
+bool recv_timestamp(timestamp_t *, int, int);
+
+/* Exporte la définition d'un horodatage. */
+bool send_timestamp(const timestamp_t *, int, int);
+
+
+
+/* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */
+
+
+/* Définition du tronc commun pour les créations SQLite */
+#define SQLITE_TIMESTAMP_CREATE(n) \
+ n " INTEGER"
+
+/* Constitue les champs destinés à une insertion / modification. */
+bool prepare_db_statement_for_timestamp(const timestamp_t *, const char *, bound_value **, size_t *);
+
+/* Décrit les colonnes utiles à un horodatage. */
+bool setup_load_of_timestamp(const timestamp_t *, const char *, bound_value **, size_t *);
+
+/* Charge les valeurs utiles pour un horodatage. */
+bool load_timestamp(timestamp_t *, const char *, const bound_value *, size_t);
+
+
+
+#endif /* _ANALYSIS_DB_MISC_TIMESTAMP_H */
diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h
index 04bbd33..ab12654 100644
--- a/src/analysis/db/protocol.h
+++ b/src/analysis/db/protocol.h
@@ -95,7 +95,8 @@ typedef enum _DBAction
{
DBA_ADD_ITEM, /* Ajout d'un élément */
DBA_REM_ITEM, /* Suppression d'un élément */
- DBA_MOD_ITEM, /* Modification de l'existant */
+
+ DBA_CHANGE_STATE, /* Changement d'activité */
DBA_COUNT
@@ -116,6 +117,34 @@ typedef enum _DBCommand
DBC_SAVE, /* Enregistrement de l'archive */
DBC_COLLECTION, /* Implication d'une collection*/
+
+
+ /**
+ * Gestion de la commande 'DBC_SET_LAST_ACTIVE'.
+ *
+ * Le client connecté envoie un paquet de la forme suivante :
+ *
+ * [ Statut d'historique : DBC_SET_LAST_ACTIVE ]
+ * [ <horodatage du dernier élément actif ]
+ *
+ * Le serveur s'exécute et notifie le client d'éventuels changements,
+ * avec une série de paquets de la forme :
+ *
+ * [ Traitement de collection : DBC_COLLECTION ]
+ * [ Action : DBC_SET_LAST_ACTIVE ]
+ * [ <élément dont le statut a évolué> ]
+ *
+ * Les traitements se réalisent dans :
+ * - g_db_collection_set_last_active() pour la partie serveur.
+ * - g_db_client_set_last_active() pour la partie client.
+ *
+ */
+
+ DBC_SET_LAST_ACTIVE, /* Définition du dernier actif */
+
+
+
+
DBC_COUNT
} DBCommand;
@@ -174,6 +203,4 @@ typedef enum _DBError
-
-
#endif /* _ANALYSIS_DB_PROTOCOL_H */
diff --git a/src/gui/panels/bookmarks.c b/src/gui/panels/bookmarks.c
index 60daf67..b3af70c 100644
--- a/src/gui/panels/bookmarks.c
+++ b/src/gui/panels/bookmarks.c
@@ -579,41 +579,71 @@ static void on_collection_content_changed(GDbCollection *collec, DBAction action
VMPA_BUFFER(virt); /* Adresse virtuelle */
GtkTreeIter iter; /* Point d'insertion */
+ GtkTreeModel *model; /* Modèle de gestion courant */
+ GDbBookmark *displayed; /* Elément de collection */
+ if (action == DBA_ADD_ITEM || (action == DBA_CHANGE_STATE && g_db_item_is_active(G_DB_ITEM(bookmark))))
+ {
+ store = GTK_TREE_STORE(gtk_tree_view_get_model(panel->treeview));
- printf(" Passage :: %d\n", action);
+ format = g_loaded_binary_get_format(panel->binary);
- store = GTK_TREE_STORE(gtk_tree_view_get_model(panel->treeview));
+ proc = g_loaded_binary_get_processor(panel->binary);
+ msize = g_arch_processor_get_memory_size(proc);
+ g_object_unref(G_OBJECT(proc));
- format = g_loaded_binary_get_format(panel->binary);
- proc = g_loaded_binary_get_processor(panel->binary);
- msize = g_arch_processor_get_memory_size(proc);
- g_object_unref(G_OBJECT(proc));
+ addr = g_db_bookmark_get_address(bookmark);
+ vmpa2_phys_to_string(addr, msize, phys, NULL);
+ vmpa2_virt_to_string(addr, msize, virt, NULL);
+ gtk_tree_store_append(store, &iter, NULL);
+ gtk_tree_store_set(store, &iter,
+ BMC_BOOKMARK, bookmark,
+ BMC_PICTURE, G_BOOKMARKS_PANEL_GET_CLASS(panel)->bookmark_img,
+ BMC_PHYSICAL, phys,
+ BMC_VIRTUAL, virt,
+ BMC_COMMENT, g_db_bookmark_get_comment(bookmark),
+ -1);
- addr = g_db_bookmark_get_address(bookmark);
- vmpa2_phys_to_string(addr, msize, phys, NULL);
- vmpa2_virt_to_string(addr, msize, virt, NULL);
- gtk_tree_store_append(store, &iter, NULL);
- gtk_tree_store_set(store, &iter,
- BMC_BOOKMARK, bookmark,
- BMC_PICTURE, G_BOOKMARKS_PANEL_GET_CLASS(panel)->bookmark_img,
- BMC_PHYSICAL, phys,
- BMC_VIRTUAL, virt,
- BMC_COMMENT, g_db_bookmark_get_comment(bookmark),
- -1);
+ }
+
+ else /*if (action == DBA_CHANGE_STATE && g_db_item_is_active(G_DB_ITEM(bookmark)))*/
+ {
+
+ store = GTK_TREE_STORE(gtk_tree_view_get_model(panel->treeview));
+ model = GTK_TREE_MODEL(store);
+
+
+ if (gtk_tree_model_get_iter_first(model, &iter))
+ do
+ {
+ gtk_tree_model_get(model, &iter, BMC_BOOKMARK, &displayed, -1);
+ if (bookmark == displayed)
+ {
+ gtk_tree_store_remove(store, &iter);
+ break;
+ }
+
+ g_object_unref(G_OBJECT(displayed));
+
+ }
+ while (gtk_tree_model_iter_next(model, &iter));
+
+
+
+ }
}
diff --git a/src/gui/panels/history.c b/src/gui/panels/history.c
index a827961..25ee39f 100644
--- a/src/gui/panels/history.c
+++ b/src/gui/panels/history.c
@@ -32,6 +32,7 @@
#include "panel-int.h"
+#include "../../analysis/db/collection.h"
#include "../../gtkext/easygtk.h"
@@ -62,6 +63,7 @@ typedef enum _HistoryColumn
HTC_ITEM, /* Elément d'évolution */
HTC_PICTURE, /* Image de représentation */
+ HTC_FOREGROUND, /* Couleur d'impression */
HTC_LABEL, /* Désignation humaine */
HTC_COUNT /* Nombre de colonnes */
@@ -84,6 +86,24 @@ static void g_history_panel_finalize(GHistoryPanel *);
/* Réagit à un changement d'affichage principal de contenu. */
static void change_history_panel_current_binary(GHistoryPanel *, GLoadedBinary *);
+/* Réagit à une modification au sein d'une collection donnée. */
+static void on_history_changed(GDbCollection *, DBAction, GDbItem *, GHistoryPanel *);
+
+/* Compare deux lignes entre elles pour le tri des évolutions. */
+static gint sort_history_lines(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gpointer);
+
+/* Réagit à une validation d'une ligne affichée. */
+static void on_history_row_activated(GtkTreeView *, GtkTreePath *, GtkTreeViewColumn *, GHistoryPanel *);
+
+/* Annule l'élément d'évolution courant. */
+static void do_history_undo(GtkButton *, GHistoryPanel *);
+
+/* Restaure l'élément d'évolution suivant. */
+static void do_history_redo(GtkButton *, GHistoryPanel *);
+
+/* Effectue un nettoyage de l'historique. */
+static void do_history_clean(GtkButton *, GHistoryPanel *);
+
/* Indique le type définit pour un panneau d'aperçu de graphiques. */
@@ -137,6 +157,8 @@ static void g_history_panel_init(GHistoryPanel *panel)
GObject *ref; /* Espace de référencement */
GtkWidget *scrollwnd; /* Support défilant */
GtkWidget *treeview; /* Affichage de la liste */
+ GtkCellRenderer *renderer; /* Moteur de rendu de colonne */
+ GtkTreeViewColumn *column; /* Colonne de la liste */
GtkWidget *box; /* Séparation horizontale */
GtkWidget *button; /* Bouton de cette même barre */
@@ -159,7 +181,8 @@ static void g_history_panel_init(GHistoryPanel *panel)
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwnd), GTK_SHADOW_IN);
- panel->store = gtk_tree_store_new(HTC_COUNT, G_TYPE_OBJECT, CAIRO_GOBJECT_TYPE_SURFACE, G_TYPE_STRING);
+ panel->store = gtk_tree_store_new(HTC_COUNT, G_TYPE_OBJECT, CAIRO_GOBJECT_TYPE_SURFACE,
+ G_TYPE_STRING, G_TYPE_STRING);
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(panel->store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
@@ -167,11 +190,32 @@ static void g_history_panel_init(GHistoryPanel *panel)
panel->treeview = GTK_TREE_VIEW(treeview);
+ gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(panel->store), sort_history_lines, NULL, NULL);
+
+ g_signal_connect(treeview, "row-activated", G_CALLBACK(on_history_row_activated), panel);
+
gtk_widget_show(treeview);
gtk_container_add(GTK_CONTAINER(scrollwnd), treeview);
g_object_unref(G_OBJECT(panel->store));
+ /* Cellules d'affichage */
+
+ renderer = gtk_cell_renderer_pixbuf_new();
+ column = gtk_tree_view_column_new_with_attributes("", renderer,
+ "surface", HTC_PICTURE,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id(column, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes(_("Label"), renderer,
+ "foreground", HTC_FOREGROUND,
+ "text", HTC_LABEL,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id(column, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
/* Eléments de contrôle inférieurs */
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
@@ -180,15 +224,15 @@ static void g_history_panel_init(GHistoryPanel *panel)
gtk_box_pack_start(GTK_BOX(base->widget), box, FALSE, TRUE, 0);
button = qck_create_button_with_css_img(NULL, NULL, "img-undo", _("Undo"),
- G_CALLBACK(NULL), NULL);
+ G_CALLBACK(do_history_undo), panel);
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
button = qck_create_button_with_css_img(NULL, NULL, "img-redo", _("Redo"),
- G_CALLBACK(NULL), NULL);
+ G_CALLBACK(do_history_redo), panel);
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
button = qck_create_button_with_css_img(NULL, NULL, "img-clean", _("Clean"),
- G_CALLBACK(NULL), NULL);
+ G_CALLBACK(do_history_clean), panel);
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
}
@@ -303,6 +347,287 @@ GPanelItem *create_history_panel(GObject *ref)
static void change_history_panel_current_binary(GHistoryPanel *panel, GLoadedBinary *binary)
{
- /* TODO */
+
+ GtkTreeStore *store; /* Modèle de gestion */
+ GList *collections; /* Ensemble de collections */
+ GList *c; /* Boucle de parcours #1 */
+ GDbCollection *collec; /* Collection visée manipulée */
+ GList *items; /* Liste des éléments groupés */
+ GList *i; /* Boucle de parcours #2 */
+ GDbItem *item; /* Elément à intégrer */
+ GtkTreeIter iter; /* Point d'insertion */
+
+
+ /* Basculement du binaire utilisé */
+
+
+
+ panel->binary = binary;
+
+
+
+
+
+ store = GTK_TREE_STORE(gtk_tree_view_get_model(panel->treeview));
+ gtk_tree_store_clear(store);
+
+ /* Si le panneau actif ne représente pas un binaire... */
+
+ if (binary == NULL) return;
+
+ /* Actualisation de l'affichage */
+
+ collections = g_loaded_binary_get_all_collections(binary);
+
+ rlock_collections(collections);
+
+ for (c = g_list_first(collections); c != NULL; c = g_list_next(c))
+ {
+ collec = G_DB_COLLECTION(c->data);
+ items = g_db_collection_list_items(collec);
+
+ for (i = g_list_first(items); i != NULL; i = g_list_next(i))
+ {
+ item = G_DB_ITEM(i->data);
+
+ gtk_tree_store_append(store, &iter, NULL);
+ gtk_tree_store_set(store, &iter,
+ HTC_ITEM, item,
+ //HTC_PICTURE, G_BOOKMARKS_PANEL_GET_CLASS(panel)->bookmark_img,
+ HTC_FOREGROUND, g_db_item_is_active(item) ? NULL : "grey",
+ HTC_LABEL, g_db_item_get_label(item),
+ -1);
+
+ }
+
+ g_signal_connect(collec, "content-changed", G_CALLBACK(on_history_changed), panel);
+
+ }
+
+ runlock_collections(collections);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = collection dont le contenu a évolué. *
+* action = type d'évolution rencontrée. *
+* item = élément ajouté, modifié ou supprimé. *
+* panel = panneau d'historique concerné par la procédure. *
+* *
+* Description : Réagit à une modification au sein d'une collection donnée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_history_changed(GDbCollection *collec, DBAction action, GDbItem *item, GHistoryPanel *panel)
+{
+ GtkTreeModel *model; /* Modèle de gestion courant */
+ GtkTreeIter iter; /* Boucle de parcours */
+ GDbItem *displayed; /* Elément de collection */
+
+ model = GTK_TREE_MODEL(panel->store);
+
+ switch (action)
+ {
+ case DBA_CHANGE_STATE:
+
+ if (gtk_tree_model_get_iter_first(model, &iter))
+ do
+ {
+ gtk_tree_model_get(model, &iter, HTC_ITEM, &displayed, -1);
+
+ if (item == displayed)
+ {
+ gtk_tree_store_set(panel->store, &iter,
+ HTC_FOREGROUND, g_db_item_is_active(item) ? NULL : "grey",
+ -1);
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(panel->store),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+ break;
+ }
+
+ g_object_unref(G_OBJECT(displayed));
+
+ }
+ while (gtk_tree_model_iter_next(model, &iter));
+
+
+ break;
+
+
+ }
+
+
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : model = gestionnaire de données pour la liste traitée. *
+* a = premier point de comparaison. *
+* b = second point de comparaison. *
+* dummy = adresse non utilisée ici. *
+* *
+* Description : Compare deux lignes entre elles pour le tri des évolutions. *
+* *
+* Retour : -1, 0 ou 1 selon le résultat de la comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gint sort_history_lines(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer dummy)
+{
+ gint result; /* Bilan à retourner */
+ GDbItem *item_a; /* Elément de collection A */
+ GDbItem *item_b; /* Elément de collection B */
+
+ gtk_tree_model_get(model, a, HTC_ITEM, &item_a, -1);
+ gtk_tree_model_get(model, b, HTC_ITEM, &item_b, -1);
+
+ result = g_db_item_compare_with_timestamp(item_a, item_b);
+
+ g_object_unref(G_OBJECT(item_a));
+ g_object_unref(G_OBJECT(item_b));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : treeview = composant graphique manipulé par l'utilisateur. *
+* path = chemin d'accès à la ligne activée. *
+* column = colonne impactée par l'action. *
+* panel = panneau d'historique concerné par la procédure. *
+* *
+* Description : Réagit à une validation d'une ligne affichée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_history_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GHistoryPanel *panel)
+{
+
+
+
+
+
+
+}
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton d'édition de l'historique d'évolution. *
+* panel = panneau d'affichage de l'historique. *
+* *
+* Description : Annule l'élément d'évolution courant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void do_history_undo(GtkButton *button, GHistoryPanel *panel)
+{
+ GtkTreeSelection *selection; /* Sélection courante */
+ GtkTreeModel *model; /* Modèle de gestion de données*/
+ GtkTreeIter iter; /* Pointeur vers la ligne visée*/
+ GDbItem *item; /* Elément de collection */
+ GDbClient *client; /* Connexion vers la base */
+
+ selection = gtk_tree_view_get_selection(panel->treeview);
+
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ {
+ if (!gtk_tree_model_iter_previous(model, &iter))
+ return;
+
+ gtk_tree_model_get(model, &iter, HTC_ITEM, &item, -1);
+
+ client = g_loaded_binary_get_db_client(panel->binary);
+ g_db_client_set_last_active(client, g_db_item_get_timestamp(item));
+ g_object_unref(G_OBJECT(client));
+
+ g_object_unref(G_OBJECT(item));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton d'édition de l'historique d'évolution. *
+* panel = panneau d'affichage de l'historique. *
+* *
+* Description : Restaure l'élément d'évolution suivant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void do_history_redo(GtkButton *button, GHistoryPanel *panel)
+{
+ GtkTreeSelection *selection; /* Sélection courante */
+ GtkTreeModel *model; /* Modèle de gestion de données*/
+ GtkTreeIter iter; /* Pointeur vers la ligne visée*/
+ GDbItem *item; /* Elément de collection */
+ GDbClient *client; /* Connexion vers la base */
+
+ selection = gtk_tree_view_get_selection(panel->treeview);
+
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ {
+ gtk_tree_model_get(model, &iter, HTC_ITEM, &item, -1);
+
+ client = g_loaded_binary_get_db_client(panel->binary);
+ g_db_client_set_last_active(client, g_db_item_get_timestamp(item));
+ g_object_unref(G_OBJECT(client));
+
+ g_object_unref(G_OBJECT(item));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : button = bouton d'édition de l'historique d'évolution. *
+* panel = panneau d'affichage de l'historique. *
+* *
+* Description : Effectue un nettoyage de l'historique. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void do_history_clean(GtkButton *button, GHistoryPanel *panel)
+{
+
+
+
+
}