Use regex to detect hypertext links in the chat history

That fix performance issue when diplaying comlex
messages in the chat history as XML text or
base64-encoded binary message
This commit is contained in:
François Grisez 2015-10-04 19:48:00 +02:00
parent 1f394e8622
commit 3715308ded
3 changed files with 52 additions and 38 deletions

View file

@ -139,35 +139,13 @@ static gboolean scroll_to_end(GtkTextView *w){
return FALSE;
}
static gboolean word_starts_with(const GtkTextIter *word_start, const char *prefix) {
gboolean res;
gchar *schema = NULL;
GtkTextIter end = *word_start;
gtk_text_iter_forward_chars(&end, strlen(prefix));
schema = gtk_text_iter_get_slice(word_start, &end);
res = ( g_strcmp0(schema, prefix) == 0 );
g_free(schema);
return res;
}
static gboolean is_space(gunichar ch, gpointer user_data) {
return g_unichar_isspace(ch);
}
static void insert_link_tags(GtkTextBuffer *buffer, const GtkTextIter *begin, const GtkTextIter *end) {
GtkTextIter iter = *begin;
while(gtk_text_iter_compare(&iter, end) < 0) {
if(gtk_text_iter_starts_word(&iter) && (
word_starts_with(&iter, "http://") ||
word_starts_with(&iter, "https://") ||
word_starts_with(&iter, "ftp://") ||
word_starts_with(&iter, "ftps://"))) {
GtkTextIter uri_begin = iter;
if(gtk_text_iter_forward_find_char(&iter, is_space, NULL, end)) {
gtk_text_buffer_apply_tag_by_name(buffer, "link", &uri_begin, &iter);
}
}
gtk_text_iter_forward_char(&iter);
static void write_body(GtkTextBuffer *buffer, GtkTextIter *iter, const gchar *text, gint len, gboolean is_me, gboolean is_link) {
const char *me_tag_name = is_me ? "me" : NULL;
const char *link_tag_name = is_link ? "link" : NULL;
if(me_tag_name) {
gtk_text_buffer_insert_with_tags_by_name(buffer, iter, text, len, "body", me_tag_name, link_tag_name, NULL);
} else {
gtk_text_buffer_insert_with_tags_by_name(buffer, iter, text, len, "body", link_tag_name, NULL);
}
}
@ -175,11 +153,13 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
gboolean me,LinphoneChatRoom *cr,LinphoneChatMessage *msg, gboolean hist){
GtkTextView *text=GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textview"));
GtkTextBuffer *buffer=gtk_text_view_get_buffer(text);
GtkTextIter iter, link_start;
GtkTextMark *link_start_mark = NULL;
GtkTextIter iter;
char *from_str=linphone_address_as_string_uri_only(from);
gchar *from_message=(gchar *)g_object_get_data(G_OBJECT(w),"from_message");
GHashTable *table=(GHashTable*)g_object_get_data(G_OBJECT(w),"table");
const GRegex *uri_regex = linphone_gtk_get_uri_regex();
GMatchInfo *match_info = NULL;
const char *message = linphone_chat_message_get_text(msg);
time_t t;
char buf[80];
time_t tnow;
@ -199,14 +179,21 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from,
}
ms_free(from_str);
link_start_mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE);
gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, linphone_chat_message_get_text(msg), -1,
"body", me ? "me" : NULL, NULL);
// Inserts message body and tags URIs as hypertext links
if(g_regex_match(uri_regex, message, 0, &match_info)) {
int pos = 0, start, end;
do {
g_match_info_fetch_pos(match_info, 0, &start, &end);
if(pos < start) write_body(buffer, &iter, &message[pos], start-pos, me, FALSE);
write_body(buffer, &iter, &message[start], end-start, me, TRUE);
pos = end;
} while(g_match_info_next(match_info, NULL));
} else {
write_body(buffer, &iter, message, -1, me, FALSE);
}
gtk_text_buffer_insert(buffer,&iter,"\n",-1);
gtk_text_buffer_get_iter_at_mark(buffer, &link_start, link_start_mark);
insert_link_tags(buffer, &link_start, &iter);
gtk_text_buffer_delete_mark(buffer, link_start_mark);
g_match_info_free(match_info);
t=linphone_chat_message_get_time(msg);
switch (linphone_chat_message_get_state (msg)){
case LinphoneChatMessageStateInProgress:

View file

@ -341,3 +341,9 @@ LINPHONE_PUBLIC void linphone_gtk_tunnel_ok(GtkButton *button);
LINPHONE_PUBLIC void linphone_gtk_notebook_current_page_changed(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data);
LINPHONE_PUBLIC void linphone_gtk_reload_sound_devices(void);
LINPHONE_PUBLIC void linphone_gtk_reload_video_devices(void);
/**
* Provide a regex to match URIs
* @return A singleton regex object
*/
const GRegex *linphone_gtk_get_uri_regex(void);

View file

@ -63,6 +63,7 @@ const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
static LinphoneCore *the_core=NULL;
static GtkWidget *the_ui=NULL;
static LinphoneLDAPContactProvider* ldap_provider = NULL;
static GRegex *uri_regex = NULL;
static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str);
static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
@ -2025,6 +2026,26 @@ static void populate_xdg_data_dirs_envvar(void) {
#endif
}
static void free_uri_regex(void) {
if(uri_regex) g_regex_unref(uri_regex);
}
const GRegex *linphone_gtk_get_uri_regex(void) {
const gchar *pattern = "\\b[a-z0-9]+://[\\S]+\\b";
GError *error = NULL;
if(uri_regex == NULL) {
uri_regex = g_regex_new(pattern, G_REGEX_OPTIMIZE, 0, &error);
if(error) {
g_warning("Could not parse regex pattern for URIs: %s", error->message);
g_error_free(error);
uri_regex = NULL;
return NULL;
}
atexit(free_uri_regex);
}
return uri_regex;
}
int main(int argc, char *argv[]){
char *config_file;
const char *factory_config_file;