Compare commits
6 Commits
master
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
| f63bf57872 | |||
| f16b26bd6d | |||
| a4e6419faf | |||
| 7eb9668068 | |||
| 7404e7092a | |||
| 62361676fe |
44
configure.ac
44
configure.ac
@@ -71,6 +71,10 @@ AC_ARG_ENABLE([omemo-qrcode],
|
|||||||
[AS_HELP_STRING([--enable-omemo-qrcode], [enable ability to display omemo qr code])])
|
[AS_HELP_STRING([--enable-omemo-qrcode], [enable ability to display omemo qr code])])
|
||||||
AC_ARG_ENABLE([coverage],
|
AC_ARG_ENABLE([coverage],
|
||||||
[AS_HELP_STRING([--enable-coverage], [enable code coverage analysis])])
|
[AS_HELP_STRING([--enable-coverage], [enable code coverage analysis])])
|
||||||
|
AC_ARG_ENABLE([sanitizers],
|
||||||
|
[AS_HELP_STRING([--enable-sanitizers], [enable AddressSanitizer + UndefinedBehaviorSanitizer + unsigned-integer-overflow])])
|
||||||
|
AC_ARG_ENABLE([hardening],
|
||||||
|
[AS_HELP_STRING([--enable-hardening], [enable extra hardening warnings (e.g. -Wnull-dereference) that may produce false positives under -O2])])
|
||||||
|
|
||||||
m4_include([m4/ax_valgrind_check.m4])
|
m4_include([m4/ax_valgrind_check.m4])
|
||||||
AX_VALGRIND_DFLT([drd], [off])
|
AX_VALGRIND_DFLT([drd], [off])
|
||||||
@@ -395,7 +399,7 @@ AC_SUBST([FORKPTY_LIB])
|
|||||||
|
|
||||||
## Default parameters
|
## Default parameters
|
||||||
AM_CFLAGS="$AM_CFLAGS -Wall -Wextra -Wformat=2 -Wno-format-zero-length"
|
AM_CFLAGS="$AM_CFLAGS -Wall -Wextra -Wformat=2 -Wno-format-zero-length"
|
||||||
AM_CFLAGS="$AM_CFLAGS -Wno-deprecated-declarations -Wno-unused-parameter -Wno-missing-field-initializers -Wno-sign-compare -Wno-cast-function-type"
|
AM_CFLAGS="$AM_CFLAGS -Wno-deprecated-declarations -Wno-unused-parameter -Wno-missing-field-initializers -Wno-cast-function-type"
|
||||||
AM_CFLAGS="$AM_CFLAGS -Wpointer-arith"
|
AM_CFLAGS="$AM_CFLAGS -Wpointer-arith"
|
||||||
AM_CFLAGS="$AM_CFLAGS -Wimplicit-function-declaration"
|
AM_CFLAGS="$AM_CFLAGS -Wimplicit-function-declaration"
|
||||||
AM_CFLAGS="$AM_CFLAGS -Wundef"
|
AM_CFLAGS="$AM_CFLAGS -Wundef"
|
||||||
@@ -406,7 +410,8 @@ AM_CFLAGS="$AM_CFLAGS -std=gnu99 -ggdb3"
|
|||||||
# GCC-specific warnings (not supported by clang) — test each one
|
# GCC-specific warnings (not supported by clang) — test each one
|
||||||
saved_CFLAGS="$CFLAGS"
|
saved_CFLAGS="$CFLAGS"
|
||||||
for _flag in -Wlogical-op -Wduplicated-cond -Wduplicated-branches \
|
for _flag in -Wlogical-op -Wduplicated-cond -Wduplicated-branches \
|
||||||
-Wstringop-overflow -Warray-bounds=2 -Walloc-zero; do
|
-Wstringop-overflow -Warray-bounds=2 -Walloc-zero \
|
||||||
|
-Wsign-compare; do
|
||||||
AC_MSG_CHECKING([whether $CC supports $_flag])
|
AC_MSG_CHECKING([whether $CC supports $_flag])
|
||||||
CFLAGS="$saved_CFLAGS $_flag -Werror"
|
CFLAGS="$saved_CFLAGS $_flag -Werror"
|
||||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
|
||||||
@@ -433,11 +438,46 @@ AS_IF([test "x$enable_coverage" = xyes],
|
|||||||
AM_LDFLAGS="$AM_LDFLAGS --coverage"
|
AM_LDFLAGS="$AM_LDFLAGS --coverage"
|
||||||
AC_MSG_NOTICE([Code coverage analysis enabled])])
|
AC_MSG_NOTICE([Code coverage analysis enabled])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_sanitizers" = xyes],
|
||||||
|
[SAN_FLAGS="-fsanitize=address,undefined"
|
||||||
|
saved_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$saved_CFLAGS -fsanitize=unsigned-integer-overflow -Werror"
|
||||||
|
AC_MSG_CHECKING([whether $CC supports -fsanitize=unsigned-integer-overflow])
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
|
||||||
|
[AC_MSG_RESULT([yes]); SAN_FLAGS="$SAN_FLAGS,unsigned-integer-overflow"],
|
||||||
|
[AC_MSG_RESULT([no])])
|
||||||
|
CFLAGS="$saved_CFLAGS"
|
||||||
|
AM_CFLAGS="$AM_CFLAGS $SAN_FLAGS -fno-sanitize-recover=all -fno-omit-frame-pointer"
|
||||||
|
AM_LDFLAGS="$AM_LDFLAGS -fsanitize=address,undefined"
|
||||||
|
AC_MSG_NOTICE([Sanitizers enabled: $SAN_FLAGS])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_hardening" = xyes],
|
||||||
|
[saved_CFLAGS="$CFLAGS"
|
||||||
|
for _flag in -Wnull-dereference; do
|
||||||
|
AC_MSG_CHECKING([whether $CC supports $_flag])
|
||||||
|
CFLAGS="$saved_CFLAGS $_flag -Werror"
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
|
||||||
|
[AC_MSG_RESULT([yes]); AM_CFLAGS="$AM_CFLAGS $_flag"],
|
||||||
|
[AC_MSG_RESULT([no])])
|
||||||
|
done
|
||||||
|
CFLAGS="$saved_CFLAGS"
|
||||||
|
AC_MSG_NOTICE([Extra hardening warnings enabled])])
|
||||||
|
|
||||||
|
# Skip _FORTIFY_SOURCE=2 if env already set one (Pikaur/makepkg) or under coverage -O0 (FORTIFY needs -O>0).
|
||||||
|
AS_IF([test "x$enable_coverage" != xyes],
|
||||||
|
[AS_CASE([" ${CPPFLAGS} ${CFLAGS} "],
|
||||||
|
[*_FORTIFY_SOURCE=*], [AC_MSG_NOTICE([_FORTIFY_SOURCE preset from environment, leaving as-is])],
|
||||||
|
[AM_CFLAGS="$AM_CFLAGS -D_FORTIFY_SOURCE=2"])])
|
||||||
|
|
||||||
AS_IF([test "x$PACKAGE_STATUS" = xdevelopment],
|
AS_IF([test "x$PACKAGE_STATUS" = xdevelopment],
|
||||||
[AM_CFLAGS="$AM_CFLAGS -Wunused -Werror"])
|
[AM_CFLAGS="$AM_CFLAGS -Wunused -Werror"])
|
||||||
AS_IF([test "x$PLATFORM" = xosx],
|
AS_IF([test "x$PLATFORM" = xosx],
|
||||||
[AM_CFLAGS="$AM_CFLAGS -Qunused-arguments"])
|
[AM_CFLAGS="$AM_CFLAGS -Qunused-arguments"])
|
||||||
|
|
||||||
|
# Treat glib/gio headers as system to keep their macros out of our -W* set.
|
||||||
|
glib_CFLAGS=$(echo "$glib_CFLAGS" | sed 's/-I/-isystem /g')
|
||||||
|
gio_CFLAGS=$(echo "$gio_CFLAGS" | sed 's/-I/-isystem /g')
|
||||||
|
|
||||||
AM_CFLAGS="$AM_CFLAGS $PTHREAD_CFLAGS $glib_CFLAGS $gio_CFLAGS $curl_CFLAGS ${SQLITE_CFLAGS}"
|
AM_CFLAGS="$AM_CFLAGS $PTHREAD_CFLAGS $glib_CFLAGS $gio_CFLAGS $curl_CFLAGS ${SQLITE_CFLAGS}"
|
||||||
AM_CFLAGS="$AM_CFLAGS $libnotify_CFLAGS ${GTK_CFLAGS} $python_CFLAGS"
|
AM_CFLAGS="$AM_CFLAGS $libnotify_CFLAGS ${GTK_CFLAGS} $python_CFLAGS"
|
||||||
AM_CFLAGS="$AM_CFLAGS -DTHEMES_PATH=\"\\\"$THEMES_PATH\\\"\" -DICONS_PATH=\"\\\"$ICONS_PATH\\\"\" -DGLOBAL_PYTHON_PLUGINS_PATH=\"\\\"$GLOBAL_PYTHON_PLUGINS_PATH\\\"\" -DGLOBAL_C_PLUGINS_PATH=\"\\\"$GLOBAL_C_PLUGINS_PATH\\\"\""
|
AM_CFLAGS="$AM_CFLAGS -DTHEMES_PATH=\"\\\"$THEMES_PATH\\\"\" -DICONS_PATH=\"\\\"$ICONS_PATH\\\"\" -DGLOBAL_PYTHON_PLUGINS_PATH=\"\\\"$GLOBAL_PYTHON_PLUGINS_PATH\\\"\" -DGLOBAL_C_PLUGINS_PATH=\"\\\"$GLOBAL_C_PLUGINS_PATH\\\"\""
|
||||||
|
|||||||
@@ -10063,8 +10063,14 @@ cmd_vcard_remove(ProfWin* window, const char* const command, gchar** args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args[1]) {
|
if (args[1]) {
|
||||||
vcard_user_remove_element(atoi(args[1]));
|
int index;
|
||||||
cons_show("Removed element at index %d", atoi(args[1]));
|
auto_gchar gchar* err_msg = NULL;
|
||||||
|
if (!strtoi_range(args[1], &index, 0, INT_MAX, &err_msg)) {
|
||||||
|
cons_show_error("%s", err_msg);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
vcard_user_remove_element((unsigned int)index);
|
||||||
|
cons_show("Removed element at index %d", index);
|
||||||
vcardwin_update();
|
vcardwin_update();
|
||||||
} else {
|
} else {
|
||||||
cons_bad_cmd_usage(command);
|
cons_bad_cmd_usage(command);
|
||||||
|
|||||||
26
src/common.c
26
src/common.c
@@ -294,7 +294,7 @@ str_replace(const char* string, const char* substr,
|
|||||||
wr = newstr;
|
wr = newstr;
|
||||||
|
|
||||||
while ((tok = strstr(head, substr))) {
|
while ((tok = strstr(head, substr))) {
|
||||||
size_t l = tok - head;
|
size_t l = g_diff_to_gsize(tok, head);
|
||||||
memcpy(wr, head, l);
|
memcpy(wr, head, l);
|
||||||
wr += l;
|
wr += l;
|
||||||
memcpy(wr, replacement, len_replacement);
|
memcpy(wr, replacement, len_replacement);
|
||||||
@@ -309,6 +309,16 @@ str_replace(const char* string, const char* substr,
|
|||||||
return newstr;
|
return newstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gsize
|
||||||
|
g_diff_to_gsize(const void* end, const void* start)
|
||||||
|
{
|
||||||
|
if (end < start) {
|
||||||
|
log_error("g_diff_to_gsize: end < start (%p < %p)", end, start);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (gsize)((const char*)end - (const char*)start);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
strtoi_range(const char* str, int* saveptr, int min, int max, gchar** err_msg)
|
strtoi_range(const char* str, int* saveptr, int min, int max, gchar** err_msg)
|
||||||
{
|
{
|
||||||
@@ -359,9 +369,9 @@ string_matches_one_of(const char* what, const char* is, gboolean is_can_be_null,
|
|||||||
char errmsg[256] = { 0 };
|
char errmsg[256] = { 0 };
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
int s = snprintf(errmsg, sizeof(errmsg) - sz, "%s must be one of:", what);
|
int s = snprintf(errmsg, sizeof(errmsg) - sz, "%s must be one of:", what);
|
||||||
if (s < 0 || s + sz >= sizeof(errmsg))
|
if (s < 0 || (size_t)s + sz >= sizeof(errmsg))
|
||||||
return ret;
|
return ret;
|
||||||
sz += s;
|
sz += (size_t)s;
|
||||||
|
|
||||||
cur = first;
|
cur = first;
|
||||||
va_start(ap, first);
|
va_start(ap, first);
|
||||||
@@ -375,12 +385,12 @@ string_matches_one_of(const char* what, const char* is, gboolean is_can_be_null,
|
|||||||
errmsg[sz] = '\0';
|
errmsg[sz] = '\0';
|
||||||
s = snprintf(errmsg + sz, sizeof(errmsg) - sz, " or '%s'.", cur);
|
s = snprintf(errmsg + sz, sizeof(errmsg) - sz, " or '%s'.", cur);
|
||||||
}
|
}
|
||||||
if (s < 0 || s + sz >= sizeof(errmsg)) {
|
if (s < 0 || (size_t)s + sz >= sizeof(errmsg)) {
|
||||||
log_debug("Error message too long or some other error occurred (%d).", s);
|
log_debug("Error message too long or some other error occurred (%d).", s);
|
||||||
s = -1;
|
s = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sz += s;
|
sz += (size_t)s;
|
||||||
cur = next;
|
cur = next;
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -431,7 +441,7 @@ str_xml_sanitize(const char* const str)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GString* sanitized = g_string_new_len(NULL, strlen(str));
|
GString* sanitized = g_string_new_len(NULL, (gssize)strlen(str));
|
||||||
const char* curr = str;
|
const char* curr = str;
|
||||||
|
|
||||||
while (*curr != '\0') {
|
while (*curr != '\0') {
|
||||||
@@ -690,7 +700,7 @@ get_file_paths_recursive(const char* path, GSList** contents)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gchar*
|
gchar*
|
||||||
get_random_string(int length)
|
get_random_string(size_t length)
|
||||||
{
|
{
|
||||||
GRand* prng;
|
GRand* prng;
|
||||||
gchar* rand;
|
gchar* rand;
|
||||||
@@ -701,7 +711,7 @@ get_random_string(int length)
|
|||||||
|
|
||||||
prng = g_rand_new();
|
prng = g_rand_new();
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; i++) {
|
||||||
rand[i] = alphabet[g_rand_int_range(prng, 0, endrange)];
|
rand[i] = alphabet[g_rand_int_range(prng, 0, endrange)];
|
||||||
}
|
}
|
||||||
g_rand_free(prng);
|
g_rand_free(prng);
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ gboolean create_dir(const char* name);
|
|||||||
gboolean copy_file(const char* const src, const char* const target, const gboolean overwrite_existing);
|
gboolean copy_file(const char* const src, const char* const target, const gboolean overwrite_existing);
|
||||||
char* str_replace(const char* string, const char* substr, const char* replacement);
|
char* str_replace(const char* string, const char* substr, const char* replacement);
|
||||||
gboolean strtoi_range(const char* str, int* saveptr, int min, int max, char** err_msg);
|
gboolean strtoi_range(const char* str, int* saveptr, int min, int max, char** err_msg);
|
||||||
|
gsize g_diff_to_gsize(const void* end, const void* start);
|
||||||
int utf8_display_len(const char* const str);
|
int utf8_display_len(const char* const str);
|
||||||
gchar* str_xml_sanitize(const char* const str);
|
gchar* str_xml_sanitize(const char* const str);
|
||||||
|
|
||||||
@@ -178,7 +179,7 @@ int is_regular_file(const char* path);
|
|||||||
int is_dir(const char* path);
|
int is_dir(const char* path);
|
||||||
void get_file_paths_recursive(const char* directory, GSList** contents);
|
void get_file_paths_recursive(const char* directory, GSList** contents);
|
||||||
|
|
||||||
gchar* get_random_string(int length);
|
gchar* get_random_string(size_t length);
|
||||||
|
|
||||||
gboolean call_external(gchar** argv);
|
gboolean call_external(gchar** argv);
|
||||||
gchar** format_call_external_argv(const char* template_fmt, const char* url, const char* filename);
|
gchar** format_call_external_argv(const char* template_fmt, const char* url, const char* filename);
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ _sanitize_account_name(const char* const name)
|
|||||||
gchar* sanitized = g_strdup(name);
|
gchar* sanitized = g_strdup(name);
|
||||||
gchar* p = sanitized;
|
gchar* p = sanitized;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
// GKeyFile special characters: [ ] = # \n \r
|
// GKeyFile group header forbids these characters.
|
||||||
if (*p == '[' || *p == ']' || *p == '=' || *p == '#' || *p == '\n' || *p == '\r') {
|
if (*p == '[' || *p == ']' || *p == '\n' || *p == '\r') {
|
||||||
*p = '_';
|
*p = '_';
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ _export_one_contact(const char* contact)
|
|||||||
gchar* key = _make_dedup_key(pl->stanza_id, pl->timestamp_str, pl->from_jid, pl->message);
|
gchar* key = _make_dedup_key(pl->stanza_id, pl->timestamp_str, pl->from_jid, pl->message);
|
||||||
g_hash_table_add(seen_keys, key);
|
g_hash_table_add(seen_keys, key);
|
||||||
}
|
}
|
||||||
int existing_count = g_slist_length(existing);
|
int existing_count = (int)g_slist_length(existing);
|
||||||
|
|
||||||
// 2. Query SQLite for this contact — get ALL messages via direct SQL
|
// 2. Query SQLite for this contact — get ALL messages via direct SQL
|
||||||
GSList* sqlite_lines = db_sqlite_get_all_chat(contact);
|
GSList* sqlite_lines = db_sqlite_get_all_chat(contact);
|
||||||
@@ -581,7 +581,7 @@ log_database_import_from_flatfile(const gchar* const contact_jid)
|
|||||||
// Wrap in a transaction for atomicity and performance
|
// Wrap in a transaction for atomicity and performance
|
||||||
int contact_imported = 0;
|
int contact_imported = 0;
|
||||||
int contact_skipped = 0;
|
int contact_skipped = 0;
|
||||||
int total_lines = g_slist_length(ff_lines);
|
int total_lines = (int)g_slist_length(ff_lines);
|
||||||
|
|
||||||
db_sqlite_begin_transaction();
|
db_sqlite_begin_transaction();
|
||||||
gboolean import_ok = TRUE;
|
gboolean import_ok = TRUE;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ _ff_cache_line_ids(ff_contact_state_t* state, const char* line)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Split metadata on unescaped '|'
|
// Split metadata on unescaped '|'
|
||||||
auto_gchar gchar* meta_str = g_strndup(bracket + 1, close - bracket - 1);
|
auto_gchar gchar* meta_str = g_strndup(bracket + 1, g_diff_to_gsize(close, bracket + 1));
|
||||||
char** parts = ff_split_meta(meta_str);
|
char** parts = ff_split_meta(meta_str);
|
||||||
|
|
||||||
char* stanza_id = NULL;
|
char* stanza_id = NULL;
|
||||||
@@ -111,9 +111,9 @@ _ff_cache_line_ids(ff_contact_state_t* state, const char* line)
|
|||||||
const char* sender_start = close + 2;
|
const char* sender_start = close + 2;
|
||||||
const char* colonspace = ff_find_unescaped_colonspace(sender_start);
|
const char* colonspace = ff_find_unescaped_colonspace(sender_start);
|
||||||
if (colonspace) {
|
if (colonspace) {
|
||||||
const char* slash = memchr(sender_start, '/', colonspace - sender_start);
|
const char* slash = memchr(sender_start, '/', g_diff_to_gsize(colonspace, sender_start));
|
||||||
const char* jid_end = slash ? slash : colonspace;
|
const char* jid_end = slash ? slash : colonspace;
|
||||||
from_jid = g_strndup(sender_start, jid_end - sender_start);
|
from_jid = g_strndup(sender_start, g_diff_to_gsize(jid_end, sender_start));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ _ff_maybe_index_line(ff_contact_state_t* state, const char* buf, off_t pos)
|
|||||||
if (!space)
|
if (!space)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto_gchar gchar* ts_str = g_strndup(buf, space - buf);
|
auto_gchar gchar* ts_str = g_strndup(buf, g_diff_to_gsize(space, buf));
|
||||||
GDateTime* dt = g_date_time_new_from_iso8601(ts_str, NULL);
|
GDateTime* dt = g_date_time_new_from_iso8601(ts_str, NULL);
|
||||||
if (!dt) {
|
if (!dt) {
|
||||||
log_warning("flatfile: unparsable timestamp in %s at offset %ld: %s",
|
log_warning("flatfile: unparsable timestamp in %s at offset %ld: %s",
|
||||||
@@ -771,7 +771,7 @@ _flatfile_get_previous_chat(const gchar* const contact_barejid, const gchar* sta
|
|||||||
|
|
||||||
// For "last N messages": back up from read_to using index
|
// For "last N messages": back up from read_to using index
|
||||||
if (!from_start) {
|
if (!from_start) {
|
||||||
int margin_entries = (MESSAGES_TO_RETRIEVE * 3) / FF_INDEX_STEP + 2;
|
size_t margin_entries = (MESSAGES_TO_RETRIEVE * 3) / FF_INDEX_STEP + 2;
|
||||||
|
|
||||||
// Find index entry closest to (but before) read_to
|
// Find index entry closest to (but before) read_to
|
||||||
size_t entry_idx = 0;
|
size_t entry_idx = 0;
|
||||||
@@ -781,7 +781,7 @@ _flatfile_get_previous_chat(const gchar* const contact_barejid, const gchar* sta
|
|||||||
entry_idx = i;
|
entry_idx = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t start_entry = entry_idx > (size_t)margin_entries
|
size_t start_entry = entry_idx > margin_entries
|
||||||
? entry_idx - margin_entries
|
? entry_idx - margin_entries
|
||||||
: 0;
|
: 0;
|
||||||
off_t backed = state->entries[start_entry].byte_offset;
|
off_t backed = state->entries[start_entry].byte_offset;
|
||||||
|
|||||||
@@ -553,7 +553,7 @@ ff_split_meta(const char* meta)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*p == '|' || *p == '\0') {
|
if (*p == '|' || *p == '\0') {
|
||||||
g_ptr_array_add(arr, g_strndup(start, p - start));
|
g_ptr_array_add(arr, g_strndup(start, g_diff_to_gsize(p, start)));
|
||||||
if (*p == '\0')
|
if (*p == '\0')
|
||||||
break;
|
break;
|
||||||
start = p + 1;
|
start = p + 1;
|
||||||
@@ -710,7 +710,7 @@ ff_parse_line(const char* line)
|
|||||||
|
|
||||||
if (bracket_start && first_space && first_space < bracket_start) {
|
if (bracket_start && first_space && first_space < bracket_start) {
|
||||||
// Standard format with metadata: {timestamp} [{meta}] {sender}: {msg}
|
// Standard format with metadata: {timestamp} [{meta}] {sender}: {msg}
|
||||||
result->timestamp_str = g_strndup(work, first_space - work);
|
result->timestamp_str = g_strndup(work, g_diff_to_gsize(first_space, work));
|
||||||
|
|
||||||
// Parse metadata section [...]
|
// Parse metadata section [...]
|
||||||
const char* bracket_end = ff_find_unescaped_char(bracket_start + 1, ']');
|
const char* bracket_end = ff_find_unescaped_char(bracket_start + 1, ']');
|
||||||
@@ -721,7 +721,7 @@ ff_parse_line(const char* line)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_gchar gchar* meta_content = g_strndup(bracket_start + 1, bracket_end - bracket_start - 1);
|
auto_gchar gchar* meta_content = g_strndup(bracket_start + 1, g_diff_to_gsize(bracket_end, bracket_start + 1));
|
||||||
char** parts = ff_split_meta(meta_content);
|
char** parts = ff_split_meta(meta_content);
|
||||||
if (parts) {
|
if (parts) {
|
||||||
_ff_parse_meta_parts(parts, result);
|
_ff_parse_meta_parts(parts, result);
|
||||||
@@ -736,12 +736,12 @@ ff_parse_line(const char* line)
|
|||||||
// Find first *unescaped* ': ' which separates sender from message.
|
// Find first *unescaped* ': ' which separates sender from message.
|
||||||
const char* colon = ff_find_unescaped_colonspace(after_meta);
|
const char* colon = ff_find_unescaped_colonspace(after_meta);
|
||||||
if (colon) {
|
if (colon) {
|
||||||
auto_gchar gchar* raw_sender = g_strndup(after_meta, colon - after_meta);
|
auto_gchar gchar* raw_sender = g_strndup(after_meta, g_diff_to_gsize(colon, after_meta));
|
||||||
|
|
||||||
// Split sender into jid/resource, then unescape resource
|
// Split sender into jid/resource, then unescape resource
|
||||||
char* slash = strchr(raw_sender, '/');
|
char* slash = strchr(raw_sender, '/');
|
||||||
if (slash) {
|
if (slash) {
|
||||||
result->from_jid = g_strndup(raw_sender, slash - raw_sender);
|
result->from_jid = g_strndup(raw_sender, g_diff_to_gsize(slash, raw_sender));
|
||||||
result->from_resource = ff_unescape_sender_resource(slash + 1);
|
result->from_resource = ff_unescape_sender_resource(slash + 1);
|
||||||
} else {
|
} else {
|
||||||
result->from_jid = g_strdup(raw_sender);
|
result->from_jid = g_strdup(raw_sender);
|
||||||
@@ -755,7 +755,7 @@ ff_parse_line(const char* line)
|
|||||||
}
|
}
|
||||||
} else if (first_space) {
|
} else if (first_space) {
|
||||||
// Legacy/simple format without metadata: {timestamp} - {sender}: {msg}
|
// Legacy/simple format without metadata: {timestamp} - {sender}: {msg}
|
||||||
result->timestamp_str = g_strndup(work, first_space - work);
|
result->timestamp_str = g_strndup(work, g_diff_to_gsize(first_space, work));
|
||||||
result->type = g_strdup("chat");
|
result->type = g_strdup("chat");
|
||||||
result->enc = g_strdup("none");
|
result->enc = g_strdup("none");
|
||||||
|
|
||||||
@@ -767,10 +767,10 @@ ff_parse_line(const char* line)
|
|||||||
|
|
||||||
char* colon = strstr(rest, ": ");
|
char* colon = strstr(rest, ": ");
|
||||||
if (colon) {
|
if (colon) {
|
||||||
char* sender = g_strndup(rest, colon - rest);
|
char* sender = g_strndup(rest, g_diff_to_gsize(colon, rest));
|
||||||
char* slash = strchr(sender, '/');
|
char* slash = strchr(sender, '/');
|
||||||
if (slash) {
|
if (slash) {
|
||||||
result->from_jid = g_strndup(sender, slash - sender);
|
result->from_jid = g_strndup(sender, g_diff_to_gsize(slash, sender));
|
||||||
result->from_resource = g_strdup(slash + 1);
|
result->from_resource = g_strdup(slash + 1);
|
||||||
} else {
|
} else {
|
||||||
result->from_jid = g_strdup(sender);
|
result->from_jid = g_strdup(sender);
|
||||||
|
|||||||
@@ -260,7 +260,12 @@ omemo_on_connect(ProfAccount* account)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_omemo_finalize_identity_load(account);
|
if (!_omemo_finalize_identity_load(account)) {
|
||||||
|
omemo_ctx.loaded = FALSE;
|
||||||
|
log_error("[OMEMO] failed to load OMEMO state from disk for %s", account->jid);
|
||||||
|
cons_show_error("OMEMO: could not load encryption state from disk; OMEMO will be unavailable this session.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wins_omemo_trust_changed(NULL);
|
wins_omemo_trust_changed(NULL);
|
||||||
}
|
}
|
||||||
@@ -1278,8 +1283,12 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint)
|
|||||||
.device_id = GPOINTER_TO_UINT(device_id),
|
.device_id = GPOINTER_TO_UINT(device_id),
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t fingerprint_len;
|
size_t fingerprint_len = 0;
|
||||||
unsigned char* fingerprint_raw = _omemo_fingerprint_decode(fingerprint, &fingerprint_len);
|
unsigned char* fingerprint_raw = _omemo_fingerprint_decode(fingerprint, &fingerprint_len);
|
||||||
|
if (!fingerprint_raw) {
|
||||||
|
log_error("[OMEMO] omemo_is_trusted_identity: failed to decode fingerprint for %s", jid);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
unsigned char djb_type[] = { '\x05' };
|
unsigned char djb_type[] = { '\x05' };
|
||||||
signal_buffer* buffer = signal_buffer_create(djb_type, 1);
|
signal_buffer* buffer = signal_buffer_create(djb_type, 1);
|
||||||
buffer = signal_buffer_append(buffer, fingerprint_raw, fingerprint_len);
|
buffer = signal_buffer_append(buffer, fingerprint_raw, fingerprint_len);
|
||||||
@@ -1463,6 +1472,10 @@ _omemo_fingerprint(ec_public_key* identity, gboolean formatted)
|
|||||||
static unsigned char*
|
static unsigned char*
|
||||||
_omemo_fingerprint_decode(const char* const fingerprint, size_t* len)
|
_omemo_fingerprint_decode(const char* const fingerprint, size_t* len)
|
||||||
{
|
{
|
||||||
|
if (!fingerprint) {
|
||||||
|
*len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
unsigned char* output = malloc(strlen(fingerprint) / 2 + 1);
|
unsigned char* output = malloc(strlen(fingerprint) / 2 + 1);
|
||||||
if (!output) {
|
if (!output) {
|
||||||
*len = 0;
|
*len = 0;
|
||||||
@@ -1529,6 +1542,11 @@ omemo_trust(const char* const jid, const char* const fingerprint_formatted)
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsigned char* fingerprint_raw = _omemo_fingerprint_decode(fingerprint_formatted, &len);
|
unsigned char* fingerprint_raw = _omemo_fingerprint_decode(fingerprint_formatted, &len);
|
||||||
|
if (!fingerprint_raw) {
|
||||||
|
log_error("[OMEMO] omemo_trust: failed to decode fingerprint for %s", jid);
|
||||||
|
cons_show_error("Failed to trust device: could not decode fingerprint.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
unsigned char djb_type[] = { '\x05' };
|
unsigned char djb_type[] = { '\x05' };
|
||||||
signal_buffer* buffer = signal_buffer_create(djb_type, 1);
|
signal_buffer* buffer = signal_buffer_create(djb_type, 1);
|
||||||
buffer = signal_buffer_append(buffer, fingerprint_raw, len);
|
buffer = signal_buffer_append(buffer, fingerprint_raw, len);
|
||||||
@@ -1546,8 +1564,10 @@ omemo_untrust(const char* const jid, const char* const fingerprint_formatted)
|
|||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char* identity = _omemo_fingerprint_decode(fingerprint_formatted, &len);
|
unsigned char* identity = _omemo_fingerprint_decode(fingerprint_formatted, &len);
|
||||||
if (!identity)
|
if (!identity) {
|
||||||
|
log_error("[OMEMO] omemo_untrust: failed to decode fingerprint for %s", jid);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
gpointer key, value;
|
gpointer key, value;
|
||||||
|
|||||||
@@ -278,7 +278,8 @@ otr_on_message_recv(const char* const barejid, const char* const resource, const
|
|||||||
if (strstr(message, OTRL_MESSAGE_TAG_V2) && strstr(message, OTRL_MESSAGE_TAG_V1)) {
|
if (strstr(message, OTRL_MESSAGE_TAG_V2) && strstr(message, OTRL_MESSAGE_TAG_V1)) {
|
||||||
tag_length = 32;
|
tag_length = 32;
|
||||||
}
|
}
|
||||||
memmove(whitespace_base, whitespace_base + tag_length, tag_length);
|
// Move the rest of the message (with NUL) over the tag.
|
||||||
|
memmove(whitespace_base, whitespace_base + tag_length, strlen(whitespace_base + tag_length) + 1);
|
||||||
char* otr_query_message = otr_start_query();
|
char* otr_query_message = otr_start_query();
|
||||||
cons_show("OTR Whitespace pattern detected. Attempting to start OTR session…");
|
cons_show("OTR Whitespace pattern detected. Attempting to start OTR session…");
|
||||||
free(message_send_chat_otr(barejid, otr_query_message, FALSE, NULL));
|
free(message_send_chat_otr(barejid, otr_query_message, FALSE, NULL));
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_f
|
|||||||
* so we can be sure there's runtime left after executing
|
* so we can be sure there's runtime left after executing
|
||||||
* the last command.
|
* the last command.
|
||||||
*/
|
*/
|
||||||
min_runtime += waittime;
|
min_runtime += (unsigned int)waittime;
|
||||||
} else {
|
} else {
|
||||||
log_error("%s", err_msg);
|
log_error("%s", err_msg);
|
||||||
g_free(err_msg);
|
g_free(err_msg);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ jid_is_valid(const gchar* const str)
|
|||||||
|
|
||||||
// Localpart validation
|
// Localpart validation
|
||||||
if (at) {
|
if (at) {
|
||||||
size_t local_len = at - str;
|
size_t local_len = g_diff_to_gsize(at, str);
|
||||||
if (local_len == 0 || local_len > JID_MAX_PART_LEN) {
|
if (local_len == 0 || local_len > JID_MAX_PART_LEN) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ jid_is_valid(const gchar* const str)
|
|||||||
|
|
||||||
// Resourcepart validation if present
|
// Resourcepart validation if present
|
||||||
if (slash) {
|
if (slash) {
|
||||||
domain_len = slash - domain_start;
|
domain_len = g_diff_to_gsize(slash, domain_start);
|
||||||
size_t resource_len = strlen(slash + 1);
|
size_t resource_len = strlen(slash + 1);
|
||||||
if (resource_len > JID_MAX_PART_LEN) {
|
if (resource_len > JID_MAX_PART_LEN) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ static void _handle_pubsub(xmpp_stanza_t* const stanza, xmpp_stanza_t* const eve
|
|||||||
static gboolean _handle_form(xmpp_stanza_t* const stanza);
|
static gboolean _handle_form(xmpp_stanza_t* const stanza);
|
||||||
static gboolean _handle_jingle_message(xmpp_stanza_t* const stanza);
|
static gboolean _handle_jingle_message(xmpp_stanza_t* const stanza);
|
||||||
static gboolean _should_ignore_based_on_silence(xmpp_stanza_t* const stanza);
|
static gboolean _should_ignore_based_on_silence(xmpp_stanza_t* const stanza);
|
||||||
|
static gboolean _stanza_id_by_trusted(const char* by);
|
||||||
#ifdef HAVE_OMEMO
|
#ifdef HAVE_OMEMO
|
||||||
static void _receive_omemo(xmpp_stanza_t* const stanza, ProfMessage* message);
|
static void _receive_omemo(xmpp_stanza_t* const stanza, ProfMessage* message);
|
||||||
#endif
|
#endif
|
||||||
@@ -1088,7 +1089,7 @@ _handle_groupchat(xmpp_stanza_t* const stanza)
|
|||||||
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
||||||
if (stanzaidst) {
|
if (stanzaidst) {
|
||||||
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
||||||
if (by && (g_strcmp0(by, from_jid->barejid) == 0)) {
|
if (by && g_strcmp0(by, from_jid->barejid) == 0 && _stanza_id_by_trusted(by)) {
|
||||||
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
||||||
if (stanzaid) {
|
if (stanzaid) {
|
||||||
message->stanzaid = strdup(stanzaid);
|
message->stanzaid = strdup(stanzaid);
|
||||||
@@ -1397,7 +1398,7 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c
|
|||||||
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
||||||
if (stanzaidst) {
|
if (stanzaidst) {
|
||||||
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
||||||
if (by && equals_our_barejid(by)) {
|
if (by && equals_our_barejid(by) && _stanza_id_by_trusted(by)) {
|
||||||
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
||||||
if (stanzaid) {
|
if (stanzaid) {
|
||||||
message->stanzaid = strdup(stanzaid);
|
message->stanzaid = strdup(stanzaid);
|
||||||
@@ -1735,3 +1736,22 @@ _should_ignore_based_on_silence(xmpp_stanza_t* const stanza)
|
|||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XEP-0359 §6 disco-gate; falls back to domain since that's what disco is run against.
|
||||||
|
static gboolean
|
||||||
|
_stanza_id_by_trusted(const char* by)
|
||||||
|
{
|
||||||
|
if (!by) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
GHashTable* features = connection_get_features(by);
|
||||||
|
if (features && g_hash_table_contains(features, STANZA_NS_STABLE_ID)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
const char* at = strchr(by, '@');
|
||||||
|
if (!at) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
features = connection_get_features(at + 1);
|
||||||
|
return features && g_hash_table_contains(features, STANZA_NS_STABLE_ID);
|
||||||
|
}
|
||||||
|
|||||||
@@ -707,7 +707,7 @@ muc_autocomplete(ProfWin* window, const char* const input, gboolean previous)
|
|||||||
} else {
|
} else {
|
||||||
search_str = last_space + 1;
|
search_str = last_space + 1;
|
||||||
if (!chat_room->autocomplete_prefix) {
|
if (!chat_room->autocomplete_prefix) {
|
||||||
chat_room->autocomplete_prefix = g_strndup(input, search_str - input);
|
chat_room->autocomplete_prefix = g_strndup(input, g_diff_to_gsize(search_str, input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -621,15 +621,20 @@ _available_handler(xmpp_stanza_t* const stanza)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (g_strcmp0(xmpp_presence->jid->barejid, my_jid->barejid) == 0) {
|
if (g_strcmp0(xmpp_presence->jid->barejid, my_jid->barejid) == 0) {
|
||||||
connection_add_available_resource(resource);
|
// Copy what we read before connection_add_available_resource() takes ownership.
|
||||||
Resource* resource_for_roster = resource_copy(resource);
|
Resource* resource_for_roster = resource_copy(resource);
|
||||||
|
auto_gchar gchar* resource_name = g_strdup(resource->name);
|
||||||
|
auto_gchar gchar* resource_status = resource->status ? g_strdup(resource->status) : NULL;
|
||||||
|
int resource_priority = resource->priority;
|
||||||
|
resource_presence_t resource_presence = resource->presence;
|
||||||
|
connection_add_available_resource(resource);
|
||||||
sv_ev_contact_online(xmpp_presence->jid->barejid, resource_for_roster, xmpp_presence->last_activity, pgpsig);
|
sv_ev_contact_online(xmpp_presence->jid->barejid, resource_for_roster, xmpp_presence->last_activity, pgpsig);
|
||||||
const char* account_name = session_get_account_name();
|
const char* account_name = session_get_account_name();
|
||||||
int max_sessions = accounts_get_max_sessions(account_name);
|
int max_sessions = accounts_get_max_sessions(account_name);
|
||||||
if (max_sessions > 0) {
|
if (max_sessions > 0) {
|
||||||
auto_gchar gchar* cur_resource = accounts_get_resource(account_name);
|
auto_gchar gchar* cur_resource = accounts_get_resource(account_name);
|
||||||
int res_count = connection_count_available_resources();
|
int res_count = connection_count_available_resources();
|
||||||
if (res_count > max_sessions && g_strcmp0(cur_resource, resource->name)) {
|
if (res_count > max_sessions && g_strcmp0(cur_resource, resource_name)) {
|
||||||
ProfWin* console = wins_get_console();
|
ProfWin* console = wins_get_console();
|
||||||
ProfWin* current_window = wins_get_current();
|
ProfWin* current_window = wins_get_current();
|
||||||
auto_gchar gchar* message = g_strdup_printf("Max sessions alarm! (%d/%d devices in use)", res_count, max_sessions);
|
auto_gchar gchar* message = g_strdup_printf("Max sessions alarm! (%d/%d devices in use)", res_count, max_sessions);
|
||||||
@@ -639,14 +644,14 @@ _available_handler(xmpp_stanza_t* const stanza)
|
|||||||
}
|
}
|
||||||
notify(message, 10000, "Security alert");
|
notify(message, 10000, "Security alert");
|
||||||
|
|
||||||
const char* resource_presence = string_from_resource_presence(resource->presence);
|
const char* resource_presence_str = string_from_resource_presence(resource_presence);
|
||||||
win_print(console, THEME_DEFAULT, "|", "New device info: \n %s (%d), %s", resource->name, resource->priority, resource_presence);
|
win_print(console, THEME_DEFAULT, "|", "New device info: \n %s (%d), %s", resource_name, resource_priority, resource_presence_str);
|
||||||
|
|
||||||
if (resource->status) {
|
if (resource_status) {
|
||||||
win_append(console, THEME_DEFAULT, ", \"%s\"", resource->status);
|
win_append(console, THEME_DEFAULT, ", \"%s\"", resource_status);
|
||||||
}
|
}
|
||||||
win_appendln(console, THEME_DEFAULT, "");
|
win_appendln(console, THEME_DEFAULT, "");
|
||||||
auto_jid Jid* jidp = jid_create_from_bare_and_resource(my_jid->barejid, resource->name);
|
auto_jid Jid* jidp = jid_create_from_bare_and_resource(my_jid->barejid, resource_name);
|
||||||
EntityCapabilities* caps = caps_lookup(jidp->fulljid);
|
EntityCapabilities* caps = caps_lookup(jidp->fulljid);
|
||||||
|
|
||||||
if (caps) {
|
if (caps) {
|
||||||
|
|||||||
@@ -253,6 +253,10 @@ main(int argc, char* argv[])
|
|||||||
PROF_FUNC_TEST(message_receive_console),
|
PROF_FUNC_TEST(message_receive_console),
|
||||||
PROF_FUNC_TEST(message_receive_chatwin),
|
PROF_FUNC_TEST(message_receive_chatwin),
|
||||||
|
|
||||||
|
/* XEP-0359 disco gate for stanza-id trust */
|
||||||
|
PROF_FUNC_TEST(stanza_id_dedup_fires_when_server_announces_sid0),
|
||||||
|
PROF_FUNC_TEST(stanza_id_not_trusted_when_server_does_not_announce_sid0),
|
||||||
|
|
||||||
#ifdef HAVE_SQLITE
|
#ifdef HAVE_SQLITE
|
||||||
/* MUC (groupchat) database — export/import of type="muc" messages */
|
/* MUC (groupchat) database — export/import of type="muc" messages */
|
||||||
PROF_FUNC_TEST(muc_export_sqlite_to_flatfile),
|
PROF_FUNC_TEST(muc_export_sqlite_to_flatfile),
|
||||||
|
|||||||
@@ -119,10 +119,9 @@ _create_dir(const char* name)
|
|||||||
gboolean
|
gboolean
|
||||||
_mkdir_recursive(const char* dir)
|
_mkdir_recursive(const char* dir)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
gboolean result = TRUE;
|
gboolean result = TRUE;
|
||||||
|
|
||||||
for (i = 1; i <= strlen(dir); i++) {
|
for (size_t i = 1; i <= strlen(dir); i++) {
|
||||||
if (dir[i] == '/' || dir[i] == '\0') {
|
if (dir[i] == '/' || dir[i] == '\0') {
|
||||||
gchar* next_dir = g_strndup(dir, i);
|
gchar* next_dir = g_strndup(dir, i);
|
||||||
result = _create_dir(next_dir);
|
result = _create_dir(next_dir);
|
||||||
|
|||||||
@@ -56,3 +56,70 @@ message_receive_chatwin(void **state)
|
|||||||
|
|
||||||
assert_true(prof_output_regex("someuser@chatserv.org/laptop: .+How are you?"));
|
assert_true(prof_output_regex("someuser@chatserv.org/laptop: .+How are you?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XEP-0359 disco gate: server announces urn:xmpp:sid:0 -> stanza-id trusted -> replay flagged as duplicate.
|
||||||
|
void
|
||||||
|
stanza_id_dedup_fires_when_server_announces_sid0(void **state)
|
||||||
|
{
|
||||||
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
||||||
|
"<iq type='result' to='stabber@localhost/profanity' from='localhost'>"
|
||||||
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
||||||
|
"<identity category='server' type='im' name='TestServer'/>"
|
||||||
|
"<feature var='urn:xmpp:sid:0'/>"
|
||||||
|
"</query>"
|
||||||
|
"</iq>"
|
||||||
|
);
|
||||||
|
|
||||||
|
prof_connect();
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-trust-1' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>first</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-42'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
assert_true(prof_output_exact("<< chat message: someuser@chatserv.org/laptop (win 2)"));
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-trust-2' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>replay</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-42'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
assert_true(prof_output_exact("Got a message with duplicate (server-generated) stanza-id from someuser@chatserv.org/laptop."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// XEP-0359 disco gate: server does NOT announce urn:xmpp:sid:0 -> stanza-id untrusted -> no replay error.
|
||||||
|
void
|
||||||
|
stanza_id_not_trusted_when_server_does_not_announce_sid0(void **state)
|
||||||
|
{
|
||||||
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
||||||
|
"<iq type='result' to='stabber@localhost/profanity' from='localhost'>"
|
||||||
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
||||||
|
"<identity category='server' type='im' name='TestServer'/>"
|
||||||
|
"<feature var='urn:xmpp:ping'/>"
|
||||||
|
"</query>"
|
||||||
|
"</iq>"
|
||||||
|
);
|
||||||
|
|
||||||
|
prof_connect();
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-untrust-1' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>first</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-77'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
assert_true(prof_output_exact("<< chat message: someuser@chatserv.org/laptop (win 2)"));
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-untrust-2' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>replay</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-77'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
|
||||||
|
prof_timeout(2);
|
||||||
|
assert_false(prof_output_exact("Got a message with duplicate (server-generated) stanza-id"));
|
||||||
|
prof_timeout_reset();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
void message_send(void **state);
|
void message_send(void **state);
|
||||||
void message_receive_console(void **state);
|
void message_receive_console(void **state);
|
||||||
void message_receive_chatwin(void **state);
|
void message_receive_chatwin(void **state);
|
||||||
|
void stanza_id_dedup_fires_when_server_announces_sid0(void **state);
|
||||||
|
void stanza_id_not_trusted_when_server_does_not_announce_sid0(void **state);
|
||||||
|
|||||||
Reference in New Issue
Block a user