blob: ef3fa6a8f6051d1f7d745ba07bd47d0d385b8164 [file] [log] [blame]
adamdunkels92622ca2003-07-30 23:10:49 +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. All advertising materials mentioning features or use of this
15 * software must display the following acknowledgement:
16 * This product includes software developed by Adam Dunkels.
17 * 4. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * This file is part of the Contiki desktop environment
34 *
adamdunkelsf60873b2003-08-29 20:33:32 +000035 * $Id: wget.c,v 1.6 2003/08/29 20:33:32 adamdunkels Exp $
adamdunkels92622ca2003-07-30 23:10:49 +000036 *
37 */
38
39
40#include "ctk.h"
41#include "dispatcher.h"
42#include "webclient.h"
43#include "resolv.h"
44#include "petsciiconv.h"
45#include "uip_main.h"
46#include "loader.h"
47
adamdunkels2c7b6d52003-08-15 18:45:10 +000048#include "program-handler.h"
49
adamdunkels92622ca2003-07-30 23:10:49 +000050#include <c64.h>
51#include <cbm.h>
52#include <stdio.h>
53#include <string.h>
54#include <fcntl.h>
55
adamdunkels0dc09e42003-08-04 00:13:47 +000056#include "c64-dio.h"
adamdunkels92622ca2003-07-30 23:10:49 +000057
58static struct ctk_window window;
59
adamdunkels0dc09e42003-08-04 00:13:47 +000060static struct ctk_label urllabel =
61 {CTK_LABEL(0, 1, 4, 1, "URL:")};
62static char url[80];
63static char urledit[80];
64struct ctk_textentry urltextentry =
65 {CTK_TEXTENTRY(5, 1, 29, 1, urledit, 78)};
66
adamdunkels92622ca2003-07-30 23:10:49 +000067
68static struct ctk_label savefilenamelabel =
adamdunkels0dc09e42003-08-04 00:13:47 +000069 {CTK_LABEL(0, 3, 14, 1, "Save filename:")};
adamdunkels92622ca2003-07-30 23:10:49 +000070static char savefilename[40];
71static struct ctk_textentry savefilenametextentry =
adamdunkels0dc09e42003-08-04 00:13:47 +000072 {CTK_TEXTENTRY(15, 3, 19, 1, savefilename, 38)};
adamdunkels92622ca2003-07-30 23:10:49 +000073
74static struct ctk_button filebutton =
adamdunkels0dc09e42003-08-04 00:13:47 +000075 {CTK_BUTTON(0, 5, 13, "Download file")};
adamdunkels92622ca2003-07-30 23:10:49 +000076
77static struct ctk_button d64button =
adamdunkels0dc09e42003-08-04 00:13:47 +000078 {CTK_BUTTON(17, 5, 18, "Download D64 disk")};
adamdunkels92622ca2003-07-30 23:10:49 +000079
80static struct ctk_label statustext =
adamdunkels0dc09e42003-08-04 00:13:47 +000081 {CTK_LABEL(0, 7, 36, 1, "")};
adamdunkels92622ca2003-07-30 23:10:49 +000082static char statusmsg[40];
83
84static struct ctk_window d64dialog;
85static struct ctk_label overwritelabel =
86 {CTK_LABEL(0, 1, 36, 1, "This will overwrite the entire disk!")};
87static struct ctk_label makesurelabel1 =
88 {CTK_LABEL(7, 3, 22, 1, "Make sure you have the")};
89static struct ctk_label makesurelabel2 =
90 {CTK_LABEL(6, 4, 24, 1, "right disk in the drive!")};
91static struct ctk_button overwritebutton =
92 {CTK_BUTTON(2, 6, 14, "Overwrite disk")};
93static struct ctk_button cancelbutton =
94 {CTK_BUTTON(26, 6, 6, "Cancel")};
95
96static DISPATCHER_SIGHANDLER(wget_sighandler, s, data);
97static struct dispatcher_proc p =
98 {DISPATCHER_PROC("Web downloader", NULL, wget_sighandler, webclient_appcall)};
99static ek_id_t id;
100
101/* State */
102
103#define DLOAD_NONE 0
104#define DLOAD_FILE 1
105#define DLOAD_D64 2
106static u8_t dload_state;
107static unsigned long dload_bytes;
108
109
110
111struct drv_state {
112 u8_t track;
113 u8_t sect;
114};
115
116static struct drv_state ds;
117
118static char buffer[256];
119static u16_t bufferptr;
120
121/*-----------------------------------------------------------------------------------*/
122/* wget_init();
123 *
124 * Initializes and starts the web browser. Called either at startup or
125 * to open the browser window.
126 */
adamdunkels7cde6092003-08-24 22:35:22 +0000127LOADER_INIT_FUNC(wget_init, arg)
adamdunkels92622ca2003-07-30 23:10:49 +0000128{
adamdunkels7cde6092003-08-24 22:35:22 +0000129 if(arg != NULL) {
130 strncpy(url, arg, sizeof(url));
131 strncpy(urledit, arg, sizeof(urledit));
132 petsciiconv_topetscii(urledit, sizeof(urledit));
133 }
134 arg_free(arg);
135
adamdunkels92622ca2003-07-30 23:10:49 +0000136 if(id == EK_ID_NONE) {
137 id = dispatcher_start(&p);
138
139 /* Create the main window. */
adamdunkels0dc09e42003-08-04 00:13:47 +0000140 ctk_window_new(&window, 36, 8, "Web downloader");
adamdunkels92622ca2003-07-30 23:10:49 +0000141
adamdunkels0dc09e42003-08-04 00:13:47 +0000142
143 CTK_WIDGET_ADD(&window, &urllabel);
144 CTK_WIDGET_ADD(&window, &urltextentry);
adamdunkels92622ca2003-07-30 23:10:49 +0000145
146 CTK_WIDGET_ADD(&window, &savefilenamelabel);
147 CTK_WIDGET_ADD(&window, &savefilenametextentry);
148
149 CTK_WIDGET_ADD(&window, &filebutton);
150
151 CTK_WIDGET_ADD(&window, &d64button);
152
153 CTK_WIDGET_ADD(&window, &statustext);
154
adamdunkels0dc09e42003-08-04 00:13:47 +0000155 dload_state = DLOAD_NONE;
156
adamdunkels92622ca2003-07-30 23:10:49 +0000157 memset(savefilename, 0, sizeof(savefilename));
adamdunkels0dc09e42003-08-04 00:13:47 +0000158 memset(url, 0, sizeof(url));
adamdunkels92622ca2003-07-30 23:10:49 +0000159
160 ctk_dialog_new(&d64dialog, 36, 8);
161 CTK_WIDGET_ADD(&d64dialog, &overwritelabel);
162 CTK_WIDGET_ADD(&d64dialog, &makesurelabel1);
163 CTK_WIDGET_ADD(&d64dialog, &makesurelabel2);
164 CTK_WIDGET_ADD(&d64dialog, &overwritebutton);
165 CTK_WIDGET_ADD(&d64dialog, &cancelbutton);
166
167
168 /* Attach as a listener to a number of signals ("Button activate",
169 "Hyperlink activate" and "Hyperlink hover", and the resolver's
170 signal. */
171 dispatcher_listen(ctk_signal_window_close);
172 dispatcher_listen(ctk_signal_button_activate);
adamdunkels0dc09e42003-08-04 00:13:47 +0000173 dispatcher_listen(ctk_signal_hyperlink_activate);
adamdunkels92622ca2003-07-30 23:10:49 +0000174 dispatcher_listen(resolv_signal_found);
175 }
176 ctk_window_open(&window);
177}
178/*-----------------------------------------------------------------------------------*/
179static void
180show_statustext(char *text)
181{
182 ctk_label_set_text(&statustext, text);
183 CTK_WIDGET_REDRAW(&statustext);
184}
185/*-----------------------------------------------------------------------------------*/
186/* open_url():
187 *
188 * Called when the URL present in the global "url" variable should be
189 * opened. It will call the hostname resolver as well as the HTTP
190 * client requester.
191 */
192static void
193start_get(void)
194{
195 u16_t addr[2];
adamdunkels0dc09e42003-08-04 00:13:47 +0000196 unsigned char i;
197 static char host[32];
198 char *file;
199 register char *urlptr;
200 unsigned short port;
201
202 /* Trim off any spaces in the end of the url. */
203 urlptr = url + strlen(url) - 1;
204 while(*urlptr == ' ' && urlptr > url) {
205 *urlptr = 0;
206 --urlptr;
207 }
208
209 /* Don't even try to go further if the URL is empty. */
210 if(urlptr == url) {
211 return;
212 }
213
214 /* See if the URL starts with http://, otherwise prepend it. */
215 if(strncmp(url, http_http, 7) != 0) {
216 while(urlptr >= url) {
217 *(urlptr + 7) = *urlptr;
218 --urlptr;
219 }
220 strncpy(url, http_http, 7);
221 }
222
223 /* Find host part of the URL. */
224 urlptr = &url[7];
225 for(i = 0; i < sizeof(host); ++i) {
226 if(*urlptr == 0 ||
227 *urlptr == '/' ||
228 *urlptr == ' ' ||
229 *urlptr == ':') {
230 host[i] = 0;
231 break;
232 }
233 host[i] = *urlptr;
234 ++urlptr;
235 }
236
237 /* XXX: Here we should find the port part of the URL, but this isn't
238 currently done because of laziness from the programmer's side
239 :-) */
240
241 /* Find file part of the URL. */
242 while(*urlptr != '/' && *urlptr != 0) {
243 ++urlptr;
244 }
245 if(*urlptr == '/') {
246 file = urlptr;
247 } else {
248 file = "/";
249 }
250
adamdunkels92622ca2003-07-30 23:10:49 +0000251
252 /* First check if the host is an IP address. */
253 if(uip_main_ipaddrconv(host, (unsigned char *)addr) == 0) {
254
255 /* Try to lookup the hostname. If it fails, we initiate a hostname
adamdunkels0dc09e42003-08-04 00:13:47 +0000256 lookup and print out an informative message on the
257 statusbar. */
adamdunkels92622ca2003-07-30 23:10:49 +0000258 if(resolv_lookup(host) == NULL) {
259 resolv_query(host);
260 show_statustext("Resolving host...");
261 return;
262 }
263 }
264
265 /* The hostname we present in the hostname table, so we send out the
266 initial GET request. */
267 if(webclient_get(host, 80, file) == 0) {
268 show_statustext("Out of memory error.");
269 } else {
270 show_statustext("Connecting...");
271 }
272}
273/*-----------------------------------------------------------------------------------*/
274static
275DISPATCHER_SIGHANDLER(wget_sighandler, s, data)
276{
277 int ret;
278 static unsigned char i;
279 DISPATCHER_SIGHANDLER_ARGS(s, data);
280
281 if(s == ctk_signal_button_activate) {
282 if(data == (void *)&filebutton) {
adamdunkelsf60873b2003-08-29 20:33:32 +0000283 /* ret = cbm_open(2, 8, 2, savefilename);
284 if(ret == -1) {*/
adamdunkels92622ca2003-07-30 23:10:49 +0000285 sprintf(statusmsg, "Open error with '%s'", savefilename);
286 show_statustext(statusmsg);
adamdunkelsf60873b2003-08-29 20:33:32 +0000287 /* } else {
adamdunkels0dc09e42003-08-04 00:13:47 +0000288 strncpy(url, urledit, sizeof(url));
289 petsciiconv_toascii(url, sizeof(url));
adamdunkels92622ca2003-07-30 23:10:49 +0000290 start_get();
291 dload_bytes = 0;
292 dload_state = DLOAD_FILE;
adamdunkelsf60873b2003-08-29 20:33:32 +0000293 }*/
adamdunkels92622ca2003-07-30 23:10:49 +0000294 } else if(data == (void *)&d64button) {
295 ctk_dialog_open(&d64dialog);
296 } else if(data == (void *)&cancelbutton) {
297 ctk_dialog_close();
298 } else if(data == (void *)&overwritebutton) {
299 ctk_dialog_close();
adamdunkels2c7b6d52003-08-15 18:45:10 +0000300
301 /* Turn of screensaver. */
302 program_handler_screensaver(NULL);
303
adamdunkels0dc09e42003-08-04 00:13:47 +0000304 strncpy(url, urledit, sizeof(url));
305 petsciiconv_toascii(url, sizeof(url));
adamdunkels92622ca2003-07-30 23:10:49 +0000306 start_get();
307 dload_bytes = 0;
308 dload_state = DLOAD_D64;
309 ds.track = 1;
310 ds.sect = 0;
311 bufferptr = 0;
adamdunkels0dc09e42003-08-04 00:13:47 +0000312 /* c64_dio_init(8);*/
313 }
314 } else if(s == ctk_signal_hyperlink_activate) {
315 if(dload_state == DLOAD_NONE) {
316 /* open_link(w->widget.hyperlink.url);*/
317 strncpy(urledit,
318 ((struct ctk_widget *)data)->widget.hyperlink.url, sizeof(urledit));
319 petsciiconv_topetscii(urledit, sizeof(urledit));
320 CTK_WIDGET_REDRAW(&urltextentry);
321 CTK_WIDGET_FOCUS(&window, &urltextentry);
adamdunkels92622ca2003-07-30 23:10:49 +0000322 }
323 } else if(s == resolv_signal_found) {
324 /* Either found a hostname, or not. */
325 if((char *)data != NULL &&
326 resolv_lookup((char *)data) != NULL) {
327 start_get();
328 } else {
329 show_statustext("Host not found.");
330 }
331 } else if(s == ctk_signal_window_close) {
332 dispatcher_exit(&p);
333 id = EK_ID_NONE;
334 LOADER_UNLOAD();
335 }
336}
337/*-----------------------------------------------------------------------------------*/
338/* webclient_aborted():
339 *
340 * Callback function. Called from the webclient when the HTTP
341 * connection was abruptly aborted.
342 */
343void
344webclient_aborted(void)
345{
346 show_statustext("Connection reset by peer");
347}
348/*-----------------------------------------------------------------------------------*/
349/* webclient_timedout():
350 *
351 * Callback function. Called from the webclient when the HTTP
352 * connection timed out.
353 */
354void
355webclient_timedout(void)
356{
357 show_statustext("Connection timed out");
358 if(dload_state == DLOAD_FILE) {
359 cbm_close(2);
360 }
361
362}
363/*-----------------------------------------------------------------------------------*/
364/* webclient_closed():
365 *
366 * Callback function. Called from the webclient when the HTTP
367 * connection was closed after a request from the "webclient_close()"
368 * function. .
369 */
370void
371webclient_closed(void)
372{
373 show_statustext("Done.");
374}
375/*-----------------------------------------------------------------------------------*/
376/* webclient_closed():
377 *
378 * Callback function. Called from the webclient when the HTTP
379 * connection is connected.
380 */
381void
382webclient_connected(void)
383{
384 show_statustext("Request sent...");
385}
386/*-----------------------------------------------------------------------------------*/
adamdunkels92622ca2003-07-30 23:10:49 +0000387static u8_t
388next_sector(void)
389{
390 ++ds.sect;
391 if(ds.track < 18) {
392 if(ds.sect == 21) {
393 ++ds.track;
394 ds.sect = 0;
395 }
396 } else if(ds.track < 25) {
397 if(ds.sect == 19) {
398 ++ds.track;
399 ds.sect = 0;
400 }
401 } else if(ds.track < 31) {
402 if(ds.sect == 18) {
403 ++ds.track;
404 ds.sect = 0;
405 }
406 } else if(ds.track < 36) {
407 if(ds.sect == 17) {
408 ++ds.track;
409 ds.sect = 0;
410 }
411 }
412
413 if(ds.track == 36) {
414 return 1;
415 }
416 return 0;
417}
418/*-----------------------------------------------------------------------------------*/
419static void
420write_buffer(void)
421{
adamdunkels0dc09e42003-08-04 00:13:47 +0000422 /* write_sector(8, ds.track, ds.sect, buffer);*/
adamdunkels0dc09e42003-08-04 00:13:47 +0000423 c64_dio_write_block(ds.track, ds.sect, buffer);
adamdunkels92622ca2003-07-30 23:10:49 +0000424 if(next_sector() != 0) {
425 dload_state = DLOAD_NONE;
426 }
427}
428static void
429handle_d64_data(char *data, u16_t len)
430{
431 u16_t bufferlen;
432
433 while(dload_state == DLOAD_D64 &&
434 len > 0) {
435 bufferlen = sizeof(buffer) - bufferptr;
436 if(len < bufferlen) {
437 bufferlen = len;
438 }
439
440 memcpy(&buffer[bufferptr], data, bufferlen);
441
442 data += bufferlen;
443 bufferptr += bufferlen;
444 len -= bufferlen;
445
446 if(bufferptr == sizeof(buffer)) {
447 write_buffer();
448 bufferptr = 0;
449 }
450 }
451}
452/*-----------------------------------------------------------------------------------*/
453/* webclient_datahandler():
454 *
455 * Callback function. Called from the webclient module when HTTP data
456 * has arrived.
457 */
458void
459webclient_datahandler(char *data, u16_t len)
460{
461 int ret;
462
463 if(len > 0) {
464 dload_bytes += len;
465 sprintf(statusmsg, "Downloading (%lu bytes)", dload_bytes);
466 show_statustext(statusmsg);
467 if(dload_state == DLOAD_D64) {
468 handle_d64_data(data, len);
469 } else if(dload_state == DLOAD_FILE) {
470 ret = cbm_write(2, data, len);
471 if(ret != len) {
472 sprintf(statusmsg, "Wrote only %d bytes", ret);
473 show_statustext(statusmsg);
474 }
475 }
476 }
477
478 if(data == NULL) {
479 if(dload_state == DLOAD_FILE) {
480 cbm_close(2);
481 }
482 dload_state = DLOAD_NONE;
483 sprintf(statusmsg, "Finished downloading %lu bytes", dload_bytes);
484 show_statustext(statusmsg);
485 }
486}
487/*-----------------------------------------------------------------------------------*/