summaryrefslogtreecommitdiff
path: root/desktop/cookies.c
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/cookies.c')
-rw-r--r--desktop/cookies.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/desktop/cookies.c b/desktop/cookies.c
new file mode 100644
index 000000000..c5dac5101
--- /dev/null
+++ b/desktop/cookies.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Cookies (implementation).
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "desktop/cookies.h"
+#include "desktop/options.h"
+#include "desktop/tree.h"
+#include "utils/messages.h"
+#include "utils/log.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+/** Flags for each type of cookie tree node. */
+enum tree_element_cookie {
+ TREE_ELEMENT_PERSISTENT = 0x01,
+ TREE_ELEMENT_VERSION = 0x02,
+ TREE_ELEMENT_SECURE = 0x03,
+ TREE_ELEMENT_LAST_USED = 0x04,
+ TREE_ELEMENT_EXPIRES = 0x05,
+ TREE_ELEMENT_PATH = 0x06,
+ TREE_ELEMENT_DOMAIN = 0x07,
+ TREE_ELEMENT_COMMENT = 0x08,
+ TREE_ELEMENT_VALUE = 0x09,
+};
+
+static struct tree *cookies_tree;
+static struct node *cookies_tree_root;
+static bool user_delete;
+static hlcache_handle *folder_icon;
+static hlcache_handle *cookie_icon;
+
+
+/**
+ * Find an entry in the cookie tree
+ *
+ * \param node the node to check the children of
+ * \param title The title to find
+ * \return Pointer to node, or NULL if not found
+ */
+static struct node *cookies_find(struct node *node, const char *title)
+{
+ struct node *search;
+ struct node_element *element;
+
+ for (search = tree_node_get_child(node); search;
+ search = tree_node_get_next(search)) {
+ element = tree_node_find_element(search, TREE_ELEMENT_TITLE,
+ NULL);
+ if (strcmp(title, tree_node_element_get_text(element)) == 0)
+ return search;
+ }
+ return NULL;
+}
+
+/**
+ * Callback for all cookie tree nodes.
+ */
+static node_callback_resp cookies_node_callback(void *user_data, struct node_msg_data *msg_data)
+{
+ struct node *node = msg_data->node;
+ struct node_element *domain, *path;
+ const char *domain_t, *path_t, *name_t;
+ char *space;
+ bool is_folder = tree_node_is_folder(node);
+
+ /* we don't remove any icons here */
+ if (msg_data->msg == NODE_DELETE_ELEMENT_IMG)
+ return NODE_CALLBACK_HANDLED;
+
+ /* let the tree handle events other than text data removal */
+ if (msg_data->msg != NODE_DELETE_ELEMENT_TXT)
+ return NODE_CALLBACK_NOT_HANDLED;
+
+ /* check if it's a domain folder */
+ if (is_folder)
+ return NODE_CALLBACK_NOT_HANDLED;
+
+ switch (msg_data->flag) {
+ case TREE_ELEMENT_TITLE:
+ if (!user_delete)
+ break;
+ /* get the rest of the cookie data */
+ domain = tree_node_find_element(node,
+ TREE_ELEMENT_DOMAIN, NULL);
+ path = tree_node_find_element(node, TREE_ELEMENT_PATH,
+ NULL);
+
+ if ((domain != NULL) &&
+ (path != NULL)) {
+ domain_t = tree_node_element_get_text(domain) +
+ strlen(messages_get(
+ "TreeDomain")) - 4;
+ space = strchr(domain_t, ' ');
+ if (space != NULL)
+ *space = '\0';
+ path_t = tree_node_element_get_text(path) +
+ strlen(messages_get("TreePath"))
+ - 4;
+ space = strchr(path_t, ' ');
+ if (space != NULL)
+ *space = '\0';
+ name_t = msg_data->data.text;
+ urldb_delete_cookie(domain_t, path_t, name_t);
+ }
+ break;
+ default:
+ break;
+ }
+
+ free(msg_data->data.text);
+
+ return NODE_CALLBACK_HANDLED;
+}
+
+
+/**
+ * Updates a tree entry for a cookie.
+ *
+ * All information is copied from the cookie_data, and as such can
+ * be edited and should be freed.
+ *
+ * \param node The node to update
+ * \param data The cookie data to use
+ * \return true if node updated, or false for failure
+ */
+static bool cookies_update_cookie_node(struct node *node,
+ const struct cookie_data *data)
+{
+ struct node_element *element;
+ char buffer[32];
+
+ assert(data != NULL);
+
+ /* update the value text */
+ element = tree_node_find_element(node, TREE_ELEMENT_VALUE, NULL);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreeValue",
+ data->value != NULL ?
+ data->value :
+ messages_get("TreeUnused")));
+
+
+ /* update the comment text */
+ if ((data->comment != NULL) &&
+ (strcmp(data->comment, "") != 0)) {
+ element = tree_node_find_element(node, TREE_ELEMENT_COMMENT, NULL);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreeComment",
+ data->comment));
+ }
+
+ /* update domain text */
+ element = tree_node_find_element(node, TREE_ELEMENT_DOMAIN, element);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreeDomain",
+ data->domain,
+ data->domain_from_set ?
+ messages_get("TreeHeaders") :
+ ""));
+
+ /* update path text */
+ element = tree_node_find_element(node, TREE_ELEMENT_PATH, element);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreePath", data->path,
+ data->path_from_set ?
+ messages_get("TreeHeaders") :
+ ""));
+
+ /* update expiry text */
+ element = tree_node_find_element(node, TREE_ELEMENT_EXPIRES, element);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreeExpires",
+ (data->expires > 0)
+ ? (data->expires == 1)
+ ? messages_get("TreeSession")
+ : ctime(&data->expires)
+ : messages_get("TreeUnknown")));
+
+ /* update last used text */
+ element = tree_node_find_element(node, TREE_ELEMENT_LAST_USED, element);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreeLastUsed",
+ (data->last_used > 0) ?
+ ctime(&data->last_used) :
+ messages_get("TreeUnknown")));
+
+ /* update secure text */
+ element = tree_node_find_element(node, TREE_ELEMENT_SECURE, element);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreeSecure",
+ data->secure ?
+ messages_get("Yes") :
+ messages_get("No")));
+
+ /* update version text */
+ element = tree_node_find_element(node, TREE_ELEMENT_VERSION, element);
+ snprintf(buffer, sizeof(buffer), "TreeVersion%i", data->version);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreeVersion",
+ messages_get(buffer)));
+
+ /* update persistant text */
+ element = tree_node_find_element(node, TREE_ELEMENT_PERSISTENT, element);
+ tree_update_element_text(cookies_tree,
+ element,
+ messages_get_buff("TreePersistent",
+ data->no_destroy ?
+ messages_get("Yes") :
+ messages_get("No")));
+
+ return node;
+}
+
+/**
+ * Creates an empty tree entry for a cookie, and links it into the tree.
+ *
+ * All information is copied from the cookie_data, and as such can
+ * be edited and should be freed.
+ *
+ * \param parent the node to link to
+ * \param data the cookie data to use
+ * \return the node created, or NULL for failure
+ */
+static struct node *cookies_create_cookie_node(struct node *parent,
+ const struct cookie_data *data)
+{
+ struct node *node;
+ char *name;
+
+ name = strdup(data->name);
+ if (name == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ node = tree_create_leaf_node(cookies_tree, NULL, name,
+ false, false, false);
+ if (node == NULL) {
+ free(name);
+ return NULL;
+ }
+
+ tree_set_node_user_callback(node, cookies_node_callback, NULL);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_PERSISTENT, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_VERSION, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_SECURE, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_LAST_USED, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_EXPIRES, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_PATH, false);
+
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_DOMAIN, false);
+
+ if ((data->comment) && (strcmp(data->comment, "")))
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_COMMENT, false);
+ tree_create_node_element(node, NODE_ELEMENT_TEXT,
+ TREE_ELEMENT_VALUE, false);
+ tree_set_node_icon(cookies_tree, node, cookie_icon);
+
+ if (!cookies_update_cookie_node(node, data))
+ {
+ tree_delete_node(NULL, node, false);
+ return NULL;
+ }
+
+ tree_link_node(cookies_tree, parent, node, false);
+ return node;
+}
+
+
+/**
+ * Called when scheduled event gets fired. Actually performs the update.
+ */
+static void cookies_schedule_callback(void *scheduled_data)
+{
+ const struct cookie_data *data = scheduled_data;
+ struct node *node = NULL;
+ struct node *cookie_node = NULL;
+ char *domain_cp;
+
+ assert(data != NULL);
+
+ node = cookies_find(cookies_tree_root, data->domain);
+
+ if (node == NULL) {
+ domain_cp = strdup(data->domain);
+ if (domain_cp == NULL) {
+ LOG(("malloc failed"));
+ warn_user("NoMemory", 0);
+ return;
+ }
+ node = tree_create_folder_node(cookies_tree,
+ cookies_tree_root, domain_cp,
+ false, false, false);
+ if (node != NULL) {
+ tree_set_node_user_callback(node, cookies_node_callback,
+ NULL);
+ tree_set_node_icon(cookies_tree, node, folder_icon);
+ }
+ }
+
+ if (node == NULL)
+ return;
+
+ cookie_node = cookies_find(node, data->name);
+ if (cookie_node == NULL)
+ cookies_create_cookie_node(node, data);
+ else
+ cookies_update_cookie_node(cookie_node, data);
+
+ return;
+}
+
+/**
+ * Initialises cookies tree.
+ *
+ * \param data user data for the callbacks
+ * \param start_redraw callback function called before every redraw
+ * \param end_redraw callback function called after every redraw
+ * \return true on success, false on memory exhaustion
+ */
+bool cookies_initialise(struct tree *tree)
+{
+
+ if (tree == NULL)
+ return false;
+
+ folder_icon = tree_load_icon(tree_directory_icon_name);
+ cookie_icon = tree_load_icon(tree_content_icon_name);
+
+ /* Create an empty tree */
+ cookies_tree = tree;
+ cookies_tree_root = tree_get_root(cookies_tree);
+
+ user_delete = false;
+ urldb_iterate_cookies(cookies_schedule_update);
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, true, true);
+
+ return true;
+}
+
+
+/**
+ * Get flags with which the cookies tree should be created;
+ *
+ * \return the flags
+ */
+unsigned int cookies_get_tree_flags(void)
+{
+ return TREE_DELETE_EMPTY_DIRS;
+}
+
+
+/* exported interface documented in cookies.h */
+bool cookies_schedule_update(const struct cookie_data *data)
+{
+ assert(data != NULL);
+ assert(user_delete == false);
+
+ schedule(100, cookies_schedule_callback, (void *)data);
+
+ return true;
+}
+
+
+/* exported interface documented in cookies.h */
+void cookies_remove(const struct cookie_data *data)
+{
+ assert(data != NULL);
+
+ schedule_remove(cookies_schedule_callback, (void *)data);
+}
+
+
+/**
+ * Free memory and release all other resources.
+ */
+void cookies_cleanup(void)
+{
+}
+
+/* Actions to be connected to front end specific toolbars */
+
+/**
+ * Delete nodes which are currently selected.
+ */
+void cookies_delete_selected(void)
+{
+ user_delete = true;
+ tree_delete_selected_nodes(cookies_tree, cookies_tree_root);
+ user_delete = false;
+}
+
+/**
+ * Delete all nodes.
+ */
+void cookies_delete_all(void)
+{
+ bool needs_redraw = tree_get_redraw(cookies_tree);
+ if (needs_redraw)
+ tree_set_redraw(cookies_tree, false);
+
+ user_delete = true;
+ tree_set_node_selected(cookies_tree, cookies_tree_root, true, true);
+ tree_delete_selected_nodes(cookies_tree, cookies_tree_root);
+ user_delete = false;
+
+ if (needs_redraw)
+ tree_set_redraw(cookies_tree, true);
+}
+
+/**
+ * Select all nodes in the tree.
+ */
+void cookies_select_all(void)
+{
+ tree_set_node_selected(cookies_tree, cookies_tree_root, true, true);
+}
+
+/**
+ * Unselect all nodes.
+ */
+void cookies_clear_selection(void)
+{
+ tree_set_node_selected(cookies_tree, cookies_tree_root, true, false);
+}
+
+/**
+ * Expand both domain and cookie nodes.
+ */
+void cookies_expand_all(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, true, true);
+}
+
+/**
+ * Expand domain nodes only.
+ */
+void cookies_expand_domains(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, true, false);
+}
+
+/**
+ * Expand cookie nodes only.
+ */
+void cookies_expand_cookies(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ true, false, true);
+}
+
+/**
+ * Collapse both domain and cookie nodes.
+ */
+void cookies_collapse_all(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ false, true, true);
+}
+
+/**
+ * Collapse domain nodes only.
+ */
+void cookies_collapse_domains(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ false, true, false);
+}
+
+/**
+ * Collapse cookie nodes only.
+ */
+void cookies_collapse_cookies(void)
+{
+ tree_set_node_expanded(cookies_tree, cookies_tree_root,
+ false, false, true);
+}