lirc anc lircc are MPlayer-only, so add LDFLAGS for MPlayer link only.
[mplayer/glamo.git] / stream / cookies.c
blobea46c4241997cfe5a678da53e8ce25f83c7511ae
1 /*
2 * HTTP Cookies
3 * Reads Netscape and Mozilla cookies.txt files
5 * by Dave Lambley <mplayer@davel.me.uk>
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <fcntl.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <dirent.h>
15 #include <inttypes.h>
16 #include <limits.h>
18 #include "cookies.h"
19 #include "http.h"
20 #include "mp_msg.h"
22 #define MAX_COOKIES 20
24 char *cookies_file = NULL;
26 typedef struct cookie_list_type {
27 char *name;
28 char *value;
29 char *domain;
30 char *path;
32 int secure;
34 struct cookie_list_type *next;
35 } cookie_list_t;
37 /* Pointer to the linked list of cookies */
38 static struct cookie_list_type *cookie_list = NULL;
41 /* Like strdup, but stops at anything <31. */
42 static char *col_dup(const char *src)
44 char *dst;
45 int length = 0;
47 while (src[length] > 31)
48 length++;
50 dst = malloc(length + 1);
51 strncpy(dst, src, length);
52 dst[length] = 0;
54 return dst;
57 static int right_hand_strcmp(const char *cookie_domain, const char *url_domain)
59 int c_l;
60 int u_l;
62 c_l = strlen(cookie_domain);
63 u_l = strlen(url_domain);
65 if (c_l > u_l)
66 return -1;
67 return strcmp(cookie_domain, url_domain + u_l - c_l);
70 static int left_hand_strcmp(const char *cookie_path, const char *url_path)
72 return strncmp(cookie_path, url_path, strlen(cookie_path));
75 /* Finds the start of all the columns */
76 static int parse_line(char **ptr, char *cols[6])
78 int col;
79 cols[0] = *ptr;
81 for (col = 1; col < 7; col++) {
82 for (; (**ptr) > 31; (*ptr)++);
83 if (**ptr == 0)
84 return 0;
85 (*ptr)++;
86 if ((*ptr)[-1] != 9)
87 return 0;
88 cols[col] = (*ptr);
91 return 1;
94 /* Loads a file into RAM */
95 static char *load_file(const char *filename, off_t * length)
97 int fd;
98 char *buffer;
100 mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename);
102 fd = open(filename, O_RDONLY);
103 if (fd < 0) {
104 mp_msg(MSGT_NETWORK, MSGL_V, "Could not open");
105 return NULL;
108 *length = lseek(fd, 0, SEEK_END);
110 if (*length < 0) {
111 mp_msg(MSGT_NETWORK, MSGL_V, "Could not find EOF");
112 return NULL;
115 if (*length > SIZE_MAX - 1) {
116 mp_msg(MSGT_NETWORK, MSGL_V, "File too big, could not malloc.");
117 return NULL;
120 lseek(fd, SEEK_SET, 0);
122 if (!(buffer = malloc(*length + 1))) {
123 mp_msg(MSGT_NETWORK, MSGL_V, "Could not malloc.");
124 return NULL;
127 if (read(fd, buffer, *length) != *length) {
128 mp_msg(MSGT_NETWORK, MSGL_V, "Read is behaving funny.");
129 return NULL;
131 close(fd);
132 buffer[*length] = 0;
134 return buffer;
137 /* Loads a cookies.txt file into a linked list. */
138 static struct cookie_list_type *load_cookies_from(const char *filename,
139 struct cookie_list_type
140 *list)
142 char *ptr;
143 off_t length;
145 mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename);
147 ptr = load_file(filename, &length);
148 if (!ptr)
149 return list;
151 while (*ptr > 0) {
152 char *cols[7];
153 if (parse_line(&ptr, cols)) {
154 struct cookie_list_type *new;
155 new = malloc(sizeof(cookie_list_t));
156 new->name = col_dup(cols[5]);
157 new->value = col_dup(cols[6]);
158 new->path = col_dup(cols[2]);
159 new->domain = col_dup(cols[0]);
160 new->secure = (*(cols[3]) == 't') || (*(cols[3]) == 'T');
161 new->next = list;
162 list = new;
165 return list;
168 /* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */
169 static struct cookie_list_type *load_cookies(void)
171 DIR *dir;
172 struct dirent *ent;
173 struct cookie_list_type *list = NULL;
174 char *buf;
176 char *homedir;
178 if (cookies_file)
179 return load_cookies_from(cookies_file, list);
181 homedir = getenv("HOME");
182 if (!homedir)
183 return list;
186 buf = malloc(strlen(homedir) + sizeof("/.mozilla/default") + 1);
187 sprintf(buf, "%s/.mozilla/default", homedir);
188 dir = opendir(buf);
189 free(buf);
191 if (dir) {
192 while ((ent = readdir(dir)) != NULL) {
193 if ((ent->d_name)[0] != '.') {
194 buf = malloc(strlen(getenv("HOME")) +
195 sizeof("/.mozilla/default/") +
196 strlen(ent->d_name) + sizeof("cookies.txt") + 1);
197 sprintf(buf, "%s/.mozilla/default/%s/cookies.txt",
198 getenv("HOME"), ent->d_name);
199 list = load_cookies_from(buf, list);
200 free(buf);
203 closedir(dir);
206 buf = malloc(strlen(homedir) + sizeof("/.netscape/cookies.txt") + 1);
207 sprintf(buf, "%s/.netscape/cookies.txt", homedir);
208 list = load_cookies_from(buf, list);
209 free(buf);
211 return list;
214 /* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
215 void
216 cookies_set(HTTP_header_t * http_hdr, const char *domain, const char *url)
218 int found_cookies = 0;
219 struct cookie_list_type *cookies[MAX_COOKIES];
220 struct cookie_list_type *list, *start;
221 int i;
222 char *path;
223 char *buf;
225 path = strchr(url, '/');
226 if (!path)
227 path = "";
229 if (!cookie_list)
230 cookie_list = load_cookies();
233 list = start = cookie_list;
235 /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
236 while (list) {
237 /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
238 if ((right_hand_strcmp(list->domain, domain) == 0)
239 && (left_hand_strcmp(list->path, path) == 0) && !list->secure) {
240 int replacing = 0;
241 for (i = 0; i < found_cookies; i++) {
242 if (strcmp(list->name, cookies[i]->name) == 0) {
243 replacing = 0;
244 if (strlen(list->domain) <= strlen(cookies[i]->domain)) {
245 cookies[i] = list;
246 } else if (strlen(list->path) <= strlen(cookies[i]->path)) {
247 cookies[i] = list;
251 if (found_cookies > MAX_COOKIES) {
252 /* Cookie jar overflow! */
253 break;
255 if (!replacing)
256 cookies[found_cookies++] = list;
258 list = list->next;
262 buf = strdup("Cookie:");
264 for (i = 0; i < found_cookies; i++) {
265 char *nbuf;
267 nbuf = malloc(strlen(buf) + strlen(" ") + strlen(cookies[i]->name) +
268 strlen("=") + strlen(cookies[i]->value) + strlen(";") + 1);
269 sprintf(nbuf, "%s %s=%s;", buf, cookies[i]->name,
270 cookies[i]->value);
271 free(buf);
272 buf = nbuf;
275 if (found_cookies)
276 http_set_field(http_hdr, buf);
277 else
278 free(buf);