blob: ec74e8a021380a215fc4b6819af248d526aa63bf [file] [log] [blame]
oliverschmidtd1318ec2005-03-29 23:12:31 +00001/*
2 * Copyright (c) 2002, Adam Dunkels.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior
16 * written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * This file is part of the Contiki desktop environment
31 *
oliverschmidtde4a9f62005-04-24 13:37:06 +000032 * $Id: wget.c,v 1.3 2005/04/24 13:37:06 oliverschmidt Exp $
oliverschmidtd1318ec2005-03-29 23:12:31 +000033 *
34 */
35
36
37#include "ctk.h"
38#include "ek.h"
39#include "webclient.h"
40#include "resolv.h"
41#include "uiplib.h"
42#include "loader.h"
oliverschmidtafeda732005-04-12 21:56:30 +000043#include "cfs.h"
oliverschmidtd1318ec2005-03-29 23:12:31 +000044
45#include "contiki.h"
46
47#include "program-handler.h"
48
49#include <string.h>
50#include <stdio.h>
oliverschmidtd1318ec2005-03-29 23:12:31 +000051#include <dio.h>
52
53
54static struct ctk_window window;
55
56static struct ctk_label urllabel =
57 {CTK_LABEL(0, 1, 4, 1, "URL:")};
58static char url[80];
59static char urledit[80];
60struct ctk_textentry urltextentry =
61 {CTK_TEXTENTRY(5, 1, 30, 1, urledit, 78)};
62
63static struct ctk_label savefilenamelabel =
64 {CTK_LABEL(0, 3, 14, 1, "Save filename:")};
65static char savefilename[40];
66static struct ctk_textentry savefilenametextentry =
67 {CTK_TEXTENTRY(15, 3, 20, 1, savefilename, 38)};
68
69static struct ctk_button filebutton =
70 {CTK_BUTTON(0, 5, 16, "Download to file")};
71
72static struct ctk_button dskbutton =
73 {CTK_BUTTON(19, 5, 16, "Download to disk")};
74
75static struct ctk_label statustext =
76 {CTK_LABEL(0, 7, 37, 1, "")};
77static char statusmsg[40];
78
79static struct ctk_window dskdialog;
80static struct ctk_label overwritelabel =
81 {CTK_LABEL(0, 1, 36, 1, "This will overwrite the entire disk!")};
82static struct ctk_label makesurelabel1 =
83 {CTK_LABEL(7, 3, 22, 1, "Make sure you have the")};
84static struct ctk_label makesurelabel2 =
85 {CTK_LABEL(4, 4, 28, 1, "right disk in slot 6 drive 1")};
86static struct ctk_button overwritebutton =
87 {CTK_BUTTON(2, 6, 14, "Overwrite disk")};
88static struct ctk_button cancelbutton =
89 {CTK_BUTTON(26, 6, 6, "Cancel")};
90
91EK_EVENTHANDLER(wget_eventhandler, ev, data);
92EK_PROCESS(p, "Web downloader", EK_PRIO_NORMAL,
93 wget_eventhandler, NULL, NULL);
94static ek_id_t id = EK_ID_NONE;
95
96/* State */
97
98#define DLOAD_NONE 0
99#define DLOAD_FILE 1
100#define DLOAD_DSK 2
101static u8_t dload_state;
102static unsigned long dload_bytes;
103
104static int savefile;
105static void* savedsk;
106
107static char buffer[16][256];
108static u16_t bufferptr;
109static u8_t relsector;
110static u16_t absblock;
111
112/*-----------------------------------------------------------------------------------*/
113/* wget_init();
114 *
115 * Initializes and starts the web browser. Called either at startup or
116 * to open the browser window.
117 */
118LOADER_INIT_FUNC(wget_init, arg)
119{
120 if(arg != NULL) {
121 strncpy(url, arg, sizeof(url));
122 strncpy(urledit, arg, sizeof(urledit));
123 } else {
124#ifdef WGET_CONF_URL
125 strncpy(url, WGET_CONF_URL, sizeof(url));
126 strncpy(urledit, WGET_CONF_URL, sizeof(urledit));
127#endif /* WGET_CONF_URL */
128 }
129 arg_free(arg);
130
131 if(id == EK_ID_NONE) {
132 id = ek_start(&p);
133
134 }
135}
136/*-----------------------------------------------------------------------------------*/
137static void
138show_statustext(char *text)
139{
140 ctk_label_set_text(&statustext, text);
141 CTK_WIDGET_REDRAW(&statustext);
142}
143/*-----------------------------------------------------------------------------------*/
144static void
145dload_close(char *text)
146{
147 show_statustext(text);
148 if(dload_state == DLOAD_FILE) {
oliverschmidtafeda732005-04-12 21:56:30 +0000149 cfs_close(savefile);
oliverschmidtd1318ec2005-03-29 23:12:31 +0000150 } else if(dload_state == DLOAD_DSK) {
151 dio_close(savedsk);
152 }
153 dload_state = DLOAD_NONE;
154 webclient_close();
155}
156/*-----------------------------------------------------------------------------------*/
157/* open_url():
158 *
159 * Called when the URL present in the global "url" variable should be
160 * opened. It will call the hostname resolver as well as the HTTP
161 * client requester.
162 */
163static void
164start_get(void)
165{
166 u16_t addr[2];
167 unsigned char i;
168 static char host[32];
169 char *file;
170 register char *urlptr;
171
172 /* Trim off any spaces in the end of the url. */
173 urlptr = url + strlen(url) - 1;
174 while(*urlptr == ' ' && urlptr > url) {
175 *urlptr = 0;
176 --urlptr;
177 }
178
179 /* Don't even try to go further if the URL is empty. */
180 if(urlptr == url) {
181 return;
182 }
183
184 /* See if the URL starts with http://, otherwise prepend it. */
185 if(strncmp(url, http_http, 7) != 0) {
186 while(urlptr >= url) {
187 *(urlptr + 7) = *urlptr;
188 --urlptr;
189 }
190 strncpy(url, http_http, 7);
191 }
192
193 /* Find host part of the URL. */
194 urlptr = &url[7];
195 for(i = 0; i < sizeof(host); ++i) {
196 if(*urlptr == 0 ||
197 *urlptr == '/' ||
198 *urlptr == ' ' ||
199 *urlptr == ':') {
200 host[i] = 0;
201 break;
202 }
203 host[i] = *urlptr;
204 ++urlptr;
205 }
206
207 /* XXX: Here we should find the port part of the URL, but this isn't
208 currently done because of laziness from the programmer's side
209 :-) */
210
211 /* Find file part of the URL. */
212 while(*urlptr != '/' && *urlptr != 0) {
213 ++urlptr;
214 }
215 if(*urlptr == '/') {
216 file = urlptr;
217 } else {
218 file = "/";
219 }
220
221 /* First check if the host is an IP address. */
222 if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) {
223
224 /* Try to lookup the hostname. If it fails, we initiate a hostname
225 lookup and print out an informative message on the
226 statusbar. */
227 if(resolv_lookup(host) == NULL) {
228 resolv_query(host);
229 show_statustext("Resolving host...");
230 return;
231 }
232 }
233
234 /* The hostname we present in the hostname table, so we send out the
235 initial GET request. */
236 if(webclient_get(host, 80, file) == 0) {
237 show_statustext("Out of memory error.");
238 } else {
239 show_statustext("Connecting...");
240 }
241}
242/*-----------------------------------------------------------------------------------*/
243EK_EVENTHANDLER(wget_eventhandler, ev, data)
244{
245 EK_EVENTHANDLER_ARGS(ev, data);
246
247 if(ev == EK_EVENT_INIT) {
248 /* Create the main window. */
249 ctk_window_new(&window, 37, 8, "Web downloader");
250
251 CTK_WIDGET_ADD(&window, &urllabel);
252 CTK_WIDGET_ADD(&window, &urltextentry);
oliverschmidtafeda732005-04-12 21:56:30 +0000253 CTK_WIDGET_ADD(&window, &savefilenamelabel);
254 CTK_WIDGET_ADD(&window, &savefilenametextentry);
255 CTK_WIDGET_ADD(&window, &filebutton);
oliverschmidtd1318ec2005-03-29 23:12:31 +0000256 CTK_WIDGET_ADD(&window, &dskbutton);
257 CTK_WIDGET_ADD(&window, &statustext);
258
oliverschmidtde4a9f62005-04-24 13:37:06 +0000259 CTK_WIDGET_FOCUS(&window, &urltextentry);
260
oliverschmidtd1318ec2005-03-29 23:12:31 +0000261 dload_state = DLOAD_NONE;
262
263 memset(savefilename, 0, sizeof(savefilename));
264 memset(url, 0, sizeof(url));
265
266 ctk_dialog_new(&dskdialog, 36, 8);
267 CTK_WIDGET_ADD(&dskdialog, &overwritelabel);
268 CTK_WIDGET_ADD(&dskdialog, &makesurelabel1);
269 CTK_WIDGET_ADD(&dskdialog, &makesurelabel2);
270 CTK_WIDGET_ADD(&dskdialog, &overwritebutton);
271 CTK_WIDGET_ADD(&dskdialog, &cancelbutton);
272
oliverschmidtde4a9f62005-04-24 13:37:06 +0000273 CTK_WIDGET_FOCUS(&dskdialog, &cancelbutton);
274
oliverschmidtd1318ec2005-03-29 23:12:31 +0000275 ctk_window_open(&window);
276 } else if(ev == tcpip_event) {
277 webclient_appcall(data);
278 } else if(ev == ctk_signal_button_activate) {
279 if(data == (void *)&filebutton) {
oliverschmidtafeda732005-04-12 21:56:30 +0000280 dload_close("");
281 savefile = cfs_open(savefilename, CFS_WRITE);
oliverschmidtd1318ec2005-03-29 23:12:31 +0000282 if(savefile == -1) {
283 sprintf(statusmsg, "Open error with '%s'", savefilename);
284 show_statustext(statusmsg);
285 } else {
286 strncpy(url, urledit, sizeof(url));
287 start_get();
288 dload_bytes = 0;
289 dload_state = DLOAD_FILE;
290 }
291 } else if(data == (void *)&dskbutton) {
292 ctk_dialog_open(&dskdialog);
293 } else if(data == (void *)&cancelbutton) {
294 ctk_dialog_close();
295 } else if(data == (void *)&overwritebutton) {
296 ctk_dialog_close();
oliverschmidtafeda732005-04-12 21:56:30 +0000297 dload_close("");
oliverschmidtd1318ec2005-03-29 23:12:31 +0000298 savedsk = dio_open(/*slot*/6 * 2 + /*drive*/1 - 1);
299 if(savedsk == NULL) {
300 sprintf(statusmsg, "Access error with slot 6 drive 1");
301 show_statustext(statusmsg);
302 } else {
303 strncpy(url, urledit, sizeof(url));
304 start_get();
305 dload_bytes = 0;
306 dload_state = DLOAD_DSK;
307 bufferptr = 0;
308 relsector = 0;
309 absblock = 0;
310 }
311 }
312 } else if(ev == ctk_signal_hyperlink_activate) {
313 if(dload_state == DLOAD_NONE) {
314 /* open_link(w->widget.hyperlink.url);*/
315 strncpy(urledit,
316 ((struct ctk_widget *)data)->widget.hyperlink.url, sizeof(urledit));
317 CTK_WIDGET_REDRAW(&urltextentry);
318 CTK_WIDGET_FOCUS(&window, &urltextentry);
319 }
320 } else if(ev == resolv_event_found) {
321 /* Either found a hostname, or not. */
322 if((char *)data != NULL &&
323 resolv_lookup((char *)data) != NULL) {
324 start_get();
325 } else {
326 show_statustext("Host not found.");
327 }
328 } else if(ev == ctk_signal_window_close) {
oliverschmidtafeda732005-04-12 21:56:30 +0000329 dload_close("");
oliverschmidtd1318ec2005-03-29 23:12:31 +0000330 ek_exit();
331 id = EK_ID_NONE;
332 LOADER_UNLOAD();
333 }
334}
335/*-----------------------------------------------------------------------------------*/
336/* webclient_aborted():
337 *
338 * Callback function. Called from the webclient when the HTTP
339 * connection was abruptly aborted.
340 */
341void
342webclient_aborted(void)
343{
344 show_statustext("Connection reset by peer");
345}
346/*-----------------------------------------------------------------------------------*/
347/* webclient_timedout():
348 *
349 * Callback function. Called from the webclient when the HTTP
350 * connection timed out.
351 */
352void
353webclient_timedout(void)
354{
355 dload_close("Connection timed out");
356}
357/*-----------------------------------------------------------------------------------*/
358/* webclient_closed():
359 *
360 * Callback function. Called from the webclient when the HTTP
361 * connection was closed after a request from the "webclient_close()"
362 * function. .
363 */
364void
365webclient_closed(void)
366{
367 if(dload_state == DLOAD_NONE) {
368 return;
369 }
370 show_statustext("Done.");
371}
372/*-----------------------------------------------------------------------------------*/
373/* webclient_closed():
374 *
375 * Callback function. Called from the webclient when the HTTP
376 * connection is connected.
377 */
378void
379webclient_connected(void)
380{
381 show_statustext("Request sent...");
382}
383/*-----------------------------------------------------------------------------------*/
384static unsigned char
385write_buffer(void)
386{
387 u8_t sector;
388
389 for(sector = 0; sector < 16; sector += 2) {
390 if(dio_write(savedsk, absblock++, buffer[sector]) != 0) {
391 return 0;
392 }
393 }
394 return 1;
395}
396/*-----------------------------------------------------------------------------------*/
397static unsigned char
398handle_dsk_data(char *data, u16_t len)
399{
400 static u8_t skew[16] = {0x0, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8,
401 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xF};
402 u16_t bufferlen;
403
404 while(len > 0) {
405 bufferlen = sizeof(buffer[0]) - bufferptr;
406 if(len < bufferlen) {
407 bufferlen = len;
408 }
409
410 memcpy(&buffer[skew[relsector]][bufferptr], data, bufferlen);
411
412 data += bufferlen;
413 bufferptr += bufferlen;
414 len -= bufferlen;
415
416 if(bufferptr == sizeof(buffer[0])) {
417 bufferptr = 0;
418 if(++relsector == 16) {
419 relsector = 0;
420 if(write_buffer() == 0) {
421 return 0;
422 }
423 }
424 }
425 }
426 return 1;
427}
428/*-----------------------------------------------------------------------------------*/
429/* webclient_datahandler():
430 *
431 * Callback function. Called from the webclient module when HTTP data
432 * has arrived.
433 */
434void
435webclient_datahandler(char *data, u16_t len)
436{
437 int ret;
438
439 if(len > 0) {
440 dload_bytes += len;
441 sprintf(statusmsg, "Downloading (%lu bytes)", dload_bytes);
442 show_statustext(statusmsg);
443 if(dload_state == DLOAD_DSK) {
444 if(handle_dsk_data(data, len) == 0) {
445 dload_close("Write error with slot 6 drive 1");
446 }
447 } else if(dload_state == DLOAD_FILE) {
oliverschmidtafeda732005-04-12 21:56:30 +0000448 ret = cfs_write(savefile, data, len);
oliverschmidtd1318ec2005-03-29 23:12:31 +0000449 if(ret != len) {
450 sprintf(statusmsg, "Wrote only %d bytes", ret);
451 dload_close(statusmsg);
452 }
453 }
454 }
455
456 if(data == NULL) {
457 sprintf(statusmsg, "Finished downloading %lu bytes", dload_bytes);
458 dload_close(statusmsg);
459 }
460}
461/*-----------------------------------------------------------------------------------*/