Contiki 3.x
www.c
1 /*
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  *
32  *
33  */
34 
35 #include <string.h>
36 #include <stddef.h>
37 
38 #include "ctk/ctk.h"
39 #include "ctk/ctk-textentry-cmdline.h"
40 #include "contiki-net.h"
41 #include "lib/petsciiconv.h"
42 #include "sys/arg.h"
43 #if WWW_CONF_WITH_WGET
44 #include "program-handler.h"
45 #endif /* WWW_CONF_WITH_WGET */
46 
47 #include "webclient.h"
48 #include "htmlparser.h"
49 #include "http-strings.h"
50 
51 #include "www.h"
52 
53 #if 1
54 #define PRINTF(x)
55 #else
56 #include <stdio.h>
57 #define PRINTF(x) printf x
58 #endif
59 
60 
61 /* The array that holds the current URL. */
62 static char url[WWW_CONF_MAX_URLLEN + 1];
63 
64 /* The array that holds the web page text. */
65 static char webpage[WWW_CONF_WEBPAGE_WIDTH *
66  WWW_CONF_WEBPAGE_HEIGHT + 1];
67 
68 /* The CTK widgets for the main window. */
69 static struct ctk_window mainwindow;
70 
71 #if WWW_CONF_HISTORY_SIZE > 0
72 static struct ctk_button backbutton =
73  {CTK_BUTTON(0, 0, 4, "Back")};
74 static struct ctk_button downbutton =
75  {CTK_BUTTON(10, 0, 4, "Down")};
76 #else /* WWW_CONF_HISTORY_SIZE > 0 */
77 static struct ctk_button downbutton =
78  {CTK_BUTTON(0, 0, 4, "Down")};
79 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
80 static struct ctk_button stopbutton =
81  {CTK_BUTTON(WWW_CONF_WEBPAGE_WIDTH - 16, 0, 4, "Stop")};
82 static struct ctk_button gobutton =
83  {CTK_BUTTON(WWW_CONF_WEBPAGE_WIDTH - 4, 0, 2, "Go")};
84 
85 static struct ctk_separator sep1 =
86  {CTK_SEPARATOR(0, 2, WWW_CONF_WEBPAGE_WIDTH)};
87 
88 static char editurl[WWW_CONF_MAX_URLLEN + 1];
89 static struct ctk_textentry urlentry =
90  {CTK_TEXTENTRY(0, 1, WWW_CONF_WEBPAGE_WIDTH - 2,
91  1, editurl, WWW_CONF_MAX_URLLEN)};
92 static struct ctk_label webpagelabel =
93  {CTK_LABEL(0, 3, WWW_CONF_WEBPAGE_WIDTH,
94  WWW_CONF_WEBPAGE_HEIGHT, webpage)};
95 
96 static char statustexturl[WWW_CONF_WEBPAGE_WIDTH];
97 static struct ctk_label statustext =
98  {CTK_LABEL(0, WWW_CONF_WEBPAGE_HEIGHT + 4,
99  WWW_CONF_WEBPAGE_WIDTH, 1, "")};
100 static struct ctk_separator sep2 =
101  {CTK_SEPARATOR(0, WWW_CONF_WEBPAGE_HEIGHT + 3,
102  WWW_CONF_WEBPAGE_WIDTH)};
103 
104 #if WWW_CONF_WITH_WGET || defined(WWW_CONF_WGET_EXEC)
105 #if CTK_CONF_WINDOWS
106 static struct ctk_window wgetdialog;
107 static struct ctk_label wgetlabel1 =
108  {CTK_LABEL(1, 1, 34, 1, "This web page cannot be displayed.")};
109 static struct ctk_label wgetlabel2 =
110  {CTK_LABEL(1, 3, 35, 1, "Would you like to download instead?")};
111 static struct ctk_button wgetnobutton =
112  {CTK_BUTTON(1, 5, 6, "Cancel")};
113 static struct ctk_button wgetyesbutton =
114  {CTK_BUTTON(11, 5, 24, "Close browser & download")};
115 #else /* CTK_CONF_WINDOWS */
116 static struct ctk_button wgetnobutton =
117  {CTK_BUTTON((WWW_CONF_WEBPAGE_WIDTH - 38) / 2 + 1,
118  11, 6, "Cancel")};
119 static struct ctk_button wgetyesbutton =
120  {CTK_BUTTON((WWW_CONF_WEBPAGE_WIDTH - 38) / 2 + 11,
121  11, 24, "Close browser & download")};
122 #endif /* CTK_CONF_WINDOWS */
123 #endif /* WWW_CONF_WITH_WGET || WWW_CONF_WGET_EXEC */
124 
125 #if WWW_CONF_HISTORY_SIZE > 0
126 /* The char arrays that hold the history of visited URLs. */
127 static char history[WWW_CONF_HISTORY_SIZE][WWW_CONF_MAX_URLLEN];
128 static char history_last;
129 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
130 
131 struct linkattrib {
132  struct ctk_hyperlink hyperlink;
133  char url[1];
134 };
135 
136 struct inputattrib;
137 
138 struct formattrib {
139  struct inputattrib *nextptr;
140  char action[1];
141 };
142 
143 struct inputattrib {
144  struct inputattrib *nextptr;
145  struct formattrib *formptr;
146  struct ctk_widget widget;
147 };
148 
149 struct textattrib {
150  struct inputattrib *nextptr;
151  struct formattrib *formptr;
152  struct ctk_textentry textentry;
153  char name[1];
154 };
155 
156 struct submitattrib {
157  struct inputattrib *nextptr;
158  struct formattrib *formptr;
159  struct ctk_button button;
160  char name[1];
161 };
162 
163 static char pageattribs[WWW_CONF_PAGEATTRIB_SIZE];
164 static char *pageattribptr;
165 
166 #if WWW_CONF_FORMS
167 static struct formattrib *formptr;
168 static struct inputattrib *currptr;
169 #endif /* WWW_CONF_FORMS */
170 
171 #define ISO_nl 0x0a
172 #define ISO_space 0x20
173 #define ISO_ampersand 0x26
174 #define ISO_plus 0x2b
175 #define ISO_slash 0x2f
176 #define ISO_eq 0x3d
177 #define ISO_questionmark 0x3f
178 
179 /* The state of the rendering code. */
180 static char *webpageptr;
181 static unsigned char x, y;
182 static unsigned char loading;
183 static unsigned short firsty, pagey;
184 
185 static unsigned char count;
186 static char receivingmsgs[4][23] = {
187  "Receiving web page ...",
188  "Receiving web page. ..",
189  "Receiving web page.. .",
190  "Receiving web page... "
191 };
192 
193 PROCESS(www_process, "Web browser");
194 
195 AUTOSTART_PROCESSES(&www_process);
196 
197 static void CC_FASTCALL formsubmit(struct formattrib *form);
198 
199 /*-----------------------------------------------------------------------------------*/
200 /* make_window()
201  *
202  * Creates the web browser's window.
203  */
204 static void
205 make_window(void)
206 {
207 #if WWW_CONF_HISTORY_SIZE > 0
208  CTK_WIDGET_ADD(&mainwindow, &backbutton);
209 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
210  CTK_WIDGET_ADD(&mainwindow, &downbutton);
211  CTK_WIDGET_ADD(&mainwindow, &stopbutton);
212  CTK_WIDGET_ADD(&mainwindow, &gobutton);
213  CTK_WIDGET_ADD(&mainwindow, &urlentry);
214  CTK_WIDGET_ADD(&mainwindow, &sep1);
215  CTK_WIDGET_ADD(&mainwindow, &webpagelabel);
216  CTK_WIDGET_SET_FLAG(&webpagelabel, CTK_WIDGET_FLAG_MONOSPACE);
217  CTK_WIDGET_ADD(&mainwindow, &sep2);
218  CTK_WIDGET_ADD(&mainwindow, &statustext);
219 
220  pageattribptr = pageattribs;
221 }
222 /*-----------------------------------------------------------------------------------*/
223 /* redraw_window():
224  *
225  * Convenience function that calls upon CTK to redraw the browser
226  * window. */
227 static void
228 redraw_window(void)
229 {
230  ctk_window_redraw(&mainwindow);
231 }
232 /*-----------------------------------------------------------------------------------*/
233 static char * CC_FASTCALL
234 add_pageattrib(unsigned size)
235 {
236  char *ptr;
237 
238  if(pageattribptr + size > pageattribs + sizeof(pageattribs)) {
239  return NULL;
240  }
241  ptr = pageattribptr;
242  pageattribptr += size;
243  return ptr;
244 }
245 /*-----------------------------------------------------------------------------------*/
246 #if WWW_CONF_FORMS
247 static void CC_FASTCALL
248 add_forminput(struct inputattrib *inputptr)
249 {
250  inputptr->nextptr = NULL;
251  currptr->nextptr = inputptr;
252  currptr = inputptr;
253 }
254 #endif /* WWW_CONF_FORMS */
255 /*-----------------------------------------------------------------------------------*/
256 static void
257 clear_page(void)
258 {
259  ctk_window_clear(&mainwindow);
260  make_window();
261  memset(webpage, 0, WWW_CONF_WEBPAGE_WIDTH * WWW_CONF_WEBPAGE_HEIGHT);
262  redraw_window();
263 }
264 /*-----------------------------------------------------------------------------------*/
265 static void
266 show_url(void)
267 {
268  memcpy(editurl, url, WWW_CONF_MAX_URLLEN);
269  strncpy(editurl, "http://", 7);
270  petsciiconv_topetscii(editurl + 7, WWW_CONF_MAX_URLLEN - 7);
271  CTK_WIDGET_REDRAW(&urlentry);
272 }
273 /*-----------------------------------------------------------------------------------*/
274 static void
275 start_loading(void)
276 {
277  loading = 1;
278  x = y = 0;
279  pagey = 0;
280  webpageptr = webpage;
281 
282  clear_page();
283 }
284 /*-----------------------------------------------------------------------------------*/
285 static void CC_FASTCALL
286 show_statustext(char *text)
287 {
288  ctk_label_set_text(&statustext, text);
289  CTK_WIDGET_REDRAW(&statustext);
290 }
291 /*-----------------------------------------------------------------------------------*/
292 /* open_url():
293  *
294  * Called when the URL present in the global "url" variable should be
295  * opened. It will call the hostname resolver as well as the HTTP
296  * client requester.
297  */
298 static void
299 open_url(void)
300 {
301  unsigned char i;
302  static char host[32];
303  char *file;
304  register char *urlptr;
305  static uip_ipaddr_t addr;
306 
307  /* Trim off any spaces in the end of the url. */
308  urlptr = url + strlen(url) - 1;
309  while(*urlptr == ' ' && urlptr > url) {
310  *urlptr = 0;
311  --urlptr;
312  }
313 
314  /* Don't even try to go further if the URL is empty. */
315  if(urlptr == url) {
316  return;
317  }
318 
319  /* See if the URL starts with http://, otherwise prepend it. */
320  if(strncmp(url, http_http, 7) != 0) {
321  while(urlptr >= url) {
322  *(urlptr + 7) = *urlptr;
323  --urlptr;
324  }
325  strncpy(url, http_http, 7);
326  }
327 
328  /* Find host part of the URL. */
329  urlptr = &url[7];
330  for(i = 0; i < sizeof(host); ++i) {
331  if(*urlptr == 0 ||
332  *urlptr == '/' ||
333  *urlptr == ' ' ||
334  *urlptr == ':') {
335  host[i] = 0;
336  break;
337  }
338  host[i] = *urlptr;
339  ++urlptr;
340  }
341 
342  /* XXX: Here we should find the port part of the URL, but this isn't
343  currently done because of laziness from the programmer's side
344  :-) */
345 
346  /* Find file part of the URL. */
347  while(*urlptr != '/' && *urlptr != 0) {
348  ++urlptr;
349  }
350  if(*urlptr == '/') {
351  file = urlptr;
352  } else {
353  file = "/";
354  }
355 
356 #if UIP_UDP
357  /* Try to lookup the hostname. If it fails, we initiate a hostname
358  lookup and print out an informative message on the statusbar. */
359  if(uiplib_ipaddrconv(host, &addr) == 0) {
360  uip_ipaddr_t *addrptr;
361  if(resolv_lookup(host, &addrptr) != RESOLV_STATUS_CACHED) {
362  resolv_query(host);
363  show_statustext("Resolving host...");
364  return;
365  }
366  uip_ipaddr_copy(&addr, addrptr);
367  }
368 #else /* UIP_UDP */
369  uiplib_ipaddrconv(host, &addr);
370 #endif /* UIP_UDP */
371 
372  /* The hostname we present in the hostname table, so we send out the
373  initial GET request. */
374  if(webclient_get(host, 80, file) == 0) {
375  show_statustext("Out of memory error");
376  } else {
377  show_statustext("Connecting...");
378  }
379  redraw_window();
380 }
381 /*-----------------------------------------------------------------------------------*/
382 /* set_link(link):
383  *
384  * Will format a link from the current web pages so that it suits the
385  * open_url() function.
386  */
387 static void CC_FASTCALL
388 set_link(char *link)
389 {
390  register char *urlptr;
391 
392  if(strncmp(link, http_http, 7) == 0) {
393  /* The link starts with http://. We just copy the contents of the
394  link into the url string and jump away. */
395  strncpy(url, link, WWW_CONF_MAX_URLLEN);
396  } else if(*link == ISO_slash &&
397  *(link + 1) == ISO_slash) {
398  /* The link starts with //, so we'll copy it into the url
399  variable, starting after the http (which already is present in
400  the url variable since we were able to open the web page on
401  which this link was found in the first place). */
402  strncpy(&url[5], link, WWW_CONF_MAX_URLLEN);
403  } else if(*link == ISO_slash) {
404  /* The link starts with a slash, so it is a non-relative link
405  within the same web site. We find the start of the filename of
406  the current URL and paste the contents of this link there, and
407  head off to the new URL. */
408  for(urlptr = &url[7];
409  *urlptr != 0 && *urlptr != ISO_slash;
410  ++urlptr);
411  strncpy(urlptr, link, WWW_CONF_MAX_URLLEN - (urlptr - url));
412  } else {
413  /* A fully relative link is found. We find the last slash in the
414  current URL and paste the link there. */
415 
416  /* XXX: we should really parse any ../ in the link as well. */
417  for(urlptr = url + strlen(url);
418  urlptr != url && *urlptr != ISO_slash;
419  --urlptr);
420  ++urlptr;
421  strncpy(urlptr, link, WWW_CONF_MAX_URLLEN - (urlptr - url));
422  }
423 }
424 /*-----------------------------------------------------------------------------------*/
425 #if WWW_CONF_HISTORY_SIZE > 0
426 /* log_back():
427  *
428  * Copies the current URL from the url variable and into the log for
429  * the back button.
430  */
431 static void
432 log_back(void)
433 {
434  if(strncmp(url, history[(int)history_last], WWW_CONF_MAX_URLLEN) != 0) {
435  memcpy(history[(int)history_last], url, WWW_CONF_MAX_URLLEN);
436  ++history_last;
437  if(history_last >= WWW_CONF_HISTORY_SIZE) {
438  history_last = 0;
439  }
440  }
441 }
442 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
443 /*-----------------------------------------------------------------------------------*/
444 static void
445 quit(void)
446 {
447  ctk_window_close(&mainwindow);
448  process_exit(&www_process);
449  LOADER_UNLOAD();
450 }
451 /*-----------------------------------------------------------------------------------*/
452 /* www_process():
453  *
454  * The program's signal dispatcher function. Is called whenever a signal arrives.
455  */
456 PROCESS_THREAD(www_process, ev, data)
457 {
458  static struct ctk_widget *w;
459 #if WWW_CONF_WITH_WGET
460  static char *argptr;
461 #endif /* WWW_CONF_WITH_WGET */
462 
463  w = (struct ctk_widget *)data;
464 
465  PROCESS_BEGIN();
466 
467  /* Create the main window. */
468  memset(webpage, 0, sizeof(webpage));
469  ctk_window_new(&mainwindow, WWW_CONF_WEBPAGE_WIDTH,
470  WWW_CONF_WEBPAGE_HEIGHT+5, "Web browser");
471  make_window();
472 #ifdef WWW_CONF_HOMEPAGE
473  strncpy(editurl, WWW_CONF_HOMEPAGE, sizeof(editurl));
474 #endif /* WWW_CONF_HOMEPAGE */
475  CTK_WIDGET_FOCUS(&mainwindow, &urlentry);
476 
477 #if WWW_CONF_WITH_WGET || defined(WWW_CONF_WGET_EXEC)
478 #if CTK_CONF_WINDOWS
479  /* Create download dialog.*/
480  ctk_dialog_new(&wgetdialog, 38, 7);
481  CTK_WIDGET_ADD(&wgetdialog, &wgetlabel1);
482  CTK_WIDGET_ADD(&wgetdialog, &wgetlabel2);
483  CTK_WIDGET_ADD(&wgetdialog, &wgetnobutton);
484  CTK_WIDGET_ADD(&wgetdialog, &wgetyesbutton);
485 #endif /* CTK_CONF_WINDOWS */
486 #endif /* WWW_CONF_WITH_WGET || WWW_CONF_WGET_EXEC */
487 
488  ctk_window_open(&mainwindow);
489 
490  while(1) {
491 
493 
494  if(ev == tcpip_event) {
495  webclient_appcall(data);
496  } else if(ev == ctk_signal_widget_activate) {
497  if(w == (struct ctk_widget *)&gobutton ||
498  w == (struct ctk_widget *)&urlentry) {
499  start_loading();
500  firsty = 0;
501 #if WWW_CONF_HISTORY_SIZE > 0
502  log_back();
503 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
504  memcpy(url, editurl, WWW_CONF_MAX_URLLEN);
505  petsciiconv_toascii(url, WWW_CONF_MAX_URLLEN);
506  open_url();
507  CTK_WIDGET_FOCUS(&mainwindow, &gobutton);
508 #if WWW_CONF_HISTORY_SIZE > 0
509  } else if(w == (struct ctk_widget *)&backbutton) {
510  firsty = 0;
511  start_loading();
512  --history_last;
513  if(history_last > WWW_CONF_HISTORY_SIZE) {
514  history_last = WWW_CONF_HISTORY_SIZE - 1;
515  }
516  memcpy(url, history[(int)history_last], WWW_CONF_MAX_URLLEN);
517  open_url();
518  CTK_WIDGET_FOCUS(&mainwindow, &backbutton);
519 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
520  } else if(w == (struct ctk_widget *)&downbutton) {
521  firsty = pagey + WWW_CONF_WEBPAGE_HEIGHT - 4;
522  start_loading();
523  open_url();
524  CTK_WIDGET_FOCUS(&mainwindow, &downbutton);
525  } else if(w == (struct ctk_widget *)&stopbutton) {
526  loading = 0;
527  webclient_close();
528 #if WWW_CONF_WITH_WGET || defined(WWW_CONF_WGET_EXEC)
529  } else if(w == (struct ctk_widget *)&wgetnobutton) {
530 #if CTK_CONF_WINDOWS
531  ctk_dialog_close();
532 #else /* CTK_CONF_WINDOWS */
533  clear_page();
534 #endif /* CTK_CONF_WINDOWS */
535  } else if(w == (struct ctk_widget *)&wgetyesbutton) {
536 #if CTK_CONF_WINDOWS
537  ctk_dialog_close();
538 #else /* CTK_CONF_WINDOWS */
539  clear_page();
540 #endif /* CTK_CONF_WINDOWS */
541 #if WWW_CONF_WITH_WGET
542  quit();
543  argptr = arg_alloc((char)WWW_CONF_MAX_URLLEN);
544  if(argptr != NULL) {
545  strncpy(argptr, url, WWW_CONF_MAX_URLLEN);
546  }
547  program_handler_load("wget.prg", argptr);
548 #else /* WWW_CONF_WITH_WGET */
549  petsciiconv_topetscii(url, sizeof(url));
550  /* Clear screen */
551  ctk_restore();
552  WWW_CONF_WGET_EXEC(url);
553  redraw_window();
554  show_statustext("Cannot exec wget");
555 #endif /* WWW_CONF_WITH_WGET */
556 #endif /* WWW_CONF_WITH_WGET || WWW_CONF_WGET_EXEC */
557 #if WWW_CONF_FORMS
558  } else {
559  /* Assume form widget. */
560  struct inputattrib *input = (struct inputattrib *)
561  (((char *)w) - offsetof(struct inputattrib, widget));
562  formsubmit(input->formptr);
563 #endif /* WWW_CONF_FORMS */
564  }
565  } else if(ev == ctk_signal_hyperlink_activate) {
566  firsty = 0;
567 #if WWW_CONF_HISTORY_SIZE > 0
568  log_back();
569 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
570  set_link(w->widget.hyperlink.url);
571  show_url();
572  open_url();
573  start_loading();
574  CTK_WIDGET_FOCUS(&mainwindow, &stopbutton);
575  } else if(ev == ctk_signal_hyperlink_hover) {
576  if(CTK_WIDGET_TYPE((struct ctk_widget *)data) == CTK_WIDGET_HYPERLINK) {
577  strncpy(statustexturl, w->widget.hyperlink.url,
578  sizeof(statustexturl));
579  petsciiconv_topetscii(statustexturl, sizeof(statustexturl));
580  show_statustext(statustexturl);
581  }
582 #if UIP_UDP
583  } else if(ev == resolv_event_found) {
584  /* Either found a hostname, or not. */
585  if((char *)data != NULL &&
586  resolv_lookup((char *)data, NULL) == RESOLV_STATUS_CACHED) {
587  open_url();
588  } else {
589  show_statustext("Host not found");
590  }
591 #endif /* UIP_UDP */
592  } else if(ev == ctk_signal_window_close ||
593  ev == PROCESS_EVENT_EXIT) {
594  quit();
595  }
596  }
597  PROCESS_END();
598 }
599 /*-----------------------------------------------------------------------------------*/
600 /* set_url():
601  *
602  * Constructs an URL from the arguments and puts it into the global
603  * "url" variable and the visible "editurl" (which is shown in the URL
604  * text entry widget in the browser window).
605  */
606 static void CC_FASTCALL
607 set_url(char *host, uint16_t port, char *file)
608 {
609  char *urlptr;
610 
611  memset(url, 0, WWW_CONF_MAX_URLLEN);
612 
613  if(strncmp(file, http_http, 7) == 0) {
614  strncpy(url, file, sizeof(url));
615  } else {
616  strncpy(url, http_http, 7);
617  urlptr = url + 7;
618  strcpy(urlptr, host);
619  urlptr += strlen(host);
620  strcpy(urlptr, file);
621  }
622 
623  show_url();
624 }
625 /*-----------------------------------------------------------------------------------*/
626 /* webclient_aborted():
627  *
628  * Callback function. Called from the webclient when the HTTP
629  * connection was abruptly aborted.
630  */
631 void
632 webclient_aborted(void)
633 {
634  show_statustext("Connection reset by peer");
635 }
636 /*-----------------------------------------------------------------------------------*/
637 /* webclient_timedout():
638  *
639  * Callback function. Called from the webclient when the HTTP
640  * connection timed out.
641  */
642 void
643 webclient_timedout(void)
644 {
645  show_statustext("Connection timed out");
646 }
647 /*-----------------------------------------------------------------------------------*/
648 /* webclient_closed():
649  *
650  * Callback function. Called from the webclient when the HTTP
651  * connection was closed after a request from the "webclient_close()"
652  * function.
653  */
654 void
655 webclient_closed(void)
656 {
657  show_statustext("Stopped");
658  petsciiconv_topetscii(webpageptr - x, x);
659  CTK_WIDGET_FOCUS(&mainwindow, &downbutton);
660  redraw_window();
661 }
662 /*-----------------------------------------------------------------------------------*/
663 /* webclient_connected():
664  *
665  * Callback function. Called from the webclient when the HTTP
666  * connection is connected.
667  */
668 void
669 webclient_connected(void)
670 {
671  start_loading();
672 
673  clear_page();
674 
675  show_statustext("Request sent...");
676  set_url(webclient_hostname(), webclient_port(), webclient_filename());
677 
678  htmlparser_init();
679 }
680 /*-----------------------------------------------------------------------------------*/
681 /* webclient_datahandler():
682  *
683  * Callback function. Called from the webclient module when HTTP data
684  * has arrived.
685  */
686 void
687 webclient_datahandler(char *data, uint16_t len)
688 {
689  if(len > 0) {
690  if(strstr(webclient_mimetype(), http_html + 1) != 0) {
691  count = (count + 1) & 3;
692  show_statustext(receivingmsgs[count]);
693  htmlparser_parse(data, len);
694  redraw_window();
695  } else {
696  uip_abort();
697 #if WWW_CONF_WITH_WGET || defined(WWW_CONF_WGET_EXEC)
698 #if CTK_CONF_WINDOWS
699  ctk_dialog_open(&wgetdialog);
700 #else /* CTK_CONF_WINDOWS */
701  strcpy(webpage + WWW_CONF_WEBPAGE_WIDTH * 5,
702  (80 - WWW_CONF_WEBPAGE_WIDTH) / 2 +
703  " This web page cannot be displayed.");
704  strcpy(webpage + WWW_CONF_WEBPAGE_WIDTH * 6,
705  (80 - WWW_CONF_WEBPAGE_WIDTH) / 2 +
706  " Would you like to download instead?");
707  CTK_WIDGET_ADD(&mainwindow, &wgetnobutton);
708  CTK_WIDGET_ADD(&mainwindow, &wgetyesbutton);
709  redraw_window();
710 #endif /* CTK_CONF_WINDOWS */
711 #endif /* WWW_CONF_WITH_WGET || WWW_CONF_WGET_EXEC */
712  }
713  } else {
714  /* Clear remaining parts of page. */
715  loading = 0;
716  }
717 
718  if(data == NULL) {
719  loading = 0;
720  show_statustext("Done");
721  petsciiconv_topetscii(webpageptr - x, x);
722  CTK_WIDGET_FOCUS(&mainwindow, &urlentry);
723  redraw_window();
724  }
725 }
726 /*-----------------------------------------------------------------------------------*/
727 static void CC_FASTCALL
728 add_pagewidget(char *text, unsigned char size, char *attrib, unsigned char type,
729  unsigned char border)
730 {
731  char *wptr;
732  static unsigned char maxwidth;
733 
734  if(!loading) {
735  return;
736  }
737 
738  maxwidth = size ? WWW_CONF_WEBPAGE_WIDTH - (1 + 2 * border)
739  : WWW_CONF_WEBPAGE_WIDTH;
740 
741  /* If the text of the link is too long so that it does not fit into
742  the width of the current window, counting from the current x
743  coordinate, we first try to jump to the next line. */
744  if(size + x > maxwidth) {
745  htmlparser_newline();
746  if(!loading) {
747  return;
748  }
749  }
750 
751  /* If the text of the link still is too long, we just chop it off!
752  XXX: this is not really the right thing to do, we should probably
753  either make a link into a multiline link, or add multiple
754  buttons. But this will do for now. */
755  if(size > maxwidth) {
756  text[maxwidth] = 0;
757  size = maxwidth;
758  }
759 
760  if(firsty == pagey) {
761  unsigned char attriblen = strlen(attrib);
762 
763  wptr = webpageptr;
764  /* To save memory, we'll copy the widget text to the web page
765  drawing area and reference it from there. */
766  wptr[0] = 0;
767  wptr += border;
768  memcpy(wptr, text, size);
769  wptr[size] = 0;
770  wptr[size + border] = ' ';
771 
772  switch(type) {
773  case CTK_WIDGET_HYPERLINK: {
774  struct linkattrib *linkptr =
775  (struct linkattrib *)add_pageattrib(sizeof(struct linkattrib) /* incl 1 attrib char */ + attriblen);
776  if(linkptr != NULL) {
777  CTK_HYPERLINK_NEW(&linkptr->hyperlink, x, y + 3, size, wptr, linkptr->url);
778  strcpy(linkptr->url, attrib);
779  CTK_WIDGET_SET_FLAG(&linkptr->hyperlink, CTK_WIDGET_FLAG_MONOSPACE);
780  CTK_WIDGET_ADD(&mainwindow, &linkptr->hyperlink);
781  }
782  break;
783  }
784 #if WWW_CONF_FORMS
785  case CTK_WIDGET_BUTTON: {
786  struct submitattrib *submitptr =
787  (struct submitattrib *)add_pageattrib(sizeof(struct submitattrib) /* incl 1 attrib char */ + attriblen);
788  if(submitptr != NULL) {
789  CTK_BUTTON_NEW((struct ctk_button *)&submitptr->button, x, y + 3, size, wptr);
790  add_forminput((struct inputattrib *)submitptr);
791  submitptr->formptr = formptr;
792  strcpy(submitptr->name, attrib);
793  CTK_WIDGET_SET_FLAG(&submitptr->button, CTK_WIDGET_FLAG_MONOSPACE);
794  CTK_WIDGET_ADD(&mainwindow, &submitptr->button);
795  }
796  break;
797  }
798  case CTK_WIDGET_TEXTENTRY: {
799  struct textattrib *textptr =
800  (struct textattrib *)add_pageattrib(sizeof(struct textattrib) /* incl 1 attrib char */ + attriblen
801  + (size ? WWW_CONF_MAX_INPUTVALUELEN : strlen(text)) + 1);
802  if(textptr != NULL) {
803  CTK_TEXTENTRY_NEW((struct ctk_textentry *)&textptr->textentry, x, y + 3, size, 1,
804  textptr->name + attriblen + 1, WWW_CONF_MAX_INPUTVALUELEN);
805  add_forminput((struct inputattrib *)textptr);
806  textptr->formptr = formptr;
807  strcpy(textptr->textentry.text, text);
808  strcpy(textptr->name, attrib);
809  if(size) {
810  CTK_WIDGET_SET_FLAG(&textptr->textentry, CTK_WIDGET_FLAG_MONOSPACE);
811  CTK_WIDGET_ADD(&mainwindow, &textptr->textentry);
812  }
813  }
814  break;
815  }
816 #endif /* WWW_CONF_FORMS */
817  }
818  }
819  /* Increase the x coordinate with the length of the link text plus
820  the extra space behind it and the CTK button markers. */
821  if(size) {
822  size += 1 + 2 * border;
823  }
824  x += size;
825 
826  if(firsty == pagey) {
827  webpageptr += size;
828  }
829 
830  if(x == WWW_CONF_WEBPAGE_WIDTH) {
831  htmlparser_newline();
832  }
833 }
834 /*-----------------------------------------------------------------------------------*/
835 void
836 htmlparser_newline(void)
837 {
838  char *wptr;
839 
840  if(pagey < firsty) {
841  ++pagey;
842  x = 0;
843  return;
844  }
845 
846  if(!loading) {
847  return;
848  }
849 
850  webpageptr += (WWW_CONF_WEBPAGE_WIDTH - x);
851  ++y;
852  x = 0;
853 
854  wptr = webpageptr - WWW_CONF_WEBPAGE_WIDTH;
855  petsciiconv_topetscii(wptr, WWW_CONF_WEBPAGE_WIDTH);
856 
857  if(y == WWW_CONF_WEBPAGE_HEIGHT) {
858  loading = 0;
859  webclient_close();
860  }
861 }
862 /*-----------------------------------------------------------------------------------*/
863 void
864 htmlparser_word(char *word, unsigned char wordlen)
865 {
866  if(loading) {
867  if(wordlen + 1 > WWW_CONF_WEBPAGE_WIDTH - x) {
868  htmlparser_newline();
869  }
870 
871  if(loading) {
872  if(pagey == firsty) {
873  memcpy(webpageptr, word, wordlen);
874  webpageptr += wordlen;
875  *webpageptr = ' ';
876  ++webpageptr;
877  }
878  x += wordlen + 1;
879  if(x == WWW_CONF_WEBPAGE_WIDTH) {
880  htmlparser_newline();
881  }
882  }
883  }
884 }
885 /*-----------------------------------------------------------------------------------*/
886 void
887 htmlparser_link(char *text, unsigned char textlen, char *url)
888 {
889  add_pagewidget(text, textlen, url, CTK_WIDGET_HYPERLINK, 0);
890 }
891 /*-----------------------------------------------------------------------------------*/
892 #if WWW_CONF_FORMS
893 void
894 htmlparser_form(char *action)
895 {
896  formptr = (struct formattrib *)add_pageattrib(sizeof(struct formattrib) + strlen(action));
897  if(formptr != NULL) {
898  formptr->nextptr = NULL;
899  currptr = (struct inputattrib *)formptr;
900  strcpy(formptr->action, action);
901  }
902 }
903 /*-----------------------------------------------------------------------------------*/
904 void
905 htmlparser_submitbutton(char *text, char *name)
906 {
907  add_pagewidget(text, (unsigned char)strlen(text), name, CTK_WIDGET_BUTTON, 1);
908 }
909 /*-----------------------------------------------------------------------------------*/
910 void
911 htmlparser_inputfield(unsigned char type, unsigned char size, char *text, char *name)
912 {
913  if(type == HTMLPARSER_INPUTTYPE_HIDDEN) {
914  add_pagewidget(text, 0, name, CTK_WIDGET_TEXTENTRY, 0);
915  } else {
916  add_pagewidget(text, size, name, CTK_WIDGET_TEXTENTRY, 1);
917  }
918 }
919 /*-----------------------------------------------------------------------------------*/
920 static void CC_FASTCALL
921 add_query(char delimiter, char *string)
922 {
923  static char *query;
924  unsigned char length;
925 
926  if(delimiter == ISO_questionmark) {
927  query = url + strlen(url);
928  }
929 
930  length = strlen(string);
931  if(query - url + WWW_CONF_MAX_URLLEN - 1 /* delimiter */ < length) {
932  return;
933  }
934 
935  *query++ = delimiter;
936  strcpy(query, string);
937  if(delimiter == ISO_eq) {
938  char *space = query;
939 
940  petsciiconv_toascii(query, length);
941  while((space = strchr(space, ISO_space)) != NULL) {
942  *space = ISO_plus;
943  }
944  }
945  query += length;
946 }
947 /*-----------------------------------------------------------------------------------*/
948 static void CC_FASTCALL
949 formsubmit(struct formattrib *form)
950 {
951  struct inputattrib *inputptr;
952  char delimiter = ISO_questionmark;
953 
954  set_link(form->action);
955 
956  for(inputptr = form->nextptr; inputptr != NULL; inputptr = inputptr->nextptr) {
957  char *name;
958  char *value;
959 
960  if(inputptr->widget.type == CTK_WIDGET_BUTTON) {
961  name = ((struct submitattrib *)inputptr)->name;
962  value = ((struct submitattrib *)inputptr)->button.text;
963  } else {
964  name = ((struct textattrib *)inputptr)->name;
965  value = ((struct textattrib *)inputptr)->textentry.text;
966  }
967 
968  add_query(delimiter, name);
969  add_query(ISO_eq, value);
970  delimiter = ISO_ampersand;
971  }
972 
973 #if WWW_CONF_HISTORY_SIZE > 0
974  log_back();
975 #endif /* WWW_CONF_HISTORY_SIZE > 0 */
976 
977  show_url();
978  open_url();
979  start_loading();
980 }
981 #endif /* WWW_CONF_FORMS */
982 /*-----------------------------------------------------------------------------------*/
#define CTK_WIDGET_ADD(win, widg)
Add a widget to a window.
Definition: ctk.h:752
process_event_t ctk_signal_window_close
Emitted when a window is closed.
Definition: ctk.c:155
#define CTK_WIDGET_TEXTENTRY
Widget number: The CTK textentry widget.
Definition: ctk.h:72
#define CTK_SEPARATOR(x, y, w)
Instantiating macro for the ctk_separator widget.
Definition: ctk.h:111
Hostname is fresh and usable.
Definition: resolv.h:68
void ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
Open a window, or bring window to front if already open.
Definition: ctk.c:347
#define CTK_WIDGET_FOCUS(win, widg)
Set focus to a widget.
Definition: ctk.h:763
void ctk_window_close(struct ctk_window *w)
Close a window if it is open.
Definition: ctk.c:400
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
process_event_t ctk_signal_hyperlink_hover
Same as ctk_signal_widget_select.
Definition: ctk.c:126
#define CTK_TEXTENTRY(x, y, w, h, text, len)
Instantiating macro for the ctk_textentry widget.
Definition: ctk.h:275
#define ctk_label_set_text(l, t)
Set the text of a label.
Definition: ctk.h:849
#define NULL
The null pointer.
char * arg_alloc(char size)
Allocates an argument buffer.
Definition: arg.c:104
void ctk_window_redraw(struct ctk_window *w)
Redraw a window.
Definition: ctk.c:652
#define uiplib_ipaddrconv
Convert a textual representation of an IP address to a numerical representation.
Definition: uiplib.h:71
#define CTK_LABEL(x, y, w, h, text)
Instantiating macro for the ctk_label widget.
Definition: ctk.h:171
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void ctk_window_new(struct ctk_window *window, unsigned char w, unsigned char h, char *title)
Create a new window.
Definition: ctk.c:732
#define uip_abort()
Abort the current connection.
Definition: uip.h:682
CCIF process_event_t resolv_event_found
Event that is broadcasted when a DNS name has been resolved.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
PETSCII/ASCII conversion functions.
#define LOADER_UNLOAD()
Unload a program from memory.
Definition: loader.h:104
void ctk_window_clear(struct ctk_window *w)
Remove all widgets from a window.
Definition: ctk.c:485
process_event_t ctk_signal_hyperlink_activate
Emitted when a hyperlink is activated.
Definition: ctk.c:126
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define CTK_WIDGET_BUTTON
Widget number: The CTK button widget.
Definition: ctk.h:68
process_event_t ctk_signal_widget_activate
Emitted when a widget is activated (pressed).
Definition: ctk.c:126
union ctk_widget::@20 widget
The union which contains the actual widget structure, as determined by the type field.
process_event_t tcpip_event
The uIP event.
Definition: tcpip.c:75
#define CTK_BUTTON(x, y, w, text)
Instantiating macro for the ctk_button widget.
Definition: ctk.h:140
#define CTK_WIDGET_HYPERLINK
Widget number: The CTK hyperlink widget.
Definition: ctk.h:70
Representation of a CTK window.
Definition: ctk.h:506
The generic CTK widget structure that contains all other widget structures.
Definition: ctk.h:444
#define CTK_WIDGET_REDRAW(widg)
Add a widget to the redraw queue.
Definition: ctk.h:771
unsigned char w
The width of the widget in character coordinates.
Definition: ctk.h:464
#define CC_FASTCALL
Configure if the C compiler supports fastcall function declarations.
Definition: cc.h:77
void program_handler_load(char *name, char *arg)
Loads a program and displays a dialog telling the user about it.
#define CTK_WIDGET_TYPE(w)
Obtain the type of a widget.
Definition: ctk.h:780
CTK header file.
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202