summaryrefslogtreecommitdiff
path: root/cookies.c
diff options
context:
space:
mode:
Diffstat (limited to 'cookies.c')
-rw-r--r--cookies.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/cookies.c b/cookies.c
new file mode 100644
index 0000000..3ff982c
--- /dev/null
+++ b/cookies.c
@@ -0,0 +1,314 @@
+/* cookies.c
+ * Cookies
+ * (c) 2002 Mikulas Patocka
+ * This file is a part of the Links program, released under GPL
+ */
+
+#include "links.h"
+
+#define ACCEPT_NONE 0
+#define ACCEPT_ALL 1
+
+static int accept_cookies = ACCEPT_ALL;
+
+static tcount cookie_id = 0;
+
+struct list_head cookies = { &cookies, &cookies };
+
+struct list_head c_domains = { &c_domains, &c_domains };
+
+struct c_server {
+ struct c_server *next;
+ struct c_server *prev;
+ int accpt;
+ unsigned char server[1];
+};
+
+static struct list_head c_servers = { &c_servers, &c_servers };
+
+void free_cookie(struct cookie *c)
+{
+ mem_free(c->name);
+ if (c->value) mem_free(c->value);
+ if (c->server) mem_free(c->server);
+ if (c->path) mem_free(c->path);
+ if (c->domain) mem_free(c->domain);
+}
+
+static int check_domain_security(unsigned char *server, unsigned char *domain)
+{
+ size_t i, j, dl;
+ int nd;
+ unsigned char *tld[] = { ".com", ".edu", ".net", ".org", ".gov", ".mil", ".int", NULL };
+ if (domain[0] == '.') domain++;
+ dl = strlen(domain);
+ if (dl > strlen(server)) return 1;
+ for (i = strlen(server) - dl, j = 0; server[i]; i++, j++)
+ if (upcase(server[i]) != upcase(domain[j])) return 1;
+ nd = 2;
+ for (i = 0; tld[i]; i++) {
+ size_t tl = strlen(tld[i]);
+ if (dl > tl && !casecmp(tld[i], &domain[dl - tl], tl)) {
+ nd = 1;
+ break;
+ }
+ }
+ if (nd == 2) {
+ unsigned char *last_dot = strrchr(domain, '.');
+ i = 0;
+ if (last_dot) {
+ while (last_dot > domain) {
+ last_dot--;
+ if (*last_dot == '.') break;
+ i++;
+ }
+ }
+ if (i >= 4) nd = 1;
+ }
+ for (i = 0; domain[i]; i++) if (domain[i] == '.') if (!--nd) break;
+ if (nd > 0) return 1;
+ return 0;
+}
+
+static void accept_cookie(struct cookie *);
+
+/* sezere 1 cookie z retezce str, na zacatku nesmi byt zadne whitechars
+ * na konci muze byt strednik nebo 0
+ * cookie musi byt ve tvaru nazev=hodnota, kolem rovnase nesmi byt zadne mezery
+ * (respektive mezery se budou pocitat do nazvu a do hodnoty)
+ */
+int set_cookie(struct terminal *term, unsigned char *url, unsigned char *str)
+{
+ int noval = 0;
+ struct cookie *cookie;
+ struct c_server *cs;
+ unsigned char *p, *q, *s, *server, *date;
+ if (accept_cookies == ACCEPT_NONE) return 0;
+ for (p = str; *p != ';' && *p; p++) {/*if (WHITECHAR(*p)) return 0*/}
+ for (q = str; *q != '='; q++) if (!*q || q >= p) {
+ noval = 1;
+ break;
+ }
+ if (str == q || q + 1 == p) return 0;
+ cookie = mem_alloc(sizeof(struct cookie));
+ server = get_host_name(url);
+ cookie->name = memacpy(str, q - str);
+ cookie->value = !noval ? memacpy(q + 1, p - q - 1) : NULL;
+ cookie->server = stracpy(server);
+ date = parse_header_param(str, "expires", 0);
+ if (date) {
+ cookie->expires = parse_http_date(date);
+ /* kdo tohle napsal a proc ?? */
+ /*if (! cookie->expires) cookie->expires++;*/ /* no harm and we can use zero then */
+ mem_free(date);
+ } else
+ cookie->expires = 0;
+ if (!(cookie->path = parse_header_param(str, "path", 0))) {
+ /*unsigned char *w;*/
+ cookie->path = stracpy("/");
+ /*
+ add_to_strn(&cookie->path, document);
+ for (w = cookie->path; *w; w++) if (end_of_dir(cookie->path, *w)) {
+ *w = 0;
+ break;
+ }
+ for (w = cookie->path + strlen(cookie->path) - 1; w >= cookie->path; w--)
+ if (*w == '/') {
+ w[1] = 0;
+ break;
+ }
+ */
+ } else {
+ if (cookie->path[0] != '/') {
+ add_to_strn(&cookie->path, "x");
+ memmove(cookie->path + 1, cookie->path, strlen(cookie->path) - 1);
+ cookie->path[0] = '/';
+ }
+ }
+ if (!(cookie->domain = parse_header_param(str, "domain", 0))) cookie->domain = stracpy(server);
+ if (cookie->domain[0] == '.') memmove(cookie->domain, cookie->domain + 1, strlen(cookie->domain));
+ if ((s = parse_header_param(str, "secure", 0))) {
+ cookie->secure = 1;
+ mem_free(s);
+ } else cookie->secure = 0;
+ if (check_domain_security(server, cookie->domain)) {
+ mem_free(cookie->domain);
+ cookie->domain = stracpy(server);
+ }
+ cookie->id = cookie_id++;
+ foreach (cs, c_servers) if (!strcasecmp(cs->server, server)) {
+ if (cs->accpt) goto ok;
+ else {
+ free_cookie(cookie);
+ mem_free(cookie);
+ mem_free(server);
+ return 0;
+ }
+ }
+ if (accept_cookies != ACCEPT_ALL) {
+ free_cookie(cookie);
+ mem_free(cookie);
+ mem_free(server);
+ return 1;
+ }
+ ok:
+ accept_cookie(cookie);
+ mem_free(server);
+ return 0;
+}
+
+static void accept_cookie(struct cookie *c)
+{
+ struct c_domain *cd;
+ struct cookie *d, *e;
+ foreach(d, cookies) if (!strcasecmp(d->name, c->name) && !strcasecmp(d->domain, c->domain)) {
+ e = d;
+ d = d->prev;
+ del_from_list(e);
+ free_cookie(e);
+ mem_free(e);
+ }
+ if (c->value && !strcasecmp(c->value, "deleted")) {
+ free_cookie(c);
+ mem_free(c);
+ return;
+ }
+ add_to_list(cookies, c);
+ foreach(cd, c_domains) if (!strcasecmp(cd->domain, c->domain)) return;
+ cd = mem_alloc(sizeof(struct c_domain) + strlen(c->domain) + 1);
+ strcpy(cd->domain, c->domain);
+ add_to_list(c_domains, cd);
+}
+
+#if 0
+static void delete_cookie(struct cookie *c)
+{
+ struct c_domain *cd;
+ struct cookie *d;
+ foreach(d, cookies) if (!strcasecmp(d->domain, c->domain)) goto x;
+ foreach(cd, c_domains) if (!strcasecmp(cd->domain, c->domain)) {
+ del_from_list(cd);
+ mem_free(cd);
+ break;
+ }
+ x:
+ del_from_list(c);
+ free_cookie(c);
+ mem_free(c);
+}
+
+static struct cookie *find_cookie_id(void *idp)
+{
+ long id = (my_intptr_t)idp;
+ struct cookie *c;
+ foreach(c, cookies) if (c->id == id) return c;
+ return NULL;
+}
+
+static void reject_cookie(void *idp)
+{
+ struct cookie *c;
+ if (!(c = find_cookie_id(idp))) return;
+ delete_cookie(c);
+}
+
+static void cookie_default(void *idp, int a)
+{
+ struct cookie *c;
+ struct c_server *s;
+ if (!(c = find_cookie_id(idp))) return;
+ foreach(s, c_servers) if (!strcasecmp(s->server, c->server)) goto found;
+ s = mem_alloc(sizeof(struct c_server) + strlen(c->server) + 1);
+ strcpy(s->server, c->server);
+ add_to_list(c_servers, s);
+ found:
+ s->accpt = a;
+}
+
+static void accept_cookie_always(void *idp)
+{
+ cookie_default(idp, 1);
+}
+
+static void accept_cookie_never(void *idp)
+{
+ cookie_default(idp, 0);
+ reject_cookie(idp);
+}
+#endif
+
+int is_in_domain(unsigned char *d, unsigned char *s)
+{
+ int dl = strlen(d);
+ int sl = strlen(s);
+ if (dl > sl) return 0;
+ if (dl == sl) return !strcasecmp(d, s);
+ if (s[sl - dl - 1] != '.') return 0;
+ return !casecmp(d, s + sl - dl, dl);
+}
+
+int is_path_prefix(unsigned char *d, unsigned char *s)
+{
+ int dl = strlen(d);
+ int sl = strlen(s);
+ if (!dl) return 1;
+ if (dl > sl) return 0;
+ if (memcmp(d, s, dl)) return 0;
+ return d[dl - 1] == '/' || !s[dl] || s[dl] == '/' || s[dl] == POST_CHAR || s[dl] == '?' || s[dl] == '&';
+}
+
+int cookie_expired(struct cookie *c) /* parse_http_date is broken */
+{
+ time_t t;
+ EINTRLOOPX(t, time(NULL), (time_t)-1);
+ return 0 && (c->expires && c->expires < t);
+}
+
+void add_cookies(unsigned char **s, int *l, unsigned char *url)
+{
+ int nc = 0;
+ struct c_domain *cd;
+ struct cookie *c, *d;
+ unsigned char *server = get_host_name(url);
+ unsigned char *data = get_url_data(url);
+ if (data > url) data--;
+ foreach (cd, c_domains) if (is_in_domain(cd->domain, server)) goto ok;
+ mem_free(server);
+ return;
+ ok:
+ foreachback (c, cookies) if (is_in_domain(c->domain, server)) if (is_path_prefix(c->path, data)) {
+ if (cookie_expired(c)) {
+ d = c;
+ c = c->prev;
+ del_from_list(d);
+ free_cookie(d);
+ mem_free(d);
+ continue;
+ }
+ if (c->secure && casecmp(url, "https://", 8)) continue;
+ if (!nc) add_to_str(s, l, "Cookie: "), nc = 1;
+ else add_to_str(s, l, "; ");
+ add_to_str(s, l, c->name);
+ if (c->value) {
+ add_to_str(s, l, "=");
+ add_to_str(s, l, c->value);
+ }
+ }
+ if (nc) add_to_str(s, l, "\r\n");
+ mem_free(server);
+}
+
+void init_cookies(void)
+{
+ /* !!! FIXME: read cookies */
+}
+
+void cleanup_cookies(void)
+{
+ struct cookie *c;
+ free_list(c_domains);
+ /* !!! FIXME: save cookies */
+ foreach (c, cookies) free_cookie(c);
+ free_list(cookies);
+}
+