/* Copyright (C) 2010-2012 by Cristian Henzel * * forked from parcellite, which is * Copyright (C) 2007-2008 by Xyhthyx * * This file is part of ClipIt. * * ClipIt 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. * * ClipIt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "main.h" #include "utils.h" #include "history.h" GList *history; /* Deletes duplicate item in history */ static GList *find_duplicate(gchar *item) { GList *element; /* Go through each element compare each */ for (element = history; element != NULL; element = element->next) { history_item *elem_data = element->data; if (g_strcmp0((gchar*)elem_data->content, item) == 0) { return element; } } return NULL; } static history_item *initialize_history_item() { history_item *hitem = g_new0(history_item, 1); hitem->is_static = 0; return hitem; } /* Returns TRUE if text should be excluded from history */ static gboolean is_excluded(gchar *text) { /* Open the file for reading */ gchar *path = g_build_filename(g_get_user_data_dir(), EXCLUDES_FILE, NULL); FILE *excludes_file = fopen(path, "rb"); g_free(path); /* Check that it opened and begin read */ if (excludes_file) { /* Read the size of the first item */ gint size; size_t fread_return; fread_return = fread(&size, 4, 1, excludes_file); /* Continue reading until size is 0 */ while (size != 0) { /* Read Regex */ gchar *regex = (gchar*)g_malloc(size + 1); fread_return = fread(regex, size, 1, excludes_file); regex[size] = '\0'; fread_return = fread(&size, 4, 1, excludes_file); /* Append the read action */ GRegex *regexp = g_regex_new(regex, G_REGEX_CASELESS, 0, NULL); gboolean result = g_regex_match(regexp, text, 0, NULL); g_regex_unref(regexp); g_free(regex); if(result) return result; } fclose(excludes_file); } return FALSE; } /* Reads history from DATADIR/clipit/history */ void read_history() { /* Build file path */ gchar *history_path = g_build_filename(g_get_user_data_dir(), HISTORY_FILE, NULL); /* Open the file for reading */ FILE *history_file = fopen(history_path, "rb"); g_free(history_path); /* Check that it opened and begin read */ if (history_file) { /* Read the size of the first item */ int size; size_t fread_return; if (fread(&size, 4, 1, history_file) != 1) size = 0; if (size == -1) { /* If size is -1, we are using the new filetype introduced in 1.4.1 */ /* We currently aren't using the extra data fields */ char extra_data[64]; int data_type; fread_return = fread(&extra_data, 64, 1, history_file); if (fread(&size, 4, 1, history_file) != 1) size = 0; if (fread(&data_type, 4, 1, history_file) != 1) data_type = 0; while (size && data_type) { switch (data_type) { case 1: { gchar *item = (gchar*)g_malloc(size + 1); fread_return = fread(item, size, 1, history_file); item[size] = '\0'; history_item *hitem = initialize_history_item(); hitem->content = item; history = g_list_prepend(history, hitem); break; } case 2: { int read_static; history_item *hitem = history->data; fread_return = fread(&read_static, size, 1, history_file); hitem->is_static = read_static; break; } } if (fread(&size, 4, 1, history_file) != 1) size = 0; if (fread(&data_type, 4, 1, history_file) != 1) data_type = 0; } } else { /* Continue reading until size is 0 */ while (size) { /* Malloc according to the size of the item */ gchar *item = (gchar*)g_malloc(size + 1); /* Read item and add ending character */ fread_return = fread(item, size, 1, history_file); item[size] = '\0'; /* Prepend item and read next size */ history_item *hitem = initialize_history_item(); hitem->content = item; history = g_list_prepend(history, hitem); if (fread(&size, 4, 1, history_file) != 1) size = 0; } } /* Close file and reverse the history to normal */ fclose(history_file); history = g_list_reverse(history); } } /* Saves history to DATADIR/clipit/history */ void save_history() { if(prefs.save_history) { /* Check that the directory is available */ check_dirs(); /* Build file path */ gchar *history_path = g_build_filename(g_get_user_data_dir(), HISTORY_FILE, NULL); /* Open the file for writing */ FILE *history_file = fopen(history_path, "wb"); g_free(history_path); /* Check that it opened and begin write */ if (history_file) { GList *element; /* Write each element to a binary file */ int i; for (i=1; i<=17; i++) { int write_val = -1; fwrite(&write_val, 4, 1, history_file); } for (element = history; element != NULL; element = element->next) { /* Create new GString from element data, write its * length (size) to file followed by the element * data itself */ int write_val = 1; history_item *elem_data = element->data; GString *item = g_string_new((gchar*)elem_data->content); int write_static = elem_data->is_static; fwrite(&(item->len), 4, 1, history_file); fwrite(&write_val, 4, 1, history_file); fputs(item->str, history_file); write_val = 4; fwrite(&write_val, 4, 1, history_file); write_val = 2; fwrite(&write_val, 4, 1, history_file); fwrite(&write_static, 4, 1, history_file); g_string_free(item, TRUE); } /* Write 0 to indicate end of file */ gint end = 0; fwrite(&end, 4, 1, history_file); fwrite(&end, 4, 1, history_file); fclose(history_file); } } /* Refresh indicator menu. Temporary solution until * getting the visible status of the menu is supported by the API */ #ifdef HAVE_APPINDICATOR create_app_indicator(0); #endif } /* Checks if item should be included in history and calls append */ void check_and_append(gchar *item) { if (item) { /* if item is too big, we don't include it in the history */ if(strlen(item) > ENTRY_MAX_SIZE) return; GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Check if we have URIs */ if((gtk_clipboard_wait_for_uris(clip) != NULL) && !prefs.save_uris) /* We have URIs but the user doesn't want to save them */ return; if(is_excluded(item)) /* This item is excluded from the history */ return; if (prefs.hyperlinks_only && !is_hyperlink(item)) /* User only wants hyperlinks, but this isn't one */ return; GList *duplicate_elem = find_duplicate(item); if (duplicate_elem) { history = g_list_remove_link(history, duplicate_elem); history = g_list_concat(duplicate_elem, history); } else { append_item(item); } } } /* Adds item to the end of history */ void append_item(gchar *item) { history_item *hitem = initialize_history_item(); hitem->content = g_strdup(item); history = g_list_prepend(history, hitem); truncate_history(); } /* Truncates history to history_limit items */ void truncate_history() { if (history) { /* Shorten history if necessary */ GList *last_element = g_list_nth (history, prefs.history_limit); while (last_element) { history_item *elem_data = last_element->data; last_element = last_element->next; if (elem_data->is_static == 0) history = g_list_remove(history, elem_data); } last_element = g_list_nth (history, prefs.history_limit - 1); /* last_element->next checks if the list is longer than the user * wants it; last_element->prev checks if this isn't the first * item, which we wouldn't want to delete */ if (last_element) { while (last_element->next && last_element->prev) { history_item *elem_data = last_element->data; while (elem_data->is_static && last_element->prev) { if (last_element->prev->prev) last_element = last_element->prev; elem_data = last_element->data; } if (elem_data->is_static == 0) history = g_list_remove(history, elem_data); last_element = g_list_nth (history, prefs.history_limit - 1); } } /* Save changes */ save_history(); } } /* Returns pointer to last item in history */ gpointer get_last_item() { if (history) { history_item *elem_data = history->data; if (elem_data->content) { /* Return the last element */ gpointer last_item = elem_data->content; return last_item; } return NULL; } return NULL; } /* Deletes duplicate item in history */ void delete_duplicate(gchar *item) { GList *element; /* Go through each element compare each */ for (element = history; element != NULL; element = element->next) { history_item *elem_data = element->data; if (g_strcmp0((gchar*)elem_data->content, item) == 0) { g_free(elem_data->content); history = g_list_delete_link(history, element); break; } } }