d094451f1724df9b5e77d71a4080ad9887668def
diff --git a/libsoup/soup-cookie-jar-text.c b/libsoup/soup-cookie-jar-text.c
index 1fc7443..9b6fb66 100644
--- a/libsoup/soup-cookie-jar-text.c
+++ b/libsoup/soup-cookie-jar-text.c
@@ -43,8 +43,11 @@ typedef struct {
 
 G_DEFINE_TYPE (SoupCookieJarText, soup_cookie_jar_text, SOUP_TYPE_COOKIE_JAR)
 
-static void load (SoupCookieJar *jar);
-static void save (SoupCookieJar *jar);
+static void load    (SoupCookieJar *jar);
+static void save    (SoupCookieJar *jar);
+static void changed (SoupCookieJar *jar,
+		     SoupCookie    *old_cookie,
+		     SoupCookie    *new_cookie);
 
 static void set_property (GObject *object, guint prop_id,
 			  const GValue *value, GParamSpec *pspec);
@@ -76,7 +79,8 @@ soup_cookie_jar_text_class_init (SoupCookieJarTextClass *text_class)
 
 	g_type_class_add_private (text_class, sizeof (SoupCookieJarTextPrivate));
 
-	cookie_jar_class->save = save;
+	cookie_jar_class->save    = save;
+	cookie_jar_class->changed = changed;
 
 	object_class->finalize     = finalize;
 	object_class->set_property = set_property;
@@ -165,64 +169,61 @@ soup_cookie_jar_text_new (const char *filename, gboolean read_only)
 			     NULL);
 }
 
-static void
-parse_line (SoupCookieJar *jar, char *line, time_t now)
+static SoupCookie*
+parse_cookie (char *line, time_t now)
 {
-	char *host, *is_domain, *path, *secure, *expires, *name, *value;
+	char **result;
+	SoupCookie *cookie = NULL;
 	gboolean http_only;
 	time_t max_age;
-	SoupCookie *cookie;
+	char *host, *is_domain, *path, *secure, *expires, *name, *value;
 
-	if (!g_str_has_prefix (line, "#HttpOnly_")) {
+	if (g_str_has_prefix (line, "#HttpOnly_")) {
 		http_only = TRUE;
 		line += strlen ("#HttpOnly_");
 	} else if (*line == '#' || g_ascii_isspace (*line))
-		return;
+		return cookie;
 	else
 		http_only = FALSE;
 
-	host = line;
-
-	is_domain = strchr (host, '\t');
-	if (!is_domain)
-		return;
-	*(is_domain++) = '\0';
+	result = g_strsplit (line, "\t", -1);
+	if (g_strv_length (result) != 7)
+		goto out;
 
-	path = strchr (is_domain, '\t');
-	if (!path)
-		return;
-	*(path++) = '\0';
-
-	secure = strchr (path, '\t');
-	if (!secure)
-		return;
-	*(secure++) = '\0';
-
-	expires = strchr (secure, '\t');
-	if (!expires)
-		return;
-	*(expires++) = '\0';
+	/* Check this first */
+	expires = result[4];
 	max_age = strtoul (expires, NULL, 10) - now;
 	if (max_age <= 0)
-		return;
+		goto out;
 
-	name = strchr (expires, '\t');
-	if (!name)
-		return;
-	*(name++) = '\0';
+	host = result[0];
+	is_domain = result[1];
+	path = result[2];
+	secure = result[3];
 
-	value = strchr (name, '\t');
-	if (!value)
-		return;
-	*(value++) = '\0';
+	name = result[5];
+	value = result[6];
 
 	cookie = soup_cookie_new (name, value, host, path, max_age);
+
 	if (strcmp (secure, "FALSE") != 0)
 		soup_cookie_set_secure (cookie, TRUE);
 	if (http_only)
 		soup_cookie_set_http_only (cookie, TRUE);
 
-	soup_cookie_jar_set_cookie_internal (jar, cookie);
+ out:
+	g_strfreev (result);
+
+	return cookie;
+}
+
+static void
+parse_line (SoupCookieJar *jar, char *line, time_t now)
+{
+	SoupCookie *cookie;
+
+	cookie = parse_cookie (line, now);
+	soup_cookie_jar_add_cookie (jar, cookie);
 }
 
 static void
@@ -238,6 +239,8 @@ load (SoupCookieJar *jar)
 	if (!g_file_get_contents (priv->filename, &contents, &length, NULL))
 		return;
 
+	/* Do not write any of the loaded cookies to the file */
+	priv->read_only = TRUE;
 	line = contents;
 	for (p = contents; *p; p++) {
 		/* \r\n comes out as an extra empty line and gets ignored */
@@ -248,11 +251,106 @@ load (SoupCookieJar *jar)
 		}
 	}
 	parse_line (jar, line, now);
+	priv->read_only = FALSE;
 
 	g_free (contents);
 }
 
 static void
+write_cookie (FILE *out, SoupCookie *cookie)
+{
+	fseek (out, 0, SEEK_END);
+
+	fprintf (out, "%s%s\t%s\t%s\t%s\t%lu\t%s\t%s\n",
+		 cookie->http_only ? "#HttpOnly_" : "",
+		 cookie->domain,
+		 *cookie->domain == '.' ? "TRUE" : "FALSE",
+		 cookie->path,
+		 cookie->secure ? "TRUE" : "FALSE",
+		 (gulong)soup_date_to_time_t (cookie->expires),
+		 cookie->name,
+		 cookie->value);
+}
+
+static void
+delete_cookie (const char *filename, SoupCookie *cookie)
+{
+	char *contents = NULL, *line, *p;
+	gsize length = 0;
+	FILE *f;
+	SoupCookie *c;
+	time_t now = time (NULL);
+
+	if (!g_file_get_contents (filename, &contents, &length, NULL))
+		return;
+
+	f = fopen (filename, "w");
+	if (!f)
+		return;
+
+	line = contents;
+	for (p = contents; *p; p++) {
+		/* \r\n comes out as an extra empty line and gets ignored */
+		if (*p == '\r' || *p == '\n') {
+			*p = '\0';
+			c = parse_cookie (line, now);
+			if (!soup_cookie_equal (cookie, c))
+				write_cookie (f, c);
+			line = p + 1;
+			soup_cookie_free (c);
+		}
+	}
+	c = parse_cookie (line, now);
+	if (!soup_cookie_equal (cookie, c))
+		write_cookie (f, c);
+	soup_cookie_free (c);
+
+	fclose (f);
+}
+
+static void
+changed (SoupCookieJar *jar,
+	 SoupCookie    *old_cookie,
+	 SoupCookie    *new_cookie)
+{
+	FILE *out;
+	SoupCookieJarTextPrivate *priv =
+		SOUP_COOKIE_JAR_TEXT_GET_PRIVATE (jar);
+
+	if (priv->read_only || !priv->filename)
+		return;		
+
+	/* We can sort of ignore the semantics of the 'changed'
+	 * signal here and simply delete the old cookie if present
+	 * and write the new cookie if present. That will do the
+	 * right thing for all 'added', 'deleted' and 'modified'
+	 * meanings.
+	 */
+	/* Also, delete_cookie takes the filename and write_cookie
+	 * a FILE pointer. Seems more convenient that way considering
+	 * the implementations of the functions
+	 */
+	if (old_cookie)
+		delete_cookie (priv->filename, old_cookie);
+
+	if (new_cookie) {
+		out = fopen (priv->filename, "a");
+		if (!out) {
+			/* FIXME: error? */
+			return;
+		}
+
+		if (new_cookie->expires)
+			write_cookie (out, new_cookie);
+
+		if (fclose (out) != 0) {
+			/* FIXME: error? */
+			return;
+		}
+	}
+}
+
+static void
 save (SoupCookieJar *jar)
 {
 	SoupCookieJarTextPrivate *priv =
@@ -282,15 +380,7 @@ save (SoupCookieJar *jar)
 	/* FIXME: order? */
 	for (c = cookies; c; c = c->next) {
 		SoupCookie *cookie = c->data;
-		fprintf (out, "%s%s\t%s\t%s\t%s\t%lu\t%s\t%s\n",
-			 cookie->http_only ? "#HttpOnly_" : "",
-			 cookie->domain,
-			 *cookie->domain == '.' ? "TRUE" : "FALSE",
-			 cookie->path,
-			 cookie->secure ? "TRUE" : "FALSE",
-			 (gulong)soup_date_to_time_t (cookie->expires),
-			 cookie->name,
-			 cookie->value);
+		write_cookie (out, cookie);
 	}
 	g_slist_free (cookies);
 
