1/*
2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <OS.h>
7#include <KernelExport.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <netinet/in.h>
12#include <arpa/inet.h>
13#include <malloc.h>
14#include <sys/socket.h>
15#include "http_cnx.h"
16#include "googlefs.h"
17#include "google_request.h"
18#include "lists2.h"
19#include "settings.h"
20#include "string_utils.h"
21
22#define DO_PUBLISH
23//#define FAKE_INPUT "/boot/home/devel/drivers/googlefs/log2.html"
24
25//#define TESTURL "http://www.google.com/search?as_q=google+api+&num=50&hl=en&ie=ISO-8859-1&btnG=Google+Search&as_epq=frequently+asked&as_oq=help&as_eq=plop&lr=lang_en&as_ft=i&as_filetype=&as_qdr=m3&as_nlo=&as_nhi=&as_occt=any&as_dt=i&as_sitesearch="
26
27//#define BASEURL "http://www.google.com/search?as_q="
28//#define Q "google+api+"
29//#define EXTRAURL "&num=50&hl=en&ie=ISO-8859-1&btnG=Google+Search&as_epq=frequently+asked&as_oq=help&as_eq=plop&lr=lang_en&as_ft=i&as_filetype=&as_qdr=m3&as_nlo=&as_nhi=&as_occt=any&as_dt=i&as_sitesearch="
30
31#define TESTURL "http://www.google.com/search?hl=en&ie=UTF-8&num=50&q=beos"
32//#define BASEURL "http://www.google.com/search?hl=en&ie=UTF-8&num=50&q="
33#define BASEURL "/search?hl=en&ie=UTF-8&oe=UTF-8"
34#define FMT_NUM "&num=%u"
35#define FMT_Q "&q=%s"
36
37/* parse_google_html.c */
38extern int google_parse_results(const char *html, size_t htmlsize, struct google_result **results);
39
40// move that to ksocket inlined
41static int kinet_aton(const char *in, struct in_addr *addr)
42{
43	int i;
44	unsigned long a;
45	uint32 inaddr = 0L;
46	const char *p = in;
47	for (i = 0; i < 4; i++) {
48		a = strtoul(p, (char **)&p, 10);
49		if (!p)
50			return -1;
51		inaddr = (inaddr >> 8) | ((a & 0x0ff) << 24);
52		*(uint32 *)addr = inaddr;
53		if (!*p)
54			return 0;
55		p++;
56	}
57	return 0;
58}
59
60
61status_t google_request_init(void)
62{
63	status_t err;
64	err = http_init();
65	return err;
66}
67
68status_t google_request_uninit(void)
69{
70	status_t err;
71	err = http_uninit();
72	return err;
73}
74
75status_t google_request_process(struct google_request *req)
76{
77	struct sockaddr_in sin;
78	struct http_cnx *cnx = NULL;
79	struct google_result *res;
80	status_t err;
81	int count;
82	char *p = NULL;
83	char *url = NULL;
84
85	err = http_create(&cnx);
86	if (err)
87		return err;
88	err = ENOMEM;
89	req->cnx = cnx;
90#ifndef FAKE_INPUT
91	sin.sin_len = sizeof(struct sockaddr_in);
92	sin.sin_family = AF_INET;
93	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
94	if (kinet_aton(google_server, &sin.sin_addr) < 0)
95		goto err_cnx;
96	sin.sin_port = htons(google_server_port);
97	err = http_connect(cnx, &sin);
98	dprintf("google_request: http_connect: error 0x%08lx\n", err);
99	if (err)
100		goto err_cnx;
101
102	err = ENOMEM;
103	p = urlify_string(req->query_string);
104	if (!p)
105		goto err_con;
106
107	err = ENOMEM;
108	url = malloc(strlen(BASEURL)+strlen(FMT_NUM)+10+strlen(FMT_Q)+strlen(p)+2);
109	if (!url)
110		goto err_url;
111	strcpy(url, BASEURL);
112	sprintf(url+strlen(url), FMT_NUM, (unsigned int)max_results);
113	sprintf(url+strlen(url), FMT_Q, p);
114
115	dprintf("google_request: final URL: %s\n", url);
116
117	err = http_get(cnx, url);
118	dprintf("google_request: http_get: error 0x%08lx\n", err);
119	if (err < 0)
120		goto err_url2;
121	dprintf("google_request: http_get: HEADERS %ld:%s\n", cnx->headerslen, cnx->headers);
122	//dprintf("DATA: %d:%s\n", cnx->datalen, cnx->data);
123
124	dprintf("google_request: buffer @ %p, len %ld\n", cnx->data, cnx->datalen);
125	{
126		int fd;
127		// debug output
128		fd = open("/tmp/google.html", O_CREAT|O_TRUNC|O_RDWR, 0644);
129		write(fd, cnx->data, cnx->datalen);
130		close(fd);
131	}
132#else
133	{
134		int fd;
135		struct stat st;
136		// debug output
137		fd = open(FAKE_INPUT, O_RDONLY, 0644);
138		if (fd < 0)
139			return -1;
140		if (fstat(fd, &st) < 0) {
141			close(fd);
142			return -1;
143		}
144		cnx->datalen = st.st_size;
145		cnx->data = malloc(cnx->datalen);
146		if (!cnx->data)
147			return ENOMEM;
148		if (read(fd, cnx->data, cnx->datalen) < cnx->datalen)
149			return -1;
150		close(fd);
151	}
152#endif /* FAKE_INPUT */
153	err = count = google_parse_results(req->cnx->data, req->cnx->datalen, &req->results);
154	if (err < 0)
155		goto err_get;
156#ifdef DO_PUBLISH
157	while ((res = SLL_DEQUEUE(req->results, next))) {
158		res->next = NULL;
159		googlefs_push_result_to_query(req, res);
160	}
161#endif
162	free(url);
163	free(p);
164	/* close now */
165	http_close(cnx);
166
167	return B_OK;
168
169
170err_get:
171err_url2:
172	free(url);
173err_url:
174	free(p);
175err_con:
176	http_close(cnx);
177err_cnx:
178	http_delete(cnx);
179	req->cnx = NULL;
180	return err;
181}
182
183status_t google_request_process_async(struct google_request *req)
184{
185	return ENOSYS;
186}
187
188status_t google_request_close(struct google_request *req)
189{
190	if (!req)
191		return EINVAL;
192	if (!req->cnx)
193		return B_OK;
194	http_close(req->cnx);
195	http_delete(req->cnx);
196	req->cnx = NULL;
197	return B_OK;
198}
199
200status_t google_request_open(const char *query_string, struct fs_volume *volume, struct fs_node *query_node, struct google_request **req)
201{
202	struct google_request *r;
203	if (!req)
204		return EINVAL;
205	r = malloc(sizeof(struct google_request));
206	if (!r)
207		return ENOMEM;
208	memset(r, 0, sizeof(struct google_request));
209	r->query_string = strdup(query_string);
210	r->volume = volume;
211	r->query_node = query_node;
212	*req = r;
213	return B_OK;
214}
215
216status_t google_request_free(struct google_request *req)
217{
218	if (!req)
219		return EINVAL;
220	free(req->query_string);
221	free(req);
222	return B_OK;
223}
224