ao_pulse: support native mute control
[mplayer.git] / stream / cookies.c
blobe50274a2489ef06d70c5edb605079ff9f0f94003
1 /*
2 * HTTP Cookies
3 * Reads Netscape and Mozilla cookies.txt files
5 * Copyright (c) 2003 Dave Lambley <mplayer@davel.me.uk>
7 * This file is part of MPlayer.
9 * MPlayer is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * MPlayer is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <dirent.h>
31 #include <inttypes.h>
32 #include <limits.h>
34 #include "osdep/io.h"
36 #include "cookies.h"
37 #include "http.h"
38 #include "mp_msg.h"
40 #define MAX_COOKIES 20
42 char *cookies_file = NULL;
44 typedef struct cookie_list_type {
45 char *name;
46 char *value;
47 char *domain;
48 char *path;
50 int secure;
52 struct cookie_list_type *next;
53 } cookie_list_t;
55 /* Pointer to the linked list of cookies */
56 static struct cookie_list_type *cookie_list = NULL;
59 /* Like strdup, but stops at anything <31. */
60 static char *col_dup(const char *src)
62 char *dst;
63 int length = 0;
65 while (src[length] > 31)
66 length++;
68 dst = malloc(length + 1);
69 strncpy(dst, src, length);
70 dst[length] = 0;
72 return dst;
75 static int right_hand_strcmp(const char *cookie_domain, const char *url_domain)
77 int c_l;
78 int u_l;
80 c_l = strlen(cookie_domain);
81 u_l = strlen(url_domain);
83 if (c_l > u_l)
84 return -1;
85 return strcmp(cookie_domain, url_domain + u_l - c_l);
88 static int left_hand_strcmp(const char *cookie_path, const char *url_path)
90 return strncmp(cookie_path, url_path, strlen(cookie_path));
93 /* Finds the start of all the columns */
94 static int parse_line(char **ptr, char *cols[6])
96 int col;
97 cols[0] = *ptr;
99 for (col = 1; col < 7; col++) {
100 for (; (**ptr) > 31; (*ptr)++);
101 if (**ptr == 0)
102 return 0;
103 (*ptr)++;
104 if ((*ptr)[-1] != 9)
105 return 0;
106 cols[col] = (*ptr);
109 return 1;
112 /* Loads a file into RAM */
113 static char *load_file(const char *filename, off_t * length)
115 int fd;
116 char *buffer;
118 mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename);
120 fd = open(filename, O_RDONLY);
121 if (fd < 0) {
122 mp_msg(MSGT_NETWORK, MSGL_V, "Could not open");
123 return NULL;
126 *length = lseek(fd, 0, SEEK_END);
128 if (*length < 0) {
129 mp_msg(MSGT_NETWORK, MSGL_V, "Could not find EOF");
130 return NULL;
133 if (*length > SIZE_MAX - 1) {
134 mp_msg(MSGT_NETWORK, MSGL_V, "File too big, could not malloc.");
135 return NULL;
138 lseek(fd, 0, SEEK_SET);
140 if (!(buffer = malloc(*length + 1))) {
141 mp_msg(MSGT_NETWORK, MSGL_V, "Could not malloc.");
142 return NULL;
145 if (read(fd, buffer, *length) != *length) {
146 mp_msg(MSGT_NETWORK, MSGL_V, "Read is behaving funny.");
147 return NULL;
149 close(fd);
150 buffer[*length] = 0;
152 return buffer;
155 /* Loads a cookies.txt file into a linked list. */
156 static struct cookie_list_type *load_cookies_from(const char *filename,
157 struct cookie_list_type
158 *list)
160 char *ptr;
161 off_t length;
163 ptr = load_file(filename, &length);
164 if (!ptr)
165 return list;
167 while (*ptr > 0) {
168 char *cols[7];
169 if (parse_line(&ptr, cols)) {
170 struct cookie_list_type *new;
171 new = malloc(sizeof(cookie_list_t));
172 new->name = col_dup(cols[5]);
173 new->value = col_dup(cols[6]);
174 new->path = col_dup(cols[2]);
175 new->domain = col_dup(cols[0]);
176 new->secure = (*(cols[3]) == 't') || (*(cols[3]) == 'T');
177 new->next = list;
178 list = new;
181 return list;
184 /* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */
185 static struct cookie_list_type *load_cookies(void)
187 DIR *dir;
188 struct dirent *ent;
189 struct cookie_list_type *list = NULL;
190 char *buf;
192 char *homedir;
194 if (cookies_file)
195 return load_cookies_from(cookies_file, list);
197 homedir = getenv("HOME");
198 if (!homedir)
199 return list;
202 buf = malloc(strlen(homedir) + sizeof("/.mozilla/default") + 1);
203 sprintf(buf, "%s/.mozilla/default", homedir);
204 dir = opendir(buf);
205 free(buf);
207 if (dir) {
208 while ((ent = readdir(dir)) != NULL) {
209 if ((ent->d_name)[0] != '.') {
210 buf = malloc(strlen(getenv("HOME")) +
211 sizeof("/.mozilla/default/") +
212 strlen(ent->d_name) + sizeof("cookies.txt") + 1);
213 sprintf(buf, "%s/.mozilla/default/%s/cookies.txt",
214 getenv("HOME"), ent->d_name);
215 list = load_cookies_from(buf, list);
216 free(buf);
219 closedir(dir);
222 buf = malloc(strlen(homedir) + sizeof("/.netscape/cookies.txt") + 1);
223 sprintf(buf, "%s/.netscape/cookies.txt", homedir);
224 list = load_cookies_from(buf, list);
225 free(buf);
227 return list;
230 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
231 void
232 cookies_set(HTTP_header_t * http_hdr, const char *domain, const char *url)
234 int found_cookies = 0;
235 struct cookie_list_type *cookies[MAX_COOKIES];
236 struct cookie_list_type *list, *start;
237 int i;
238 char *path;
239 char *buf;
241 path = strchr(url, '/');
242 if (!path)
243 path = "";
245 if (!cookie_list)
246 cookie_list = load_cookies();
249 list = start = cookie_list;
251 /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
252 while (list) {
253 /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
254 if ((right_hand_strcmp(list->domain, domain) == 0)
255 && (left_hand_strcmp(list->path, path) == 0) && !list->secure) {
256 int replacing = 0;
257 for (i = 0; i < found_cookies; i++) {
258 if (strcmp(list->name, cookies[i]->name) == 0) {
259 replacing = 0;
260 if (strlen(list->domain) <= strlen(cookies[i]->domain)) {
261 cookies[i] = list;
262 } else if (strlen(list->path) <= strlen(cookies[i]->path)) {
263 cookies[i] = list;
267 if (found_cookies > MAX_COOKIES) {
268 /* Cookie jar overflow! */
269 break;
271 if (!replacing)
272 cookies[found_cookies++] = list;
274 list = list->next;
278 buf = strdup("Cookie:");
280 for (i = 0; i < found_cookies; i++) {
281 char *nbuf;
283 nbuf = malloc(strlen(buf) + strlen(" ") + strlen(cookies[i]->name) +
284 strlen("=") + strlen(cookies[i]->value) + strlen(";") + 1);
285 sprintf(nbuf, "%s %s=%s;", buf, cookies[i]->name,
286 cookies[i]->value);
287 free(buf);
288 buf = nbuf;
291 if (found_cookies)
292 http_set_field(http_hdr, buf);
293 else
294 free(buf);