blob: f2967303a2d2da81a27ecc11eb4f30a75c43cd02 [file] [log] [blame]
adamdunkelsca9ddcb2003-03-19 14:13: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. 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 *
adamdunkels75c276c2003-09-04 19:35:32 +000035 * $Id: www.c,v 1.21 2003/09/04 19:35:32 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000036 *
37 */
38
39
40#include "ctk.h"
41#include "dispatcher.h"
42#include "webclient.h"
43#include "htmlparser.h"
44#include "http-strings.h"
45#include "resolv.h"
46
47#include "petsciiconv.h"
48
adamdunkels8bb5cca2003-08-24 22:41:31 +000049#include "program-handler.h"
50
51
adamdunkels8af703e2003-04-08 11:50:20 +000052#include "loader.h"
53
adamdunkelsca9ddcb2003-03-19 14:13:31 +000054#include "www-conf.h"
55
adamdunkels30c449e2003-07-31 23:12:05 +000056#if 1
adamdunkelsca9ddcb2003-03-19 14:13:31 +000057#define PRINTF(x)
58#else
59#include <stdio.h>
60#define PRINTF(x) printf x
61#endif
62
63
64/* The array that holds the current URL. */
65static char url[WWW_CONF_MAX_URLLEN + 1];
66static char tmpurl[WWW_CONF_MAX_URLLEN + 1];
67
68/* The array that holds the web page text. */
adamdunkels89c1f4e2003-08-09 13:33:25 +000069static char webpage[WWW_CONF_WEBPAGE_WIDTH *
70 WWW_CONF_WEBPAGE_HEIGHT + 1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +000071
72/* The CTK widgets for the main window. */
73static struct ctk_window mainwindow;
74
75static struct ctk_button backbutton =
76 {CTK_BUTTON(0, 0, 4, "Back")};
77static struct ctk_button downbutton =
78 {CTK_BUTTON(10, 0, 4, "Down")};
79static struct ctk_button stopbutton =
adamdunkels89c1f4e2003-08-09 13:33:25 +000080 {CTK_BUTTON(WWW_CONF_WEBPAGE_WIDTH - 16, 0, 4, "Stop")};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000081static struct ctk_button gobutton =
adamdunkels89c1f4e2003-08-09 13:33:25 +000082 {CTK_BUTTON(WWW_CONF_WEBPAGE_WIDTH - 4, 0, 2, "Go")};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000083
84static struct ctk_separator sep1 =
adamdunkels89c1f4e2003-08-09 13:33:25 +000085 {CTK_SEPARATOR(0, 2, WWW_CONF_WEBPAGE_WIDTH)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000086
87static char editurl[WWW_CONF_MAX_URLLEN + 1];
88static struct ctk_textentry urlentry =
adamdunkels89c1f4e2003-08-09 13:33:25 +000089 {CTK_TEXTENTRY(0, 1, WWW_CONF_WEBPAGE_WIDTH - 2,
90 1, editurl, WWW_CONF_MAX_URLLEN)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000091static struct ctk_label webpagelabel =
adamdunkels89c1f4e2003-08-09 13:33:25 +000092 {CTK_LABEL(0, 3, WWW_CONF_WEBPAGE_WIDTH,
93 WWW_CONF_WEBPAGE_HEIGHT, webpage)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000094
adamdunkels89c1f4e2003-08-09 13:33:25 +000095static char statustexturl[WWW_CONF_WEBPAGE_WIDTH];
adamdunkelsca9ddcb2003-03-19 14:13:31 +000096static struct ctk_label statustext =
adamdunkels89c1f4e2003-08-09 13:33:25 +000097 {CTK_LABEL(0, WWW_CONF_WEBPAGE_HEIGHT + 4,
98 WWW_CONF_WEBPAGE_WIDTH, 1, "")};
adamdunkelsca9ddcb2003-03-19 14:13:31 +000099static struct ctk_separator sep2 =
adamdunkels89c1f4e2003-08-09 13:33:25 +0000100 {CTK_SEPARATOR(0, WWW_CONF_WEBPAGE_HEIGHT + 3,
101 WWW_CONF_WEBPAGE_WIDTH)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000102
adamdunkelsf6eea752003-08-22 19:24:40 +0000103static struct ctk_window wgetdialog;
104static struct ctk_label wgetlabel1 =
adamdunkels77b7a692003-08-29 20:36:23 +0000105 {CTK_LABEL(1, 1, 34, 1, "This web page cannot be displayed.")};
adamdunkelsf6eea752003-08-22 19:24:40 +0000106static struct ctk_label wgetlabel2 =
adamdunkels77b7a692003-08-29 20:36:23 +0000107 {CTK_LABEL(1, 3, 35, 1, "Would you like to download instead?")};
adamdunkelsf6eea752003-08-22 19:24:40 +0000108static struct ctk_button wgetnobutton =
adamdunkels77b7a692003-08-29 20:36:23 +0000109 {CTK_BUTTON(1, 5, 6, "Cancel")};
adamdunkelsf6eea752003-08-22 19:24:40 +0000110static struct ctk_button wgetyesbutton =
adamdunkels77b7a692003-08-29 20:36:23 +0000111 {CTK_BUTTON(11, 5, 24, "Close browser & download")};
adamdunkelsf6eea752003-08-22 19:24:40 +0000112
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000113/* The char arrays that hold the history of visited URLs. */
adamdunkels17e84a32003-04-02 09:54:39 +0000114static char history[WWW_CONF_HISTORY_SIZE][WWW_CONF_MAX_URLLEN];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000115static char history_last, history_first;
116
117
118/* The CTK widget definitions for the hyperlinks and the char arrays
119 that hold the link URLs. */
120struct formattribs {
121 char formaction[WWW_CONF_MAX_FORMACTIONLEN];
122 char formname[WWW_CONF_MAX_FORMNAMELEN];
123#define FORMINPUTTYPE_SUBMITBUTTON 1
124#define FORMINPUTTYPE_INPUTFIELD 2
125 unsigned char inputtype;
126 char inputname[WWW_CONF_MAX_INPUTNAMELEN];
127 char *inputvalue;
128};
129
130union pagewidgetattrib {
131 char url[WWW_CONF_MAX_URLLEN];
adamdunkelsd59dadf2003-08-15 18:48:35 +0000132#if WWW_CONF_FORMS
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000133 struct formattribs form;
adamdunkelsd59dadf2003-08-15 18:48:35 +0000134#endif /* WWW_CONF_FORMS */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000135};
adamdunkels17e84a32003-04-02 09:54:39 +0000136static struct ctk_widget pagewidgets[WWW_CONF_MAX_NUMPAGEWIDGETS];
137static union pagewidgetattrib pagewidgetattribs[WWW_CONF_MAX_NUMPAGEWIDGETS];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000138static unsigned char pagewidgetptr;
139
140
141/* The "scrolly" variable holds the line number (in the web page) of
142 the first line of text shown on screen. */
143static unsigned short scrolly;
144
adamdunkels30c449e2003-07-31 23:12:05 +0000145/* The "scrollend" variable contains the web page line number of the
146 last line that should be shown on screen, before the download
147 should stop. */
148#if WWW_CONF_PAGEVIEW
149static unsigned short scrollend;
150#endif /* WWW_CONF_PAGEVIEW */
151
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000152#if WWW_CONF_RENDERSTATE
153static unsigned char renderstate;
154#endif /* WWW_CONF_RENDERSTATE */
155
156/* The "run" flag is used to determine if the web page should be
157 continuosly scrolled upward with new data coming in from below. */
158static unsigned char run;
159
160#define ISO_nl 0x0a
161#define ISO_space 0x20
162#define ISO_ampersand 0x26
163#define ISO_plus 0x2b
164#define ISO_slash 0x2f
165#define ISO_eq 0x3d
166#define ISO_questionmark 0x3f
167
168/* The state of the rendering code. */
169static u8_t x;
170static u16_t starty;
adamdunkels17e84a32003-04-02 09:54:39 +0000171static char nextword[WWW_CONF_WEBPAGE_WIDTH + 1];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000172static unsigned char nextwordptr;
173
174static unsigned char count;
175static char receivingmsgs[4][23] = {
176 "Receiving web page ...",
177 "Receiving web page. ..",
178 "Receiving web page.. .",
179 "Receiving web page... "
180};
181
182
adamdunkels78c03dc2003-04-09 13:45:05 +0000183static DISPATCHER_SIGHANDLER(www_sighandler, s, data);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000184static struct dispatcher_proc p =
adamdunkels78c03dc2003-04-09 13:45:05 +0000185 {DISPATCHER_PROC("Web browser", NULL, www_sighandler, webclient_appcall)};
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000186static ek_id_t id;
187
188
189static void formsubmit(struct formattribs *attribs);
190/*-----------------------------------------------------------------------------------*/
191/* make_window()
192 *
193 * Creates the web browser's window.
194 */
195static void
196make_window(void)
197{
198
199 CTK_WIDGET_ADD(&mainwindow, &backbutton);
200 CTK_WIDGET_ADD(&mainwindow, &downbutton);
201 CTK_WIDGET_ADD(&mainwindow, &stopbutton);
202 CTK_WIDGET_ADD(&mainwindow, &gobutton);
203 CTK_WIDGET_ADD(&mainwindow, &urlentry);
204 CTK_WIDGET_ADD(&mainwindow, &sep1);
205 CTK_WIDGET_ADD(&mainwindow, &webpagelabel);
206 CTK_WIDGET_ADD(&mainwindow, &sep2);
207 CTK_WIDGET_ADD(&mainwindow, &statustext);
208
209 CTK_WIDGET_FOCUS(&mainwindow, &stopbutton);
210
211 pagewidgetptr = 0;
212}
213/*-----------------------------------------------------------------------------------*/
214/* redraw_window():
215 *
216 * Convenience function that calls upon CTK to redraw the browser
217 * window. */
218static void
219redraw_window(void)
220{
221 ctk_window_redraw(&mainwindow);
222}
223/*-----------------------------------------------------------------------------------*/
224/* www_init();
225 *
226 * Initializes and starts the web browser. Called either at startup or
227 * to open the browser window.
228 */
adamdunkels8bb5cca2003-08-24 22:41:31 +0000229LOADER_INIT_FUNC(www_init, arg)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000230{
adamdunkels8bb5cca2003-08-24 22:41:31 +0000231 arg_free(arg);
232
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000233 if(id == EK_ID_NONE) {
234 id = dispatcher_start(&p);
235
236 /* Create the main window. */
237 memset(webpage, 0, sizeof(webpage));
adamdunkels89c1f4e2003-08-09 13:33:25 +0000238 ctk_window_new(&mainwindow, WWW_CONF_WEBPAGE_WIDTH,
239 WWW_CONF_WEBPAGE_HEIGHT+5, "Web browser");
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000240 make_window();
adamdunkels77b7a692003-08-29 20:36:23 +0000241#ifdef WWW_CONF_HOMEPAGE
242 strncpy(editurl, WWW_CONF_HOMEPAGE, sizeof(editurl));
243#endif /* WWW_CONF_HOMEPAGE */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000244 CTK_WIDGET_FOCUS(&mainwindow, &urlentry);
adamdunkelsf6eea752003-08-22 19:24:40 +0000245
246 /* Create download dialog.*/
adamdunkels77b7a692003-08-29 20:36:23 +0000247 ctk_dialog_new(&wgetdialog, 38, 7);
adamdunkelsf6eea752003-08-22 19:24:40 +0000248 CTK_WIDGET_ADD(&wgetdialog, &wgetlabel1);
249 CTK_WIDGET_ADD(&wgetdialog, &wgetlabel2);
250 CTK_WIDGET_ADD(&wgetdialog, &wgetnobutton);
251 CTK_WIDGET_ADD(&wgetdialog, &wgetyesbutton);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000252
253 /* Attach as a listener to a number of signals ("Button activate",
254 "Hyperlink activate" and "Hyperlink hover", and the resolver's
255 signal. */
adamdunkels62b64992003-04-08 07:20:11 +0000256 dispatcher_listen(ctk_signal_window_close);
adamdunkels328e5352003-08-20 20:54:46 +0000257 dispatcher_listen(ctk_signal_widget_activate);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000258 dispatcher_listen(ctk_signal_hyperlink_activate);
259 dispatcher_listen(ctk_signal_hyperlink_hover);
260 dispatcher_listen(resolv_signal_found);
adamdunkels77b7a692003-08-29 20:36:23 +0000261
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000262 }
263 ctk_window_open(&mainwindow);
264}
265/*-----------------------------------------------------------------------------------*/
266static void
267clear_page(void)
268{
adamdunkelsf6eea752003-08-22 19:24:40 +0000269 /* if(ctk_window_isopen(&mainwindow)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000270 ctk_window_close(&mainwindow);
adamdunkelsf6eea752003-08-22 19:24:40 +0000271 }*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000272 ctk_window_clear(&mainwindow);
273 make_window();
adamdunkelsf6eea752003-08-22 19:24:40 +0000274 /* ctk_window_open(&mainwindow);*/
275 ctk_window_redraw(&mainwindow);
adamdunkels17e84a32003-04-02 09:54:39 +0000276 memset(webpage, 0, WWW_CONF_WEBPAGE_WIDTH * WWW_CONF_WEBPAGE_HEIGHT);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000277}
278/*-----------------------------------------------------------------------------------*/
279static void
280show_url(void)
281{
282 memcpy(editurl, url, WWW_CONF_MAX_URLLEN);
283 strncpy(editurl, "http://", 7);
284 petsciiconv_topetscii(editurl + 7, WWW_CONF_MAX_URLLEN - 7);
285 CTK_WIDGET_REDRAW(&urlentry);
286}
287/*-----------------------------------------------------------------------------------*/
288static void
289show_statustext(char *text)
290{
291 ctk_label_set_text(&statustext, text);
292 CTK_WIDGET_REDRAW(&statustext);
293}
294/*-----------------------------------------------------------------------------------*/
295/* open_url():
296 *
297 * Called when the URL present in the global "url" variable should be
298 * opened. It will call the hostname resolver as well as the HTTP
299 * client requester.
300 */
301static void
302open_url(void)
303{
304 unsigned char i;
305 static char host[32];
306 char *file;
307 register char *urlptr;
308 unsigned short port;
adamdunkels75c276c2003-09-04 19:35:32 +0000309 static u16_t addr[2];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000310
311 /* Trim off any spaces in the end of the url. */
312 urlptr = url + strlen(url) - 1;
313 while(*urlptr == ' ' && urlptr > url) {
314 *urlptr = 0;
315 --urlptr;
316 }
317
318 /* Don't even try to go further if the URL is empty. */
319 if(urlptr == url) {
320 return;
321 }
322
323 /* See if the URL starts with http://, otherwise prepend it. */
324 if(strncmp(url, http_http, 7) != 0) {
325 while(urlptr >= url) {
326 *(urlptr + 7) = *urlptr;
327 --urlptr;
328 }
329 strncpy(url, http_http, 7);
330 }
331
332 /* Find host part of the URL. */
333 urlptr = &url[7];
334 for(i = 0; i < sizeof(host); ++i) {
335 if(*urlptr == 0 ||
336 *urlptr == '/' ||
337 *urlptr == ' ' ||
338 *urlptr == ':') {
339 host[i] = 0;
340 break;
341 }
342 host[i] = *urlptr;
343 ++urlptr;
344 }
345
346 /* XXX: Here we should find the port part of the URL, but this isn't
347 currently done because of laziness from the programmer's side
348 :-) */
349
350 /* Find file part of the URL. */
351 while(*urlptr != '/' && *urlptr != 0) {
352 ++urlptr;
353 }
354 if(*urlptr == '/') {
355 file = urlptr;
356 } else {
357 file = "/";
358 }
359
360 /* Try to lookup the hostname. If it fails, we initiate a hostname
361 lookup and print out an informative message on the statusbar. */
adamdunkels75c276c2003-09-04 19:35:32 +0000362 if(uip_main_ipaddrconv(host, (unsigned char *)addr) == 0) {
363 if(resolv_lookup(host) == NULL) {
364 resolv_query(host);
365 show_statustext("Resolving host...");
366 return;
367 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000368 }
369
370 /* The hostname we present in the hostname table, so we send out the
371 initial GET request. */
372 if(webclient_get(host, 80, file) == 0) {
373 show_statustext("Out of memory error.");
374 } else {
375 show_statustext("Connecting...");
376 }
377 redraw_window();
378}
379/*-----------------------------------------------------------------------------------*/
380/* open_link(link):
381 *
382 * Will format a link from the current web pages so that it suits the
383 * open_url() function and finally call it to open the requested URL.
384 */
385static void
386open_link(char *link)
387{
388 char *urlptr;
389
390 if(strncmp(link, http_http, 7) == 0) {
391 /* The link starts with http://. We just copy the contents of the
392 link into the url string and jump away. */
393 strncpy(url, link, WWW_CONF_MAX_URLLEN);
394 } else if(*link == ISO_slash &&
395 *(link + 1) == ISO_slash) {
396 /* The link starts with //, so we'll copy it into the url
397 variable, starting after the http (which already is present in
398 the url variable since we were able to open the web page on
399 which this link was found in the first place). */
400 strncpy(&url[5], link, WWW_CONF_MAX_URLLEN);
401 } else if(*link == ISO_slash) {
402 /* The link starts with a slash, so it is a non-relative link
403 within the same web site. We find the start of the filename of
404 the current URL and paste the contents of this link there, and
405 head off to the new URL. */
406 for(urlptr = &url[7];
407 *urlptr != 0 && *urlptr != ISO_slash;
408 ++urlptr);
409 strncpy(urlptr, link, WWW_CONF_MAX_URLLEN - (urlptr - url));
410 } else {
411 /* A fully relative link is found. We find the last slash in the
412 current URL and paste the link there. */
413
414 /* XXX: we should really parse any ../ in the link as well. */
415 for(urlptr = url + strlen(url);
416 urlptr != url && *urlptr != ISO_slash;
417 --urlptr);
418 ++urlptr;
419 strncpy(urlptr, link, WWW_CONF_MAX_URLLEN - (urlptr - url));
420 }
421
422 /* Open the URL. */
423 scrolly = 0;
424 show_url();
425 open_url();
426}
427/*-----------------------------------------------------------------------------------*/
428/* log_back():
429 *
430 * Copies the current URL from the url variable and into the log for
431 * the back button.
432 */
433static void
434log_back(void)
435{
adamdunkels89c1f4e2003-08-09 13:33:25 +0000436 if(strncmp(url, history[(int)history_last], WWW_CONF_MAX_URLLEN) != 0) {
437 memcpy(history[(int)history_last], url, WWW_CONF_MAX_URLLEN);
438 ++history_last;
439 if(history_last >= WWW_CONF_HISTORY_SIZE) {
440 history_last = 0;
441 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000442 }
443}
444/*-----------------------------------------------------------------------------------*/
adamdunkelsf6eea752003-08-22 19:24:40 +0000445static void
446quit(void)
447{
448 ctk_window_close(&mainwindow);
449 dispatcher_exit(&p);
450 id = EK_ID_NONE;
451 LOADER_UNLOAD();
452}
453/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000454/* www_dispatcher():
455 *
456 * The program's signal dispatcher function. Is called by the ek
457 * dispatcher whenever a signal arrives.
458 */
adamdunkels78c03dc2003-04-09 13:45:05 +0000459static
460DISPATCHER_SIGHANDLER(www_sighandler, s, data)
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000461{
462 static struct ctk_widget *w;
463 static unsigned char i;
adamdunkels8bb5cca2003-08-24 22:41:31 +0000464 static char *argptr;
465
adamdunkels78c03dc2003-04-09 13:45:05 +0000466 DISPATCHER_SIGHANDLER_ARGS(s, data);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000467
468
469 w = (struct ctk_widget *)data;
adamdunkels328e5352003-08-20 20:54:46 +0000470 if(s == ctk_signal_widget_activate) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000471 if(w == (struct ctk_widget *)&backbutton) {
472 scrolly = 0;
473 run = 1;
474
475 --history_last;
adamdunkels17e84a32003-04-02 09:54:39 +0000476 if(history_last > WWW_CONF_HISTORY_SIZE) {
477 history_last = WWW_CONF_HISTORY_SIZE - 1;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000478 }
adamdunkels30c449e2003-07-31 23:12:05 +0000479 memcpy(url, history[(int)history_last], WWW_CONF_MAX_URLLEN);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000480 open_url();
481 CTK_WIDGET_FOCUS(&mainwindow, &backbutton);
482 } else if(w == (struct ctk_widget *)&downbutton) {
483 run = 1;
484 open_url();
485 CTK_WIDGET_FOCUS(&mainwindow, &downbutton);
adamdunkels328e5352003-08-20 20:54:46 +0000486 } else if(w == (struct ctk_widget *)&gobutton ||
487 w == (struct ctk_widget *)&urlentry) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000488 scrolly = 0;
adamdunkelsfb565d92003-08-13 22:51:07 +0000489#if WWW_CONF_PAGEVIEW
490 starty = 0;
491#endif /* WWW_CONF_PAGEVIEW */
adamdunkels30c449e2003-07-31 23:12:05 +0000492
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000493 run = 1;
494 log_back();
495 memcpy(url, editurl, WWW_CONF_MAX_URLLEN);
496 petsciiconv_toascii(url, WWW_CONF_MAX_URLLEN);
497 open_url();
498 CTK_WIDGET_FOCUS(&mainwindow, &gobutton);
499 } else if(w == (struct ctk_widget *)&stopbutton) {
500 run = 0;
501 webclient_close();
adamdunkelsf6eea752003-08-22 19:24:40 +0000502 } else if(w == (struct ctk_widget *)&wgetnobutton) {
503 ctk_dialog_close();
504 } else if(w == (struct ctk_widget *)&wgetyesbutton) {
adamdunkels8bb5cca2003-08-24 22:41:31 +0000505 ctk_dialog_close();
adamdunkelsf6eea752003-08-22 19:24:40 +0000506 quit();
adamdunkels8bb5cca2003-08-24 22:41:31 +0000507 argptr = arg_alloc(WWW_CONF_MAX_URLLEN);
508 if(argptr != NULL) {
509 strncpy(argptr, url, WWW_CONF_MAX_URLLEN);
510 }
511 program_handler_load("wget.prg", argptr);
adamdunkelsf6eea752003-08-22 19:24:40 +0000512
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000513#if WWW_CONF_FORMS
514 } else {
515 /* Check form buttons */
516 for(i = 0; i < pagewidgetptr; ++i) {
517 if(&pagewidgets[i] == w) {
518 formsubmit(&pagewidgetattribs[i].form);
519 /* show_statustext(pagewidgetattribs[i].form.formaction);*/
520 /* PRINTF(("Formaction %s formname %s inputname %s\n",
521 pagewidgetattribs[i].form.formaction,
522 pagewidgetattribs[i].form.formname,
523 pagewidgetattribs[i].form.inputname));*/
524 break;
525 }
526 }
527#endif /* WWW_CONF_FORMS */
528 }
529 } else if(s == ctk_signal_hyperlink_activate) {
530 log_back();
531 open_link(w->widget.hyperlink.url);
532 CTK_WIDGET_FOCUS(&mainwindow, &stopbutton);
adamdunkelsf6eea752003-08-22 19:24:40 +0000533 /* ctk_window_open(&mainwindow);*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000534 run = 1;
535 } else if(s == ctk_signal_hyperlink_hover) {
adamdunkels89c1f4e2003-08-09 13:33:25 +0000536 if(CTK_WIDGET_TYPE((struct ctk_widget *)data) ==
537 CTK_WIDGET_HYPERLINK) {
adamdunkelsc4bf5ca2003-04-18 00:20:22 +0000538 strncpy(statustexturl, w->widget.hyperlink.url,
539 sizeof(statustexturl));
540 petsciiconv_topetscii(statustexturl, sizeof(statustexturl));
541 show_statustext(statustexturl);
542 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000543 } else if(s == resolv_signal_found) {
544 /* Either found a hostname, or not. */
545 if((char *)data != NULL &&
546 resolv_lookup((char *)data) != NULL) {
547 open_url();
548 } else {
549 show_statustext("Host not found.");
550 }
adamdunkels30c449e2003-07-31 23:12:05 +0000551 } else if(s == ctk_signal_window_close ||
552 s == dispatcher_signal_quit) {
adamdunkelsf6eea752003-08-22 19:24:40 +0000553 quit();
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000554 }
555}
556/*-----------------------------------------------------------------------------------*/
557/* set_url():
558 *
559 * Constructs an URL from the arguments and puts it into the global
560 * "url" variable and the visible "editurl" (which is shown in the URL
561 * text entry widget in the browser window).
562 */
563static void
564set_url(char *host, u16_t port, char *file)
565{
566 char *urlptr;
567
568 memset(url, 0, WWW_CONF_MAX_URLLEN);
569
570 if(strncmp(file, http_http, 7) == 0) {
571 strncpy(url, file, sizeof(url));
572 } else {
573 strncpy(url, http_http, 7);
574 urlptr = url + 7;
575 strcpy(urlptr, host);
576 urlptr += strlen(host);
577 strcpy(urlptr, file);
578 }
579
580 show_url();
581}
582/*-----------------------------------------------------------------------------------*/
583/* webclient_aborted():
584 *
585 * Callback function. Called from the webclient when the HTTP
586 * connection was abruptly aborted.
587 */
588void
589webclient_aborted(void)
590{
591 show_statustext("Connection reset by peer");
592}
593/*-----------------------------------------------------------------------------------*/
594/* webclient_timedout():
595 *
596 * Callback function. Called from the webclient when the HTTP
597 * connection timed out.
598 */
599void
600webclient_timedout(void)
601{
602 show_statustext("Connection timed out");
603}
604/*-----------------------------------------------------------------------------------*/
605/* webclient_closed():
606 *
607 * Callback function. Called from the webclient when the HTTP
608 * connection was closed after a request from the "webclient_close()"
609 * function. .
610 */
611void
612webclient_closed(void)
613{
614 show_statustext("Stopped.");
adamdunkels17e84a32003-04-02 09:54:39 +0000615 petsciiconv_topetscii(&webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
616 WWW_CONF_WEBPAGE_WIDTH], WWW_CONF_WEBPAGE_WIDTH);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000617 redraw_window();
618}
619/*-----------------------------------------------------------------------------------*/
620/* webclient_closed():
621 *
622 * Callback function. Called from the webclient when the HTTP
623 * connection is connected.
624 */
625void
626webclient_connected(void)
627{
628 x = nextwordptr = 0;
629 starty = scrolly;
adamdunkels8bb5cca2003-08-24 22:41:31 +0000630
adamdunkels30c449e2003-07-31 23:12:05 +0000631#if WWW_CONF_PAGEVIEW
adamdunkels8bb5cca2003-08-24 22:41:31 +0000632 if(starty > 4) {
633 starty = scrolly - 4;
adamdunkels30c449e2003-07-31 23:12:05 +0000634 }
adamdunkels8bb5cca2003-08-24 22:41:31 +0000635 scrollend = starty + WWW_CONF_WEBPAGE_HEIGHT - 4;
adamdunkels30c449e2003-07-31 23:12:05 +0000636#endif /* WWW_CONF_PAGEVIEW */
637
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000638 nextword[0] = 0;
639
640 if(scrolly == 0) {
641 clear_page();
642 redraw_window();
643 }
adamdunkels30c449e2003-07-31 23:12:05 +0000644
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000645 show_statustext("Request sent...");
646 set_url(webclient_hostname(), webclient_port(), webclient_filename());
647
648#if WWW_CONF_RENDERSTATE
649 renderstate = HTMLPARSER_RENDERSTATE_NONE;
650#endif /* WWW_CONF_RENDERSTATE */
651 htmlparser_init();
652}
653/*-----------------------------------------------------------------------------------*/
654/* scroll():
655 *
656 * Scrolls the entire web page display (text and hyperlinks) one line
657 * upwards.
658 */
659static void
660scroll(void)
661{
662 unsigned char i;
663 unsigned char lptr, linkptrtmp;
664 struct ctk_widget *linksptr;
665 char *statustexttext;
666 struct ctk_widget *focuswidget;
adamdunkels30c449e2003-07-31 23:12:05 +0000667
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000668 /* Scroll text up. */
adamdunkels17e84a32003-04-02 09:54:39 +0000669 memcpy(webpage, &webpage[WWW_CONF_WEBPAGE_WIDTH],
670 (WWW_CONF_WEBPAGE_HEIGHT - 1) * WWW_CONF_WEBPAGE_WIDTH);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000671
672 /* Clear last line of text. */
adamdunkels30c449e2003-07-31 23:12:05 +0000673 memset(&webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
674 WWW_CONF_WEBPAGE_WIDTH],
adamdunkels17e84a32003-04-02 09:54:39 +0000675 ' ', WWW_CONF_WEBPAGE_WIDTH);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000676
adamdunkels30c449e2003-07-31 23:12:05 +0000677 /* Scroll links and form widgets up. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000678
679 lptr = 0;
680 linksptr = pagewidgets;
681 for(i = 0; i < pagewidgetptr; ++i) {
682 /* First, check which links that scroll off the top of the page
683 and should be removed. */
684 if(CTK_WIDGET_YPOS(linksptr) == 3) {
685 lptr = i + 1;
686 } else {
687 /* Else, move them upward one notch. */
688
689 /* XXX: this is really a hack! These values should not be used
690 like this, but should be obtained and set using some CTK API
691 function. */
adamdunkels17e84a32003-04-02 09:54:39 +0000692 linksptr->widget.hyperlink.text -= WWW_CONF_WEBPAGE_WIDTH;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000693
694 --(linksptr->y);
695 }
696 ++linksptr;
697 }
698
699 /* See if there are any links that scroll off the top. */
700 if(lptr != 0) {
701 memcpy(pagewidgets, &pagewidgets[lptr],
adamdunkels1a23b5b2003-08-05 13:50:02 +0000702 sizeof(struct ctk_widget) *
703 (WWW_CONF_MAX_NUMPAGEWIDGETS - lptr));
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000704 memcpy(pagewidgetattribs, &pagewidgetattribs[lptr],
adamdunkels1a23b5b2003-08-05 13:50:02 +0000705 sizeof(union pagewidgetattrib) *
706 (WWW_CONF_MAX_NUMPAGEWIDGETS - lptr));
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000707
708 /* Compute new value of linkptr and tuck it away in
709 linkptrtmp. make_window() destroys linkptr, so we need to
710 restore it after the call. */
711 linkptrtmp = pagewidgetptr - lptr;
712
713 /* XXX: hack - these values should *not* be obtained this way, but
714 through some CTK API instead! */
715 statustexttext = statustext.text;
716 focuswidget = mainwindow.focused;
717 ctk_window_clear(&mainwindow);
718 make_window();
719 CTK_WIDGET_FOCUS(&mainwindow, focuswidget);
720 show_statustext(statustexttext);
721
722 pagewidgetptr = linkptrtmp;
723
724 linksptr = pagewidgets;
725 for(i = 0; i < pagewidgetptr; ++i) {
726 if(linksptr->type == CTK_WIDGET_HYPERLINK) {
727 linksptr->widget.hyperlink.url -= lptr *
728 sizeof(union pagewidgetattrib);
729 }
730 CTK_WIDGET_ADD(&mainwindow, linksptr);
731 ++linksptr;
732 }
733 }
734}
735/*-----------------------------------------------------------------------------------*/
adamdunkels17e84a32003-04-02 09:54:39 +0000736static char tmpcenterline[WWW_CONF_WEBPAGE_WIDTH];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000737/* inc_y():
738 *
739 * Called from the rendering code when it is time to move on line
740 * downwards.
741 */
742static void
743inc_y(void)
744{
745 unsigned char spaces, i;
746 char *cptr;
adamdunkels1a23b5b2003-08-05 13:50:02 +0000747 register struct ctk_widget *linksptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000748
749 if(starty > 0) {
750 --starty;
751 } else {
752#if WWW_CONF_RENDERSTATE
753 /* Check if current line should be centered and if so, center
754 it. */
755 if(renderstate & HTMLPARSER_RENDERSTATE_CENTER) {
adamdunkels30c449e2003-07-31 23:12:05 +0000756 cptr = &webpage[(WWW_CONF_WEBPAGE_HEIGHT - 0) *
757 WWW_CONF_WEBPAGE_WIDTH - 1];
adamdunkels17e84a32003-04-02 09:54:39 +0000758 for(spaces = 0; spaces < WWW_CONF_WEBPAGE_WIDTH; ++spaces) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000759 if(*cptr-- != ' ') {
760 break;
761 }
762 }
763
764 spaces = spaces / 2;
765
adamdunkels30c449e2003-07-31 23:12:05 +0000766 memcpy(tmpcenterline,
adamdunkels17e84a32003-04-02 09:54:39 +0000767 &webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
768 WWW_CONF_WEBPAGE_WIDTH],
769 WWW_CONF_WEBPAGE_WIDTH);
adamdunkels30c449e2003-07-31 23:12:05 +0000770 memcpy(&webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
adamdunkels17e84a32003-04-02 09:54:39 +0000771 WWW_CONF_WEBPAGE_WIDTH] + spaces,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000772 tmpcenterline,
adamdunkels17e84a32003-04-02 09:54:39 +0000773 WWW_CONF_WEBPAGE_WIDTH - spaces);
774 memset(&webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
775 WWW_CONF_WEBPAGE_WIDTH], ' ', spaces);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000776
777 linksptr = pagewidgets;
778 for(i = 0; i < pagewidgetptr; ++i) {
adamdunkels17e84a32003-04-02 09:54:39 +0000779 if(CTK_WIDGET_YPOS(linksptr) == 3 + WWW_CONF_WEBPAGE_HEIGHT - 1) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000780 linksptr->x += spaces;
781 linksptr->widget.hyperlink.text += spaces;
782 }
783 ++linksptr;
784 }
785 }
786#endif /* WWW_CONF_RENDERSTATE */
787
adamdunkels17e84a32003-04-02 09:54:39 +0000788 petsciiconv_topetscii(&webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
789 WWW_CONF_WEBPAGE_WIDTH], WWW_CONF_WEBPAGE_WIDTH);
adamdunkels30c449e2003-07-31 23:12:05 +0000790 /* redraw_window();*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000791 scroll();
792 ++scrolly;
adamdunkels30c449e2003-07-31 23:12:05 +0000793#if WWW_CONF_PAGEVIEW
794 if(scrolly == scrollend) {
795 run = 0;
796 webclient_close();
797 }
adamdunkels11bb9462003-08-11 22:25:07 +0000798#else /* WWW_CONF_PAGEVIEW */
799 redraw_window();
adamdunkels30c449e2003-07-31 23:12:05 +0000800#endif /* WWW_CONF_PAGEVIEW */
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000801 }
802}
803/*-----------------------------------------------------------------------------------*/
804/* webclient_datahandler():
805 *
806 * Callback function. Called from the webclient module when HTTP data
807 * has arrived.
808 */
809void
810webclient_datahandler(char *data, u16_t len)
811{
812 if(len > 0) {
adamdunkelsf6eea752003-08-22 19:24:40 +0000813 if(strcmp(webclient_mimetype(), http_texthtml) == 0) {
814 count = (count + 1) & 3;
815 show_statustext(receivingmsgs[count]);
816 htmlparser_parse(data, len);
817 } else {
adamdunkels8bb5cca2003-08-24 22:41:31 +0000818 uip_abort();
adamdunkelsf6eea752003-08-22 19:24:40 +0000819 ctk_dialog_open(&wgetdialog);
820 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000821 } else {
822 /* Clear remaining parts of page. */
823 run = 0;
824 }
825
826 if(data == NULL) {
827 run = 0;
828 show_statustext("Done.");
adamdunkels17e84a32003-04-02 09:54:39 +0000829 petsciiconv_topetscii(&webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
830 WWW_CONF_WEBPAGE_WIDTH], WWW_CONF_WEBPAGE_WIDTH);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000831 redraw_window();
832 }
833}
834/*-----------------------------------------------------------------------------------*/
835/* output_word():
836 *
837 * Called from the rendering code when a full word has been received
838 * and should be put on screen.
839 */
840static void
841output_word(char c)
842{
843 char *webpageptr;
844
845 if(nextwordptr == 0) {
846 if(c == ISO_nl) {
847 x = 0;
848 inc_y();
849 }
850 return;
851 }
852
adamdunkels17e84a32003-04-02 09:54:39 +0000853 if(x + nextwordptr > WWW_CONF_WEBPAGE_WIDTH) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000854 inc_y();
855 x = 0;
856 }
857
858 nextword[nextwordptr] = 0;
859 if(starty == 0) {
adamdunkels17e84a32003-04-02 09:54:39 +0000860 webpageptr = &webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) * WWW_CONF_WEBPAGE_WIDTH + x];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000861 if(nextwordptr > 0) {
862 strcpy(webpageptr, nextword);
863 }
864 webpageptr[nextwordptr] = ' ';
865 }
866 if(c == ISO_nl) {
867 x = 0;
868 inc_y();
869 } else {
870 x += nextwordptr + 1;
871 }
872 nextwordptr = 0;
873}
874/*-----------------------------------------------------------------------------------*/
875static void *
876add_pagewidget(char *text, unsigned char type,
877 unsigned char border)
878{
adamdunkelsd59dadf2003-08-15 18:48:35 +0000879 register struct ctk_widget *lptr;
adamdunkels1a23b5b2003-08-05 13:50:02 +0000880 register unsigned char *webpageptr;
adamdunkelsfb565d92003-08-13 22:51:07 +0000881 static unsigned char len, maxwidth;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000882 static void *dataptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000883
884 len = strlen(text);
885
886 if(len + border == 0) {
887 return NULL;
888 }
889
adamdunkels17e84a32003-04-02 09:54:39 +0000890 maxwidth = WWW_CONF_WEBPAGE_WIDTH - (1 + 2 * border);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000891
892 /* If the text of the link is too long so that it does not fit into
893 the width of the current window, counting from the current x
894 coordinate, we first try to jump to the next line. */
895 if(len + x > maxwidth) {
896 output_word(ISO_nl);
897 }
898
899 /* If the text of the link still is too long, we just chop it off!
900 XXX: this is not really the right thing to do, we should probably
901 either make the link a multiline button, or add multiple
902 buttons. But this will do for now. */
903 if(len > maxwidth) {
904 text[maxwidth] = 0;
905 len = maxwidth;
906 }
907
908 dataptr = NULL;
909
910 if(starty == 0) {
adamdunkels30c449e2003-07-31 23:12:05 +0000911 webpageptr = &webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
912 WWW_CONF_WEBPAGE_WIDTH + x];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000913 /* To save memory, we'll copy the widget text to the web page
914 drawing area and reference it from there. */
915 webpageptr[0] = 0;
916 webpageptr += border;
917 strncpy(webpageptr, text, len);
918 webpageptr[len] = 0;
919 webpageptr[len + border] = ' ';
adamdunkels17e84a32003-04-02 09:54:39 +0000920 if(pagewidgetptr < WWW_CONF_MAX_NUMPAGEWIDGETS) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000921 dataptr = &pagewidgetattribs[pagewidgetptr];
922 lptr = &pagewidgets[pagewidgetptr];
923
924 switch(type) {
925 case CTK_WIDGET_HYPERLINK:
926 CTK_HYPERLINK_NEW((struct ctk_hyperlink *)lptr, x,
adamdunkels17e84a32003-04-02 09:54:39 +0000927 WWW_CONF_WEBPAGE_HEIGHT + 2, len,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000928 webpageptr, dataptr);
929 break;
930 case CTK_WIDGET_BUTTON:
931 CTK_BUTTON_NEW((struct ctk_button *)lptr, x,
adamdunkels17e84a32003-04-02 09:54:39 +0000932 WWW_CONF_WEBPAGE_HEIGHT + 2, len,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000933 webpageptr);
934 ((struct formattribs *)dataptr)->inputvalue = webpageptr;
935 break;
936 case CTK_WIDGET_TEXTENTRY:
937 CTK_TEXTENTRY_NEW((struct ctk_textentry *)lptr,
adamdunkels17e84a32003-04-02 09:54:39 +0000938 x, WWW_CONF_WEBPAGE_HEIGHT + 2, len, 1,
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000939 webpageptr, len);
940 ((struct formattribs *)dataptr)->inputvalue = webpageptr;
941 break;
942 }
943 CTK_WIDGET_ADD(&mainwindow, lptr);
944
945 ++pagewidgetptr;
946 }
947 }
948 /* Increase the x coordinate with the length of the link text plus
949 the extra space behind it and the CTK button markers. */
950 x += len + 1 + 2 * border;
951
adamdunkels17e84a32003-04-02 09:54:39 +0000952 if(x >= WWW_CONF_WEBPAGE_WIDTH) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000953 inc_y();
954 x = 0;
955 }
956
957 return dataptr;
958}
959/*-----------------------------------------------------------------------------------*/
960/* htmlparser_link:
961 *
962 * Callback function. Will be called when the HTML parser has parsed a
963 * link. We will put a CTK hyperlink widget at the appropriate position
964 * in the window.
965 */
966void
967htmlparser_link(char *text, char *url)
968{
969 static unsigned char *linkurlptr;
970
971 linkurlptr = add_pagewidget(text, CTK_WIDGET_HYPERLINK, 0);
972 if(linkurlptr != NULL &&
973 strlen(url) < WWW_CONF_MAX_URLLEN) {
974 strcpy(linkurlptr, url);
975 }
976}
977/*-----------------------------------------------------------------------------------*/
978/* htmlparser_char():
979 *
980 * Callback function. Called by the HTML parser module for every
981 * printable character in the HTML file.
982 */
983void
984htmlparser_char(char c)
985{
986 if(c == ' ' ||
987 c == ISO_nl) {
988 output_word(c);
adamdunkels30c449e2003-07-31 23:12:05 +0000989 } else if(c != 0 && (c & 0x80) == 0) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000990 nextword[nextwordptr] = c;
adamdunkels17e84a32003-04-02 09:54:39 +0000991 if(nextwordptr < WWW_CONF_WEBPAGE_WIDTH) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000992 ++nextwordptr;
993 }
994 }
995}
996/*-----------------------------------------------------------------------------------*/
997#if WWW_CONF_RENDERSTATE
998void
999htmlparser_renderstate(unsigned char s)
1000{
1001 if((s & HTMLPARSER_RENDERSTATE_STATUSMASK) ==
1002 HTMLPARSER_RENDERSTATE_BEGIN) {
1003 renderstate |= s & ~HTMLPARSER_RENDERSTATE_STATUSMASK;
1004 } else {
1005 renderstate &= ~(s & ~HTMLPARSER_RENDERSTATE_STATUSMASK);
1006 }
1007}
1008#endif /* WWW_CONF_RENDERSTATE */
1009
1010#if WWW_CONF_FORMS
1011/*-----------------------------------------------------------------------------------*/
1012void
1013htmlparser_submitbutton(char *text, char *name,
1014 char *formname, char *formaction)
1015{
1016 register struct formattribs *form;
adamdunkels30c449e2003-07-31 23:12:05 +00001017
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001018 form = add_pagewidget(text, CTK_WIDGET_BUTTON, 1);
1019 if(form != NULL) {
1020 strncpy(form->formaction, formaction, WWW_CONF_MAX_FORMACTIONLEN);
1021 strncpy(form->formname, formname, WWW_CONF_MAX_FORMNAMELEN);
1022 strncpy(form->inputname, name, WWW_CONF_MAX_INPUTNAMELEN);
1023 form->inputtype = FORMINPUTTYPE_SUBMITBUTTON;
1024 }
adamdunkels30c449e2003-07-31 23:12:05 +00001025
1026
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001027}
1028/*-----------------------------------------------------------------------------------*/
1029void
1030htmlparser_inputfield(char *text, char *name,
1031 char *formname, char *formaction)
1032{
1033 register struct formattribs *form;
1034
1035 form = add_pagewidget(text, CTK_WIDGET_TEXTENTRY, 1);
1036 if(form != NULL) {
1037 strncpy(form->formaction, formaction, WWW_CONF_MAX_FORMACTIONLEN);
1038 strncpy(form->formname, formname, WWW_CONF_MAX_FORMNAMELEN);
1039 strncpy(form->inputname, name, WWW_CONF_MAX_INPUTNAMELEN);
1040 form->inputtype = FORMINPUTTYPE_INPUTFIELD;
1041 }
1042}
1043/*-----------------------------------------------------------------------------------*/
1044static void
1045formsubmit(struct formattribs *attribs)
1046{
1047 unsigned char i, j;
adamdunkels1a23b5b2003-08-05 13:50:02 +00001048 register char *urlptr, *valueptr;
1049 register struct formattribs *faptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001050
1051 urlptr = &tmpurl[0];
1052
1053 strncpy(urlptr, attribs->formaction, WWW_CONF_MAX_URLLEN);
1054 tmpurl[WWW_CONF_MAX_URLLEN] = 0;
1055 urlptr += strlen(urlptr);
1056 *urlptr = ISO_questionmark;
1057 ++urlptr;
1058
1059
1060 /* Construct an URL by finding all input field forms with the same
1061 formname as the current submit button, and add the submit button
1062 URL stuff as well. */
1063 for(i = 0; i < pagewidgetptr; ++i) {
1064 if(urlptr - &tmpurl[0] >= WWW_CONF_MAX_URLLEN) {
1065 break;
1066 }
1067
1068 faptr = &pagewidgetattribs[i].form;
1069
1070 if(strcmp(attribs->formaction, faptr->formaction) == 0 &&
1071 strcmp(attribs->formname, faptr->formname) == 0 &&
1072 (faptr->inputtype == FORMINPUTTYPE_INPUTFIELD ||
1073 faptr == attribs)) {
1074
1075 /* Copy the name of the input field into the URL and append a
1076 questionmark. */
1077 strncpy(urlptr, faptr->inputname, WWW_CONF_MAX_URLLEN - strlen(tmpurl));
1078 tmpurl[WWW_CONF_MAX_URLLEN] = 0;
1079 urlptr += strlen(urlptr);
1080 *urlptr = ISO_eq;
1081 ++urlptr;
1082
1083 /* Convert and copy the contents of the input field to the URL
1084 and append an ampersand. */
1085 valueptr = pagewidgets[i].widget.textentry.text;
1086 petsciiconv_toascii(valueptr, WWW_CONF_MAX_INPUTVALUELEN);
1087 for(j = 0; j < WWW_CONF_MAX_INPUTVALUELEN; ++j) {
1088 if(urlptr - &tmpurl[0] >= WWW_CONF_MAX_URLLEN) {
1089 break;
1090 }
1091 *urlptr = *valueptr;
1092 if(*urlptr == ISO_space) {
1093 *urlptr = ISO_plus;
1094 }
1095 if(*urlptr == 0) {
1096 break;
1097 }
1098 ++urlptr;
1099 ++valueptr;
1100 }
1101
1102 *urlptr = ISO_ampersand;
1103 ++urlptr;
1104 }
1105 }
1106 --urlptr;
1107 *urlptr = 0;
1108 /* PRINTF(("formsubmit: URL '%s'\n", tmpurl));*/
adamdunkels89c1f4e2003-08-09 13:33:25 +00001109 log_back();
adamdunkelsca9ddcb2003-03-19 14:13:31 +00001110 open_link(tmpurl);
1111}
1112/*-----------------------------------------------------------------------------------*/
1113#endif /* WWW_CONF_FORMS */