38
38
#include <telepathy-glib/dbus.h>
39
39
#include <telepathy-glib/defs.h>
40
40
#include <telepathy-glib/util.h>
41
#include <telepathy-logger/call-event.h>
42
#include <telepathy-logger/call-event-internal.h>
43
#include <telepathy-logger/event-internal.h>
44
#include <telepathy-logger/text-event.h>
45
#include <telepathy-logger/text-event-internal.h>
46
#include <telepathy-logger/log-manager.h>
47
#include <telepathy-logger/log-store-internal.h>
48
#include <telepathy-logger/log-manager-internal.h>
42
#include "telepathy-logger/call-event.h"
43
#include "telepathy-logger/call-event-internal.h"
44
#include "telepathy-logger/entity-internal.h"
45
#include "telepathy-logger/event-internal.h"
46
#include "telepathy-logger/text-event.h"
47
#include "telepathy-logger/text-event-internal.h"
48
#include "telepathy-logger/log-manager.h"
49
#include "telepathy-logger/log-store-internal.h"
50
#include "telepathy-logger/log-manager-internal.h"
51
#include "telepathy-logger/util-internal.h"
50
53
#define DEBUG_FLAG TPL_DEBUG_LOG_STORE
51
#include <telepathy-logger/entity-internal.h>
52
#include <telepathy-logger/debug-internal.h>
53
#include <telepathy-logger/util-internal.h>
54
#include "telepathy-logger/debug-internal.h"
55
56
#define LOG_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR)
56
57
#define LOG_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
57
58
#define LOG_DIR_CHATROOMS "chatrooms"
58
59
#define LOG_FILENAME_SUFFIX ".log"
60
#define LOG_FILENAME_CALL_TAG ".call"
61
#define LOG_FILENAME_CALL_SUFFIX LOG_FILENAME_CALL_TAG LOG_FILENAME_SUFFIX
62
#define LOG_DATE_PATTERN "[0-9]{8,}"
63
#define LOG_FILENAME_PATTERN "^" LOG_DATE_PATTERN "\\" LOG_FILENAME_SUFFIX "$"
64
#define LOG_FILENAME_CALL_PATTERN "^" LOG_DATE_PATTERN "\\" LOG_FILENAME_CALL_TAG "\\" LOG_FILENAME_SUFFIX "$"
59
66
#define LOG_TIME_FORMAT_FULL "%Y%m%dT%H:%M:%S"
60
67
#define LOG_TIME_FORMAT "%Y%m%d"
61
68
#define LOG_HEADER \
265
277
param_spec = g_param_spec_boolean ("testmode",
267
"Wheter the logstore is in testmode, for testsuite use only",
279
"Whether the logstore is in testmode, for testsuite use only",
268
280
FALSE, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
269
281
g_object_class_install_property (object_class, PROP_TESTMODE, param_spec);
355
log_store_xml_get_file_suffix (GType type)
357
if (type == TPL_TYPE_TEXT_EVENT)
358
return LOG_FILENAME_SUFFIX;
359
else if (type == TPL_TYPE_CALL_EVENT)
360
return LOG_FILENAME_CALL_SUFFIX;
362
g_return_val_if_reached (NULL);
344
log_store_xml_get_timestamp_filename (void)
366
log_store_xml_get_timestamp_filename (GType type)
350
372
now = g_date_time_new_now_local ();
351
373
time_str = g_date_time_format (now, LOG_TIME_FORMAT);
352
filename = g_strconcat (time_str, LOG_FILENAME_SUFFIX, NULL);
374
filename = g_strconcat (time_str, log_store_xml_get_file_suffix (type),
354
377
g_date_time_unref (now);
355
378
g_free (time_str);
377
401
log_store_xml_get_filename (TplLogStoreXml *self,
378
402
TpAccount *account,
382
407
gchar *timestamp;
385
410
id_dir = log_store_xml_get_dir (self, account, target);
386
timestamp = log_store_xml_get_timestamp_filename ();
411
timestamp = log_store_xml_get_timestamp_filename (type);
387
412
filename = g_build_filename (id_dir, timestamp, NULL);
413
439
g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
414
440
g_return_val_if_fail (TPL_IS_ENTITY (target), FALSE);
416
filename = log_store_xml_get_filename (self, account, target);
442
filename = log_store_xml_get_filename (self, account, target, type);
417
443
basedir = g_path_get_dirname (filename);
419
445
if (!g_file_test (basedir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
473
499
gchar *timestamp = NULL;
474
500
gchar *contact_name = NULL;
475
501
gchar *contact_id = NULL;
502
gchar *log_str = NULL;
477
503
TpChannelTextMessageType msg_type;
479
505
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
509
535
avatar_token = g_markup_escape_text (tpl_entity_get_avatar_token (sender),
512
event = g_strdup_printf ("<message time='%s' id='%s' name='%s' "
538
log_str = g_strdup_printf ("<message time='%s' id='%s' name='%s' "
513
539
"token='%s' isuser='%s' type='%s'>"
514
540
"%s</message>\n" LOG_FOOTER, timestamp,
515
541
contact_id, contact_name,
523
549
contact_id, timestamp);
525
551
ret = _log_store_xml_write_to_store (self, account,
526
_tpl_event_get_target (TPL_EVENT (message)), event, error);
552
_tpl_event_get_target (TPL_EVENT (message)), log_str, TPL_TYPE_TEXT_EVENT,
529
556
g_free (contact_id);
530
557
g_free (contact_name);
531
558
g_free (timestamp);
534
561
g_free (avatar_token);
536
563
if (bus_daemon != NULL)
615
642
tpl_entity_get_identifier (target),
618
ret = _log_store_xml_write_to_store (self, account, target, log_str, error);
645
ret = _log_store_xml_write_to_store (self, account, target, log_str,
646
TPL_TYPE_CALL_EVENT, error);
621
649
g_free (sender_id);
689
log_store_xml_exists_in_directory (const gchar *dirname,
695
const gchar *basename;
698
DEBUG ("Looking in directory '%s' %s",
699
dirname, recursive ? "resursively" : "");
701
dir = g_dir_open (dirname, 0, NULL);
702
exists = (dir != NULL);
704
if (CONTAINS_ALL_SUPPORTED_TYPES (type_mask) || !exists)
708
while ((basename = g_dir_read_name (dir)) != NULL)
712
filename = g_build_filename (dirname, basename, NULL);
714
DEBUG ("Matching with filename '%s'", basename);
716
if (recursive && g_file_test (filename, G_FILE_TEST_IS_DIR))
717
exists = log_store_xml_exists_in_directory (filename, regex, type_mask,
718
!tp_strdiff (basename, LOG_DIR_CHATROOMS));
719
else if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
720
exists = g_regex_match (regex, basename, 0, 0);
737
log_store_xml_create_filename_regex (gint type_mask)
740
GRegex *regex = NULL;
741
GError *error = NULL;
743
pattern = g_string_new ("");
745
if (type_mask & TPL_EVENT_MASK_TEXT)
746
g_string_append (pattern, LOG_FILENAME_PATTERN);
748
if (type_mask & TPL_EVENT_MASK_CALL)
749
g_string_append_printf (pattern,
750
"%s" LOG_FILENAME_CALL_PATTERN,
751
pattern->len == 0 ? "" : "|");
753
if (pattern->len == 0)
756
DEBUG ("Pattern is '%s'", pattern->str);
758
regex = g_regex_new (pattern->str, G_REGEX_OPTIMIZE, 0, &error);
762
DEBUG ("Failed to create regex: %s", error->message);
763
g_error_free (error);
767
g_string_free (pattern, TRUE);
662
774
log_store_xml_exists (TplLogStore *store,
667
779
TplLogStoreXml *self = (TplLogStoreXml *) store;
782
gboolean exists = FALSE;
671
784
g_return_val_if_fail (TPL_IS_LOG_STORE_XML (self), FALSE);
672
785
g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
673
g_return_val_if_fail (TPL_IS_ENTITY (target), FALSE);
675
/* FIXME This method is exposed synchronously in the log manager API and
676
* thus we need a constant time reply. The implementation is not 100%
677
* correct here, but provide this constant time. See fd.o but #35549. */
679
dir = log_store_xml_get_dir (self, account, target);
680
exists = g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
786
g_return_val_if_fail (target == NULL || TPL_IS_ENTITY (target), FALSE);
788
dirname = log_store_xml_get_dir (self, account, target);
789
regex = log_store_xml_create_filename_regex (type_mask);
792
exists = log_store_xml_exists_in_directory (dirname, regex, type_mask,
798
g_regex_unref (regex);
770
886
DEBUG ("Collating a list of dates in:'%s'", directory);
772
pattern = g_string_new ("");
774
if (type_mask & TPL_EVENT_MASK_TEXT)
775
g_string_append (pattern, "<message ");
777
if (type_mask & TPL_EVENT_MASK_CALL)
778
g_string_append_printf (pattern,
780
pattern->len == 0 ? "" : "|");
782
if (pattern->len == 0)
887
regex = log_store_xml_create_filename_regex (type_mask);
785
regex = g_regex_new (pattern->str, G_REGEX_OPTIMIZE, 0, &error);
788
DEBUG ("Failed to create regex: %s", error->message);
789
g_error_free (error);
793
892
while ((basename = g_dir_read_name (dir)) != NULL)
797
if (!g_str_has_suffix (basename, LOG_FILENAME_SUFFIX))
800
filename = g_build_filename (directory, basename, NULL);
802
if (CONTAINS_ALL_SUPPORTED_TYPES (type_mask)
803
|| log_store_xml_match_in_file (filename, regex))
809
p = strstr (basename, LOG_FILENAME_SUFFIX);
810
str = g_strndup (basename, p - basename);
815
date = create_date_from_string (str);
817
dates = g_list_insert_sorted (dates, date,
818
(GCompareFunc) g_date_compare);
898
if (!g_regex_match (regex, basename, 0, NULL))
901
p = strstr (basename, LOG_FILENAME_CALL_SUFFIX);
904
p = strstr (basename, LOG_FILENAME_SUFFIX);
906
str = g_strndup (basename, p - basename);
911
date = create_date_from_string (str);
914
dates = g_list_insert_sorted (dates, date,
915
(GCompareFunc) g_date_compare);
860
955
g_date_strftime (str, 9, "%Y%m%d", date);
862
957
basedir = log_store_xml_get_dir (self, account, target);
863
timestamp = g_strconcat (str, LOG_FILENAME_SUFFIX, NULL);
958
timestamp = g_strconcat (str, log_store_xml_get_file_suffix (type), NULL);
864
959
filename = g_build_filename (basedir, timestamp, NULL);
866
961
g_free (basedir);
1136
1231
gchar *target_id;
1137
1232
gchar *self_id;
1138
1233
GError *error = NULL;
1234
guint num_events = 0;
1140
g_return_val_if_fail (TPL_IS_LOG_STORE_XML (self), NULL);
1141
g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
1142
g_return_val_if_fail (!TPL_STR_EMPTY (filename), NULL);
1237
g_return_if_fail (TPL_IS_LOG_STORE_XML (self));
1238
g_return_if_fail (TP_IS_ACCOUNT (account));
1239
g_return_if_fail (!TPL_STR_EMPTY (filename));
1144
1241
DEBUG ("Attempting to parse filename:'%s'...", filename);
1146
1243
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
1148
1245
DEBUG ("Filename:'%s' does not exist", filename);
1152
1249
if (!tp_account_parse_object_path (
1198
1295
/* Now get the events. */
1296
index = events->head;
1199
1297
for (node = log_node->children; node; node = node->next)
1201
1299
TplEvent *event = NULL;
1203
if (type_mask & TPL_EVENT_MASK_TEXT
1301
if (type == TPL_TYPE_TEXT_EVENT
1204
1302
&& strcmp ((const gchar *) node->name, "message") == 0)
1205
1303
event = parse_text_node (self, node, is_room, target_id, self_id,
1207
else if (type_mask & TPL_EVENT_MASK_CALL
1305
else if (type == TPL_TYPE_CALL_EVENT
1208
1306
&& strcmp ((const char*) node->name, "call") == 0)
1209
1307
event = parse_call_node (self, node, is_room, target_id, self_id,
1212
1310
if (event != NULL)
1213
g_queue_push_tail (&events, event);
1312
while (index != NULL &&
1313
tpl_event_get_timestamp (event) <
1314
tpl_event_get_timestamp (TPL_EVENT (index->data)))
1315
index = g_list_next (index);
1319
g_queue_insert_after (events, index, event);
1320
index = g_list_next (index);
1324
g_queue_push_tail (events, event);
1325
index = events->head;
1216
DEBUG ("Parsed %d events", events.length);
1332
DEBUG ("Parsed %u events", num_events);
1218
1334
g_free (target_id);
1219
1335
xmlFreeDoc (doc);
1220
1336
xmlFreeParserCtxt (ctxt);
1227
1341
* Used to make possible the full search vs. specific subtrees search */
1229
1343
log_store_xml_get_all_files (TplLogStoreXml *self,
1233
1348
GList *files = NULL;
1234
1349
const gchar *name;
1235
1350
const gchar *basedir;
1237
1353
g_return_val_if_fail (TPL_IS_LOG_STORE_XML (self), NULL);
1238
1354
/* dir can be NULL, do not check */
1362
regex = log_store_xml_create_filename_regex (type_mask);
1246
1367
while ((name = g_dir_read_name (gdir)) != NULL)
1248
1369
gchar *filename;
1250
1371
filename = g_build_filename (basedir, name, NULL);
1251
if (g_str_has_suffix (filename, LOG_FILENAME_SUFFIX))
1253
files = g_list_prepend (files, filename);
1257
if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1373
if (g_regex_match (regex, name, 0, NULL))
1374
files = g_list_prepend (files, filename);
1375
else if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1259
1377
/* Recursively get all log files */
1260
1378
files = g_list_concat (files,
1261
log_store_xml_get_all_files (self,
1379
log_store_xml_get_all_files (self, filename, type_mask));
1268
1385
g_dir_close (gdir);
1388
g_regex_unref (regex);
1369
1489
g_return_val_if_fail (TPL_IS_LOG_STORE_XML (self), NULL);
1370
1490
g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL);
1372
files = log_store_xml_get_all_files (self, NULL);
1492
files = log_store_xml_get_all_files (self, NULL, type_mask);
1373
1493
DEBUG ("Found %d log files in total", g_list_length (files));
1375
1495
return _log_store_xml_search_in_files (self, text, files, type_mask);
1436
1556
TplLogStoreXml *self = (TplLogStoreXml *) store;
1437
1557
gchar *filename;
1558
GQueue events = G_QUEUE_INIT;
1440
1560
g_return_val_if_fail (TPL_IS_LOG_STORE_XML (self), NULL);
1441
1561
g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
1442
1562
g_return_val_if_fail (TPL_IS_ENTITY (target), NULL);
1443
1563
g_return_val_if_fail (date != NULL, NULL);
1445
filename = log_store_xml_get_filename_for_date (self, account, target,
1447
events = log_store_xml_get_events_for_file (self, account, filename, type_mask);
1565
if (type_mask & TPL_EVENT_MASK_TEXT)
1567
filename = log_store_xml_get_filename_for_date (self, account, target,
1568
date, TPL_TYPE_TEXT_EVENT);
1569
log_store_xml_get_events_for_file (self, account, filename,
1570
TPL_TYPE_TEXT_EVENT, &events);
1574
if (type_mask & TPL_EVENT_MASK_CALL)
1576
filename = log_store_xml_get_filename_for_date (self, account, target,
1577
date, TPL_TYPE_CALL_EVENT);
1578
log_store_xml_get_events_for_file (self, account, filename,
1579
TPL_TYPE_CALL_EVENT, &events);