Initial import
diff --git a/contiki/README b/contiki/README
new file mode 100644
index 0000000..1c3ebef
--- /dev/null
+++ b/contiki/README
@@ -0,0 +1,28 @@
+This is the source code for the Contiki desktop environment, which is
+a modern Internet-enabled desktop environment for the Commodore 64 and
+a bunch of other systems written by Adam Dunkels. The Contiki desktop
+environment includes a simple window system and GUI, TCP/IP
+networking, a web server, a telnet client, and a web browser. Contiki
+is written in C and is compiled with Ullrich von Bassewitz' cc65 C
+compiler.
+
+More information about the Contiki desktop environment can be found on
+its web page:
+
+ http://dunkels.com/adam/contiki/
+
+The cc65 C compiler can be found on the cc65 web page:
+
+ http://www.cc65.org/
+
+The Contiki desktop environment source code is divided into the
+following directories:
+
+ apps/ - the Contiki applications
+ ctk/ - the ctk conio windowing toolkit on which Contiki builds
+ ek/ - the ek event kernel and the dispatcher
+ lib/ - various library files
+ uip/ - the uIP TCP/IP stack
+
+To build the Contiki desktop environment from sources, GNU make and
+cc65 must be installed.
diff --git a/contiki/apps/contiki.c b/contiki/apps/contiki.c
new file mode 100644
index 0000000..0644480
--- /dev/null
+++ b/contiki/apps/contiki.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: contiki.c,v 1.1 2003/03/19 14:13:32 adamdunkels Exp $
+ *
+ */
+
+#include "uip_main.h"
+#include "uip.h"
+#include "uip_arp.h"
+#include "ctk.h"
+#include "dispatcher.h"
+#include "resolv.h"
+#include "email.h"
+
+static struct ctk_menu menu;
+unsigned char menuitem_about, menuitem_processes, menuitem_tcpip;
+
+#define MAX_PROCESSLABELS 10
+static struct ctk_window processwindow;
+static unsigned char ids[MAX_PROCESSLABELS][3];
+static struct ctk_label processidlabels[MAX_PROCESSLABELS];
+static struct ctk_label processnamelabels[MAX_PROCESSLABELS];
+
+static struct ctk_button processupdatebutton =
+ {CTK_BUTTON(0, 9, 6, "Update")};
+static struct ctk_button processclosebutton =
+ {CTK_BUTTON(13, 9, 5, "Close")};
+
+static struct ctk_window aboutdialog;
+static struct ctk_label aboutlabel1 =
+ {CTK_LABEL(5, 0, 23, 1, "The Contiki Desktop OS")};
+static struct ctk_label aboutlabel2 =
+ {CTK_LABEL(3, 3, 28, 1, "A modern, Internet-enabled")};
+static struct ctk_label aboutlabel3 =
+ {CTK_LABEL(2, 4, 28, 1, "operating system and desktop")};
+static struct ctk_label aboutlabel4 =
+ {CTK_LABEL(0, 5, 32, 1, "environment for the Commodore 64")};
+static struct ctk_label aboutlabel5 =
+ {CTK_LABEL(4, 6, 26, 1, "written by Adam Dunkels")};
+
+static char abouturl_petscii[] = "http://dunkels.com/adam/contiki/";
+static char abouturl_ascii[40];
+static struct ctk_hyperlink abouturl =
+ {CTK_HYPERLINK(0, 8, 32, "http://dunkels.com/adam/contiki/",
+ abouturl_ascii)};
+static struct ctk_button aboutclose =
+ {CTK_BUTTON(12, 10, 5, "Close")};
+
+/* TCP/IP configuration window. */
+static struct ctk_window tcpipwindow;
+
+#ifdef WITH_ETHERNET
+static struct ctk_label ipaddrlabel =
+ {CTK_LABEL(0, 1, 10, 1, "IP address")};
+static char ipaddr[17];
+static struct ctk_textentry ipaddrtextentry =
+ {CTK_TEXTENTRY(11, 1, 16, 1, ipaddr, 16)};
+static struct ctk_label netmasklabel =
+ {CTK_LABEL(0, 3, 10, 1, "Netmask")};
+static char netmask[17];
+static struct ctk_textentry netmasktextentry =
+ {CTK_TEXTENTRY(11, 3, 16, 1, netmask, 16)};
+static struct ctk_label gatewaylabel =
+ {CTK_LABEL(0, 5, 10, 1, "Gateway")};
+static char gateway[17];
+static struct ctk_textentry gatewaytextentry =
+ {CTK_TEXTENTRY(11, 5, 16, 1, gateway, 16)};
+static struct ctk_label dnsserverlabel =
+ {CTK_LABEL(0, 7, 10, 1, "DNS server")};
+static char dnsserver[17];
+static struct ctk_textentry dnsservertextentry =
+ {CTK_TEXTENTRY(11, 7, 16, 1, dnsserver, 16)};
+#else /* WITH_ETHERNET */
+static struct ctk_label ipaddrlabel =
+ {CTK_LABEL(0, 2, 10, 1, "IP address")};
+static char ipaddr[17];
+static struct ctk_textentry ipaddrtextentry =
+ {CTK_TEXTENTRY(11, 2, 16, 1, ipaddr, 16)};
+static struct ctk_label dnsserverlabel =
+ {CTK_LABEL(0, 4, 10, 1, "DNS server")};
+static char dnsserver[17];
+static struct ctk_textentry dnsservertextentry =
+ {CTK_TEXTENTRY(11, 4, 16, 1, dnsserver, 16)};
+#endif /* WITH_ETHERNET */
+
+static struct ctk_button tcpipclosebutton =
+ {CTK_BUTTON(0, 9, 2, "Ok")};
+
+/* . == 0, + == 1 */
+static unsigned char abouticon_bitmap[3*3*8] = {
+ 0x00, 0x7f, 0x43, 0x4c, 0x58, 0x53, 0x60, 0x6f,
+ 0x00, 0xff, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xfe, 0xc2, 0x32, 0x1a, 0xca, 0x06, 0xf6,
+
+ 0x40, 0x5f, 0x40, 0x5f, 0x40, 0x5f, 0x40, 0x4f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xfc, 0x01, 0xf3,
+ 0x02, 0xfa, 0x02, 0x82, 0x3e, 0xfe, 0xfe, 0xfe,
+
+ 0x60, 0x67, 0x50, 0x59, 0x4c, 0x43, 0x7f, 0x00,
+ 0x07, 0xe7, 0x0f, 0xef, 0x0f, 0x0f, 0xff, 0x00,
+ 0x8e, 0x06, 0x06, 0x06, 0x8e, 0xfe, 0xfe, 0x00
+};
+
+static char abouticon_textmap[9] = {
+ ' ', ' ', 'c',
+ ' ', '?', ' ',
+ '.', ' ', ' '
+};
+
+static struct ctk_icon abouticon =
+ {CTK_ICON("About Contiki", abouticon_bitmap, abouticon_textmap)};
+
+/* . == 0, + == 1 */
+static unsigned char tcpipconficon_bitmap[3*3*8] = {
+ 0x00, 0x79, 0x43, 0x73, 0x47, 0x77, 0x47, 0x6f,
+ 0x00, 0xfe, 0xfe, 0xfc, 0xfc, 0xfc, 0xf8, 0xfb,
+ 0x00, 0x16, 0x02, 0x00, 0x02, 0x00, 0x00, 0xc2,
+
+ 0x48, 0x4c, 0x5f, 0x5f, 0x1f, 0x3f, 0x3f, 0x03,
+ 0x79, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xfe, 0xfc,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ 0x77, 0x47, 0x70, 0x43, 0x79, 0x41, 0x7c, 0x00,
+ 0xfc, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xf7, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x84, 0xf0, 0x00
+};
+
+static char tcpipconficon_textmap[9] = {
+ 't', 'c', 'p',
+ '/', 'i', 'p',
+ 'c', 'f', 'g'
+};
+
+
+static struct ctk_icon tcpipconficon =
+ {CTK_ICON("TCP/IP conf", tcpipconficon_bitmap, tcpipconficon_textmap)};
+
+static void sighandler(ek_signal_t s, ek_data_t data);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("Contiki", NULL, sighandler, NULL)};
+static ek_id_t id;
+
+/*-----------------------------------------------------------------------------------*/
+static void
+update_processwindow(void)
+{
+ unsigned char i, *idsptr;
+ struct dispatcher_proc *p;
+
+ for(i = 0; i < MAX_PROCESSLABELS; ++i) {
+ p = dispatcher_process(i);
+ if(p != NULL) {
+ idsptr = ids[i];
+ idsptr[0] = '0' + i / 10;
+ idsptr[1] = '0' + i % 10;
+ idsptr[2] = 0;
+ CTK_LABEL_NEW(&processidlabels[i],
+ 0, i + 1, 2, 1, idsptr);
+ CTK_WIDGET_ADD(&processwindow, &processidlabels[i]);
+
+ CTK_LABEL_NEW(&processnamelabels[i],
+ 3, i + 1, 17, 1, p->name);
+ CTK_WIDGET_ADD(&processwindow, &processnamelabels[i]);
+ }
+ }
+
+ CTK_WIDGET_ADD(&processwindow, &processupdatebutton);
+ CTK_WIDGET_ADD(&processwindow, &processclosebutton);
+ CTK_WIDGET_FOCUS(&processwindow, &processupdatebutton);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+make_processwindow(void)
+{
+ ctk_window_new(&processwindow, 20, 10, "Processes");
+ ctk_window_move(&processwindow, 0, 1);
+ update_processwindow();
+}
+/*-----------------------------------------------------------------------------------*/
+void
+contiki_init(void)
+{
+ id = dispatcher_start(&p);
+
+ ctk_dialog_new(&aboutdialog, 32, 11);
+ CTK_WIDGET_ADD(&aboutdialog, &aboutlabel1);
+ CTK_WIDGET_ADD(&aboutdialog, &aboutlabel2);
+ CTK_WIDGET_ADD(&aboutdialog, &aboutlabel3);
+ CTK_WIDGET_ADD(&aboutdialog, &aboutlabel4);
+ CTK_WIDGET_ADD(&aboutdialog, &aboutlabel5);
+ CTK_WIDGET_ADD(&aboutdialog, &abouturl);
+ CTK_WIDGET_ADD(&aboutdialog, &aboutclose);
+ CTK_WIDGET_FOCUS(&aboutdialog, &aboutclose);
+
+ ctk_menu_new(&menu, "Contiki");
+ menuitem_about = ctk_menuitem_add(&menu, "About");
+ menuitem_processes = ctk_menuitem_add(&menu, "Processes");
+
+ menuitem_tcpip = ctk_menuitem_add(&menu, "TCP/IP conf");
+#if 0
+#ifdef WITH_ETHERNET
+ menuitem_ethernet = ctk_menuitem_add(&menu, "Ethernet");
+#endif /* WITH_ETHERNET */
+#ifdef WITH_RS232
+ menuitem_serial = ctk_menuitem_add(&menu, "Serial link");
+#endif /* WITH_RS232 */
+#endif /* 0 */
+
+ strcpy(abouturl_ascii, abouturl_petscii);
+ petsciiconv_toascii(abouturl_ascii, sizeof(abouturl_ascii));
+
+ /* Create TCP/IP configuration window. */
+ ctk_window_new(&tcpipwindow, 30, 10, "TCP/IP config");
+ ctk_window_move(&tcpipwindow, 4, 6);
+
+
+#ifdef WITH_ETHERNET
+ CTK_WIDGET_ADD(&tcpipwindow, &ipaddrlabel);
+ CTK_WIDGET_ADD(&tcpipwindow, &ipaddrtextentry);
+ CTK_WIDGET_ADD(&tcpipwindow, &netmasklabel);
+ CTK_WIDGET_ADD(&tcpipwindow, &netmasktextentry);
+ CTK_WIDGET_ADD(&tcpipwindow, &gatewaylabel);
+ CTK_WIDGET_ADD(&tcpipwindow, &gatewaytextentry);
+ CTK_WIDGET_ADD(&tcpipwindow, &dnsserverlabel);
+ CTK_WIDGET_ADD(&tcpipwindow, &dnsservertextentry);
+#else
+ CTK_WIDGET_ADD(&tcpipwindow, &ipaddrlabel);
+ CTK_WIDGET_ADD(&tcpipwindow, &ipaddrtextentry);
+ CTK_WIDGET_ADD(&tcpipwindow, &dnsserverlabel);
+ CTK_WIDGET_ADD(&tcpipwindow, &dnsservertextentry);
+#endif /* WITH_ETHERNET */
+
+ CTK_WIDGET_ADD(&tcpipwindow, &tcpipclosebutton);
+
+ CTK_WIDGET_FOCUS(&tcpipwindow, &ipaddrtextentry);
+
+ ctk_menu_add(&menu);
+
+ CTK_ICON_ADD(&abouticon, id);
+ CTK_ICON_ADD(&tcpipconficon, id);
+
+ dispatcher_listen(ctk_signal_button_activate);
+ dispatcher_listen(ctk_signal_menu_activate);
+ dispatcher_listen(ctk_signal_hyperlink_activate);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+nullterminate(char *cptr)
+{
+ /* Find the first space character in the ipaddr and put a zero there
+ to end the string. */
+ for(; *cptr != ' ' && *cptr != 0; ++cptr);
+ *cptr = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+apply_tcpipconfig(void)
+{
+ u16_t addr[2];
+
+#ifdef WITH_UIP
+ nullterminate(ipaddr);
+ if(uip_main_ipaddrconv(ipaddr, (unsigned char *)addr)) {
+ uip_sethostaddr(addr);
+ }
+
+#ifdef WITH_ETHERNET
+ nullterminate(netmask);
+ if(uip_main_ipaddrconv(netmask, (unsigned char *)addr)) {
+ uip_setnetmask(addr);
+ }
+
+ nullterminate(gateway);
+ if(uip_main_ipaddrconv(gateway, (unsigned char *)addr)) {
+ uip_setdraddr(addr);
+ }
+#endif /* WITH_ETHERNET */
+
+ nullterminate(dnsserver);
+ if(uip_main_ipaddrconv(dnsserver, (unsigned char *)addr)) {
+ resolv_conf(addr);
+ }
+#endif /* WITH_UIP */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sighandler(ek_signal_t s, ek_data_t data)
+{
+ struct ctk_widget *w;
+
+ if(s == ctk_signal_button_activate) {
+ w = (struct ctk_widget *)data;
+ if(w == (struct ctk_widget *)&aboutclose) {
+ ctk_dialog_close();
+ ctk_redraw();
+ } else if(w == (struct ctk_widget *)&abouticon) {
+ ctk_dialog_open(&aboutdialog);
+ ctk_redraw();
+ } else if(w == (struct ctk_widget *)&tcpipclosebutton) {
+ apply_tcpipconfig();
+ ctk_window_close(&tcpipwindow);
+ ctk_redraw();
+ } else if(w == (struct ctk_widget *)&tcpipconficon) {
+ ctk_window_open(&tcpipwindow);
+ ctk_redraw();
+ } else if(w == (struct ctk_widget *)&processupdatebutton) {
+ ctk_window_clear(&processwindow);
+ update_processwindow();
+ ctk_window_redraw(&processwindow);
+ } else if(w == (struct ctk_widget *)&processclosebutton) {
+ ctk_window_close(&processwindow);
+ ctk_redraw();
+ }
+
+ } else if(s == ctk_signal_menu_activate) {
+ if((struct ctk_menu *)data == &menu) {
+ if(menu.active == menuitem_about) {
+ ctk_dialog_open(&aboutdialog);
+ } else if(menu.active == menuitem_processes) {
+ make_processwindow();
+ ctk_window_open(&processwindow);
+ } else if(menu.active == menuitem_tcpip) {
+ ctk_window_open(&tcpipwindow);
+ }
+ ctk_redraw();
+ }
+ } else if(s == ctk_signal_hyperlink_activate) {
+ if((struct ctk_widget *)data == (struct ctk_widget *)&abouturl) {
+ ctk_dialog_close();
+ ctk_redraw();
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/contiki.h b/contiki/apps/contiki.h
new file mode 100644
index 0000000..e9a50c0
--- /dev/null
+++ b/contiki/apps/contiki.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: contiki.h,v 1.1 2003/03/19 14:13:32 adamdunkels Exp $
+ *
+ */
+#ifndef __CONTIKI_H__
+#define __CONTIKI_H__
+
+void contiki_init(void);
+
+#endif /* __CONTIKI_H__ */
diff --git a/contiki/apps/email.c b/contiki/apps/email.c
new file mode 100644
index 0000000..4a1ac38
--- /dev/null
+++ b/contiki/apps/email.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: email.c,v 1.1 2003/03/19 14:13:32 adamdunkels Exp $
+ *
+ */
+
+
+#include "ctk.h"
+#include "dispatcher.h"
+#include "smtp.h"
+#include "uip_main.h"
+#include "petsciiconv.h"
+
+#define MAXNUMMSGS 6
+
+static struct ctk_menu menu;
+unsigned char menuitem_open, menuitem_setup;
+
+/* The main window. */
+static struct ctk_window mainwindow;
+
+static struct ctk_button newmailbutton =
+ {CTK_BUTTON(26, 0, 8, "New mail")};
+static struct ctk_button checkbutton =
+ {CTK_BUTTON(0, 0, 10, "Check mail")};
+
+static struct ctk_button msgbuttons[MAXNUMMSGS];
+static struct ctk_label msglabels[MAXNUMMSGS];
+static char msgtitles[20][MAXNUMMSGS];
+static struct ctk_separator sep1 =
+ {CTK_SEPARATOR(0, 7, 36)};
+static struct ctk_separator sep2 =
+ {CTK_SEPARATOR(0, 20, 36)};
+static struct ctk_label statuslabel =
+ {CTK_LABEL(6, 21, 23, 1, "")};
+
+
+static struct ctk_label tolabel =
+ {CTK_LABEL(0, 8, 3, 1, "To:")};
+static char to[40];
+static struct ctk_textentry totextentry =
+ {CTK_TEXTENTRY(8, 8, 26, 1, to, 38)};
+
+static struct ctk_label cclabel =
+ {CTK_LABEL(0, 9, 3, 1, "Cc:")};
+static char cc[40];
+static struct ctk_textentry cctextentry =
+ {CTK_TEXTENTRY(8, 9, 26, 1, cc, 38)};
+
+static struct ctk_label subjectlabel =
+ {CTK_LABEL(0, 10, 8, 1, "Subject:")};
+static char subject[40];
+static struct ctk_textentry subjecttextentry =
+ {CTK_TEXTENTRY(8, 10, 26, 1, subject, 38)};
+
+static char mail[36*9];
+static struct ctk_textentry mailtextentry =
+ {CTK_TEXTENTRY(0, 11, 34, 9, mail, 36)};
+
+static struct ctk_button sendbutton =
+ {CTK_BUTTON(0, 21, 4, "Send")};
+static struct ctk_button erasebutton =
+ {CTK_BUTTON(29, 21, 5, "Erase")};
+
+/* The "Really cancel message?" dialog. */
+static struct ctk_window canceldialog;
+static struct ctk_label canceldialoglabel1 =
+ {CTK_LABEL(2, 1, 22, 1, "Really cancel message?")};
+static struct ctk_label canceldialoglabel2 =
+ {CTK_LABEL(0, 2, 26, 1, "All contents will be lost.")};
+static struct ctk_button cancelyesbutton =
+ {CTK_BUTTON(4, 4, 3, "Yes")};
+static struct ctk_button cancelnobutton =
+ {CTK_BUTTON(18, 8, 2, "No")};
+
+/* The setup window. */
+static struct ctk_window setupwindow;
+static struct ctk_label fromaddresslabel =
+ {CTK_LABEL(0, 0, 25, 1, "Name and e-mail address")};
+static char fromaddress[40];
+static struct ctk_textentry fromaddresstextentry =
+ {CTK_TEXTENTRY(0, 1, 25, 1, fromaddress, 39)};
+
+static struct ctk_label smtpserverlabel =
+ {CTK_LABEL(0, 3, 20, 1, "Outgoing mailserver")};
+static char smtpserver[40];
+static struct ctk_textentry smtpservertextentry =
+ {CTK_TEXTENTRY(0, 4, 25, 1, smtpserver, 39)};
+
+static struct ctk_label pop3serverlabel =
+ {CTK_LABEL(0, 6, 20, 1, "Incoming mailserver")};
+static char pop3server[40];
+static struct ctk_textentry pop3servertextentry =
+ {CTK_TEXTENTRY(0, 7, 25, 1, pop3server, 39)};
+
+static struct ctk_label pop3userlabel =
+ {CTK_LABEL(0, 9, 20, 1, "Mailserver username")};
+static char pop3user[40];
+static struct ctk_textentry pop3usertextentry =
+ {CTK_TEXTENTRY(0, 10, 25, 1, pop3user, 39)};
+
+static struct ctk_label pop3passwordlabel =
+ {CTK_LABEL(0, 12, 20, 1, "Mailserver password")};
+static char pop3password[40];
+static struct ctk_textentry pop3passwordtextentry =
+ {CTK_TEXTENTRY(0, 13, 25, 1, pop3password, 39)};
+
+
+static struct ctk_button setupokbutton =
+ {CTK_BUTTON(24, 15, 2, "Ok")};
+
+static void sighandler(ek_signal_t s, ek_data_t data);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("E-mail client", NULL, sighandler, smtp_appcall)};
+static ek_id_t id;
+
+/*-----------------------------------------------------------------------------------*/
+static void
+make_window(void)
+{
+ unsigned char i;
+ struct ctk_button *button;
+ struct ctk_label *label;
+
+ /* Create the main window. */
+ ctk_window_new(&mainwindow, 36, 22, "E-mail");
+ ctk_window_move(&mainwindow, 1, 0);
+
+ CTK_WIDGET_ADD(&mainwindow, &checkbutton);
+ CTK_WIDGET_FOCUS(&mainwindow, &checkbutton);
+ CTK_WIDGET_ADD(&mainwindow, &newmailbutton);
+ CTK_WIDGET_ADD(&mainwindow, &sep1);
+ CTK_WIDGET_ADD(&mainwindow, &sep2);
+ CTK_WIDGET_ADD(&mainwindow, &statuslabel);
+
+ for(i = 0; i < MAXNUMMSGS; ++i) {
+ button = &msgbuttons[i];
+ CTK_BUTTON_NEW(button, 0, i + 1, 1, " ");
+ CTK_WIDGET_ADD(&mainwindow, button);
+ label = &msglabels[i];
+ CTK_LABEL_NEW(label, 3, i + 1, 33, 1, msgtitles[i]);
+ CTK_WIDGET_ADD(&mainwindow, label);
+ }
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+make_composer(void)
+{
+ CTK_WIDGET_ADD(&mainwindow, &tolabel);
+ CTK_WIDGET_ADD(&mainwindow, &cclabel);
+ CTK_WIDGET_ADD(&mainwindow, &subjectlabel);
+
+ CTK_WIDGET_ADD(&mainwindow, &totextentry);
+ CTK_WIDGET_FOCUS(&mainwindow, &totextentry);
+ CTK_WIDGET_ADD(&mainwindow, &cctextentry);
+ CTK_WIDGET_ADD(&mainwindow, &subjecttextentry);
+
+ CTK_WIDGET_ADD(&mainwindow, &mailtextentry);
+
+ CTK_WIDGET_ADD(&mainwindow, &sendbutton);
+ CTK_WIDGET_ADD(&mainwindow, &erasebutton);
+
+ memset(mail, ' ', sizeof(mail));
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+make_read(void)
+{
+ CTK_WIDGET_ADD(&mainwindow, &tolabel);
+ CTK_WIDGET_ADD(&mainwindow, &cclabel);
+ CTK_WIDGET_ADD(&mainwindow, &subjectlabel);
+
+ CTK_WIDGET_ADD(&mainwindow, &totextentry);
+ /* CTK_WIDGET_FOCUS(&mainwindow, &totextentry); */
+ CTK_WIDGET_ADD(&mainwindow, &cctextentry);
+ CTK_WIDGET_ADD(&mainwindow, &subjecttextentry);
+
+ CTK_WIDGET_ADD(&mainwindow, &mailtextentry);
+
+ CTK_WIDGET_ADD(&mainwindow, &sendbutton);
+ CTK_WIDGET_ADD(&mainwindow, &erasebutton);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+email_init(void)
+{
+ if(id == EK_ID_NONE) {
+ id = dispatcher_start(&p);
+
+ /* Create the "Really cancel message?" dialog. */
+ ctk_dialog_new(&canceldialog, 26, 6);
+ CTK_WIDGET_ADD(&canceldialog, &canceldialoglabel1);
+ CTK_WIDGET_ADD(&canceldialog, &canceldialoglabel2);
+ CTK_WIDGET_ADD(&canceldialog, &cancelyesbutton);
+ CTK_WIDGET_ADD(&canceldialog, &cancelnobutton);
+ CTK_WIDGET_FOCUS(&canceldialog, &cancelnobutton);
+
+ /* Create setup window. */
+ ctk_window_new(&setupwindow, 28, 16, "E-mail setup");
+ ctk_window_move(&setupwindow, 5, 3);
+
+ CTK_WIDGET_ADD(&setupwindow, &fromaddresslabel);
+ CTK_WIDGET_ADD(&setupwindow, &fromaddresstextentry);
+ CTK_WIDGET_ADD(&setupwindow, &smtpserverlabel);
+ CTK_WIDGET_ADD(&setupwindow, &smtpservertextentry);
+ CTK_WIDGET_ADD(&setupwindow, &pop3serverlabel);
+ CTK_WIDGET_ADD(&setupwindow, &pop3servertextentry);
+ CTK_WIDGET_ADD(&setupwindow, &pop3userlabel);
+ CTK_WIDGET_ADD(&setupwindow, &pop3usertextentry);
+ CTK_WIDGET_ADD(&setupwindow, &pop3passwordlabel);
+ CTK_WIDGET_ADD(&setupwindow, &pop3passwordtextentry);
+ CTK_WIDGET_ADD(&setupwindow, &setupokbutton);
+
+ CTK_WIDGET_FOCUS(&setupwindow, &fromaddresstextentry);
+
+
+ /* Create main window. */
+ make_window();
+ make_composer();
+
+ /* Create and add the menu */
+ ctk_menu_new(&menu, "E-mail");
+ menuitem_setup = ctk_menuitem_add(&menu, "Setup");
+ menuitem_open = ctk_menuitem_add(&menu, "Open");
+ ctk_menu_add(&menu);
+
+ /* Attach listeners to signals. */
+ dispatcher_listen(ctk_signal_button_activate);
+ dispatcher_listen(ctk_signal_menu_activate);
+
+ /* Open setup window */
+ ctk_window_open(&setupwindow);
+ } else {
+ ctk_window_open(&mainwindow);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+applyconfig(void)
+{
+ u16_t addr[2];
+ char *cptr;
+
+ for(cptr = smtpserver; *cptr != ' ' && *cptr != 0; ++cptr);
+ *cptr = 0;
+
+ if(uip_main_ipaddrconv(smtpserver, (unsigned char *)addr)) {
+ smtp_configure("contiki", addr);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+prepare_message(void)
+{
+ char *mptr1, *mptr2;
+
+ /* Convert fields to ASCII. */
+ petsciiconv_toascii(to, sizeof(to));
+ petsciiconv_toascii(subject, sizeof(subject));
+ petsciiconv_toascii(mail, 255);
+ petsciiconv_toascii(mail + 255, sizeof(mail) - 255);
+
+ /* Insert line delimiters. */
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sighandler(ek_signal_t s, ek_data_t data)
+{
+ struct ctk_widget *w;
+ unsigned char i;
+
+ if(s == ctk_signal_button_activate) {
+ w = (struct ctk_widget *)data;
+ if(w == (struct ctk_widget *)&newmailbutton) {
+ /* ctk_window_open(&composerwindow);*/
+ ctk_window_close(&mainwindow);
+ make_window();
+ make_composer();
+ ctk_window_open(&mainwindow);
+ ctk_window_redraw(&mainwindow);
+#if 0
+ } else if(w == &replybutton) {
+ /* XXX Fiddle in the from and subject fields into the new
+ mail. */
+ ctk_window_open(&composerwindow);
+ ctk_redraw();
+#endif
+ } else if(w == (struct ctk_widget *)&checkbutton) {
+ /* XXX Should actually check email. */
+ ctk_label_set_text(&statuslabel, "Checking mail...");
+ ctk_window_redraw(&mainwindow);
+ } else if(w == (struct ctk_widget *)&sendbutton) {
+ prepare_message();
+ smtp_send(to, fromaddress, subject, mail, sizeof(mail));
+ ctk_label_set_text(&statuslabel, "Sending message...");
+ ctk_redraw();
+ } else if(w == (struct ctk_widget *)&erasebutton) {
+ ctk_dialog_open(&canceldialog);
+ ctk_window_redraw(&mainwindow);
+ } else if(w == (struct ctk_widget *)&cancelyesbutton) {
+ ctk_dialog_close();
+ ctk_redraw();
+ } else if(w == (struct ctk_widget *)&cancelnobutton) {
+ ctk_dialog_close();
+ ctk_redraw();
+ } else if(w == (struct ctk_widget *)&setupokbutton) {
+ applyconfig();
+ ctk_window_close(&setupwindow);
+ ctk_window_open(&mainwindow);
+ ctk_redraw();
+ } else {
+ for(i = 0; i < MAXNUMMSGS; ++i) {
+ if(w == (struct ctk_widget *)&msgbuttons[i]) {
+ ctk_window_close(&mainwindow);
+ make_window();
+ /* make_read(); download(i); */
+ ctk_window_open(&mainwindow);
+ ctk_window_redraw(&mainwindow);
+ break;
+ }
+ }
+ }
+ } else if(s == ctk_signal_menu_activate) {
+ if((struct ctk_menu *)data == &menu) {
+ if(menu.active == menuitem_open) {
+ ctk_window_open(&mainwindow);
+ } else if(menu.active == menuitem_setup) {
+ ctk_window_open(&setupwindow);
+ }
+ ctk_redraw();
+ }
+
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+smtp_done(unsigned char error)
+{
+ ctk_label_set_text(&statuslabel, "SMTP done");
+ ctk_redraw();
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/email.h b/contiki/apps/email.h
new file mode 100644
index 0000000..09a1ca4
--- /dev/null
+++ b/contiki/apps/email.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: email.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __EMAIL_H__
+#define __EMAIL_H__
+
+void email_init(void);
+
+#endif /* __EMAIL_H__ */
diff --git a/contiki/apps/html-strings b/contiki/apps/html-strings
new file mode 100644
index 0000000..e3c43c9
--- /dev/null
+++ b/contiki/apps/html-strings
@@ -0,0 +1,36 @@
+html_slasha "/a\0"
+html_slashcenter "/center\0"
+html_slashform "/form\0"
+html_slashh "/h\0"
+html_slashscript "/script\0"
+html_slashselect "/select\0"
+html_slashstyle "/style\0"
+html_a "a\0"
+html_body "body\0"
+html_br "br\0"
+html_center "center\0"
+html_form "form\0"
+html_frame "frame\0"
+html_h1 "h1\0"
+html_h2 "h2\0"
+html_h3 "h3\0"
+html_h4 "h4\0"
+html_img "img\0"
+html_input "input\0"
+html_li "li\0"
+html_p "p\0"
+html_script "script\0"
+html_select "select\0"
+html_style "style\0"
+html_tr "tr\0"
+html_href "href\0"
+html_alt "alt\0"
+html_src "src\0"
+html_type "type\0"
+html_submit "submit\0"
+html_value "value\0"
+html_action "action\0"
+html_name "name\0"
+html_text "text\0"
+html_size "size\0"
+html_image "image\0"
\ No newline at end of file
diff --git a/contiki/apps/html-strings.c b/contiki/apps/html-strings.c
new file mode 100644
index 0000000..968f857
--- /dev/null
+++ b/contiki/apps/html-strings.c
@@ -0,0 +1,108 @@
+char html_slasha[4] =
+/* "/a\0" */
+{0x2f, 0x61, 00, };
+char html_slashcenter[9] =
+/* "/center\0" */
+{0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 00, };
+char html_slashform[7] =
+/* "/form\0" */
+{0x2f, 0x66, 0x6f, 0x72, 0x6d, 00, };
+char html_slashh[4] =
+/* "/h\0" */
+{0x2f, 0x68, 00, };
+char html_slashscript[9] =
+/* "/script\0" */
+{0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 00, };
+char html_slashselect[9] =
+/* "/select\0" */
+{0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 00, };
+char html_slashstyle[8] =
+/* "/style\0" */
+{0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 00, };
+char html_a[3] =
+/* "a\0" */
+{0x61, 00, };
+char html_body[6] =
+/* "body\0" */
+{0x62, 0x6f, 0x64, 0x79, 00, };
+char html_br[4] =
+/* "br\0" */
+{0x62, 0x72, 00, };
+char html_center[8] =
+/* "center\0" */
+{0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 00, };
+char html_form[6] =
+/* "form\0" */
+{0x66, 0x6f, 0x72, 0x6d, 00, };
+char html_frame[7] =
+/* "frame\0" */
+{0x66, 0x72, 0x61, 0x6d, 0x65, 00, };
+char html_h1[4] =
+/* "h1\0" */
+{0x68, 0x31, 00, };
+char html_h2[4] =
+/* "h2\0" */
+{0x68, 0x32, 00, };
+char html_h3[4] =
+/* "h3\0" */
+{0x68, 0x33, 00, };
+char html_h4[4] =
+/* "h4\0" */
+{0x68, 0x34, 00, };
+char html_img[5] =
+/* "img\0" */
+{0x69, 0x6d, 0x67, 00, };
+char html_input[7] =
+/* "input\0" */
+{0x69, 0x6e, 0x70, 0x75, 0x74, 00, };
+char html_li[4] =
+/* "li\0" */
+{0x6c, 0x69, 00, };
+char html_p[3] =
+/* "p\0" */
+{0x70, 00, };
+char html_script[8] =
+/* "script\0" */
+{0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 00, };
+char html_select[8] =
+/* "select\0" */
+{0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 00, };
+char html_style[7] =
+/* "style\0" */
+{0x73, 0x74, 0x79, 0x6c, 0x65, 00, };
+char html_tr[4] =
+/* "tr\0" */
+{0x74, 0x72, 00, };
+char html_href[6] =
+/* "href\0" */
+{0x68, 0x72, 0x65, 0x66, 00, };
+char html_alt[5] =
+/* "alt\0" */
+{0x61, 0x6c, 0x74, 00, };
+char html_src[5] =
+/* "src\0" */
+{0x73, 0x72, 0x63, 00, };
+char html_type[6] =
+/* "type\0" */
+{0x74, 0x79, 0x70, 0x65, 00, };
+char html_submit[8] =
+/* "submit\0" */
+{0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 00, };
+char html_value[7] =
+/* "value\0" */
+{0x76, 0x61, 0x6c, 0x75, 0x65, 00, };
+char html_action[8] =
+/* "action\0" */
+{0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 00, };
+char html_name[6] =
+/* "name\0" */
+{0x6e, 0x61, 0x6d, 0x65, 00, };
+char html_text[6] =
+/* "text\0" */
+{0x74, 0x65, 0x78, 0x74, 00, };
+char html_size[6] =
+/* "size\0" */
+{0x73, 0x69, 0x7a, 0x65, 00, };
+char html_image[7] =
+/* "image\0" */
+{0x69, 0x6d, 0x61, 0x67, 0x65, 00, };
diff --git a/contiki/apps/html-strings.h b/contiki/apps/html-strings.h
new file mode 100644
index 0000000..7c926f2
--- /dev/null
+++ b/contiki/apps/html-strings.h
@@ -0,0 +1,36 @@
+extern char html_slasha[4];
+extern char html_slashcenter[9];
+extern char html_slashform[7];
+extern char html_slashh[4];
+extern char html_slashscript[9];
+extern char html_slashselect[9];
+extern char html_slashstyle[8];
+extern char html_a[3];
+extern char html_body[6];
+extern char html_br[4];
+extern char html_center[8];
+extern char html_form[6];
+extern char html_frame[7];
+extern char html_h1[4];
+extern char html_h2[4];
+extern char html_h3[4];
+extern char html_h4[4];
+extern char html_img[5];
+extern char html_input[7];
+extern char html_li[4];
+extern char html_p[3];
+extern char html_script[8];
+extern char html_select[8];
+extern char html_style[7];
+extern char html_tr[4];
+extern char html_href[6];
+extern char html_alt[5];
+extern char html_src[5];
+extern char html_type[6];
+extern char html_submit[8];
+extern char html_value[7];
+extern char html_action[8];
+extern char html_name[6];
+extern char html_text[6];
+extern char html_size[6];
+extern char html_image[7];
diff --git a/contiki/apps/htmlparser.c b/contiki/apps/htmlparser.c
new file mode 100644
index 0000000..1ee41d1
--- /dev/null
+++ b/contiki/apps/htmlparser.c
@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: htmlparser.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+/* htmlparser.c:
+ *
+ * Implements a very simplistic HTML parser. It recognizes HTML links
+ * (<a href>-tags), HTML img alt tags, a few text flow break tags
+G * (<br>, <p>, <h>), the <li> tag (but does not even try to
+ * distinguish between <ol> or <ul>) as well as HTML comment tags
+ * (<!-- -->).
+ *
+ * To save memory, the HTML parser is state machine driver, which
+ * means that it will shave off one character from the HTML page,
+ * process that character, and return to the next. Another way of
+ * doing it would be to buffer a number of characters and process them
+ * together.
+ *
+ * The main function in this file is the htmlparser_parse() function
+ * which takes a htmlparser_state structur and a part of an HTML file
+ * as an argument. The htmlparser_parse() function will call the
+ * helper functions parse_char() and parse_tag(). Those functions will
+ * in turn call the two callback functions htmlparser_char() and
+ * htmlparser_tag(). Those functions must be implemented by the using
+ * module (e.g., a web browser program).
+ *
+ * htmlparser_char() will be called for every non-tag character.
+ *
+ * htmlparser_tag() will be called whenever a full tag has been found.
+ *
+ */
+
+
+#include "htmlparser.h"
+#include "html-strings.h"
+#include "www-conf.h"
+
+#if 1
+#define PRINTF(x)
+#else
+#include <stdio.h>
+#define PRINTF(x) printf x
+#endif
+
+#ifdef WITH_CC65
+#define FASTCALL __fastcall__
+#else
+#define FASTCALL
+#endif
+
+/*-----------------------------------------------------------------------------------*/
+#define ISO_A 0x41
+#define ISO_B 0x42
+#define ISO_E 0x45
+#define ISO_F 0x46
+#define ISO_G 0x47
+#define ISO_H 0x48
+#define ISO_I 0x49
+#define ISO_L 0x4c
+#define ISO_M 0x4d
+#define ISO_P 0x50
+#define ISO_R 0x52
+#define ISO_T 0x54
+
+#define ISO_a (ISO_A | 0x20)
+#define ISO_b (ISO_B | 0x20)
+#define ISO_e (ISO_E | 0x20)
+#define ISO_f (ISO_F | 0x20)
+#define ISO_g (ISO_G | 0x20)
+#define ISO_h (ISO_H | 0x20)
+#define ISO_i (ISO_I | 0x20)
+#define ISO_l (ISO_L | 0x20)
+#define ISO_m (ISO_M | 0x20)
+#define ISO_p (ISO_P | 0x20)
+#define ISO_r (ISO_R | 0x20)
+#define ISO_t (ISO_T | 0x20)
+
+#define ISO_ht 0x09
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+#define ISO_space 0x20
+#define ISO_bang 0x21
+#define ISO_citation 0x22
+#define ISO_ampersand 0x26
+#define ISO_citation2 0x27
+#define ISO_asterisk 0x2a
+#define ISO_dash 0x2d
+#define ISO_slash 0x2f
+#define ISO_semicolon 0x3b
+#define ISO_lt 0x3c
+#define ISO_eq 0x3d
+#define ISO_gt 0x3e
+
+#define ISO_rbrack 0x5b
+#define ISO_lbrack 0x5d
+
+#define MINORSTATE_NONE 0
+#define MINORSTATE_TEXT 1 /* Parse normal text */
+#define MINORSTATE_EXTCHAR 2 /* Check for semi-colon */
+#define MINORSTATE_TAG 3 /* Check for name of tag. */
+#define MINORSTATE_TAGEND 4 /* Scan for end of tag. */
+#define MINORSTATE_TAGATTR 5 /* Parse tag attr. */
+#define MINORSTATE_TAGATTRSPACE 6 /* Parse optional space after tag
+ attr. */
+#define MINORSTATE_TAGATTRPARAM 7 /* Parse tag attr parameter. */
+#define MINORSTATE_TAGATTRPARAMNQ 8 /* Parse tag attr parameter without
+ quotation marks. */
+#define MINORSTATE_HTMLCOMMENT 9 /* Scan for HTML comment end */
+
+#define MAJORSTATE_NONE 0
+#define MAJORSTATE_BODY 1
+#define MAJORSTATE_LINK 2
+#define MAJORSTATE_FORM 3
+#define MAJORSTATE_DISCARD 4
+
+
+struct htmlparser_state {
+ unsigned char minorstate;
+ char tag[20];
+ unsigned char tagptr;
+ char tagattr[20];
+ unsigned char tagattrptr;
+ char tagattrparam[WWW_CONF_MAX_URLLEN];
+ unsigned char tagattrparamptr;
+ unsigned char lastchar, quotechar;
+ unsigned char majorstate, lastmajorstate;
+ char linkurl[WWW_CONF_MAX_URLLEN];
+ char linktext[40];
+ unsigned char linktextptr;
+#if WWW_CONF_FORMS
+ char formaction[WWW_CONF_MAX_FORMACTIONLEN];
+ char formname[WWW_CONF_MAX_FORMNAMELEN];
+ unsigned char inputtype;
+ char inputname[WWW_CONF_MAX_INPUTNAMELEN];
+ char inputvalue[WWW_CONF_MAX_INPUTVALUELEN];
+ unsigned char inputvaluesize;
+#endif /* WWW_CONF_FORMS */
+};
+
+static struct htmlparser_state s;
+
+/*-----------------------------------------------------------------------------------*/
+static char last[1] = {0xff};
+
+static char *tags[] = {
+#define TAG_FIRST 0
+#define TAG_SLASHA 0
+ html_slasha,
+#define TAG_SLASHCENTER 1
+ html_slashcenter,
+#define TAG_SLASHFORM 2
+ html_slashform,
+#define TAG_SLASHH 3
+ html_slashh,
+#define TAG_SLASHSCRIPT 4
+ html_slashscript,
+#define TAG_SLASHSELECT 5
+ html_slashselect,
+#define TAG_SLASHSTYLE 6
+ html_slashstyle,
+#define TAG_A 7
+ html_a,
+#define TAG_BODY 8
+ html_body,
+#define TAG_BR 9
+ html_br,
+#define TAG_CENTER 10
+ html_center,
+#define TAG_FORM 11
+ html_form,
+#define TAG_FRAME 12
+ html_frame,
+#define TAG_H1 13
+ html_h1,
+#define TAG_H2 14
+ html_h2,
+#define TAG_H3 15
+ html_h3,
+#define TAG_H4 16
+ html_h4,
+#define TAG_IMG 17
+ html_img,
+#define TAG_INPUT 18
+ html_input,
+#define TAG_LI 19
+ html_li,
+#define TAG_P 20
+ html_p,
+#define TAG_SCRIPT 21
+ html_script,
+#define TAG_SELECT 22
+ html_select,
+#define TAG_STYLE 23
+ html_style,
+#define TAG_TR 24
+ html_tr,
+#define TAG_LAST 25
+ last,
+};
+
+/*-----------------------------------------------------------------------------------*/
+static unsigned char FASTCALL
+iswhitespace(char c)
+{
+ return (c == ISO_space ||
+ c == ISO_nl ||
+ c == ISO_cr ||
+ c == ISO_ht);
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char FASTCALL
+find_tag(char *tag)
+{
+ static unsigned char first, last, i, tabi;
+ static char tagc;
+
+ tabi = first = TAG_FIRST;
+ last = TAG_LAST;
+ i = 0;
+
+ do {
+ tagc = tag[i];
+
+ if(tagc == 0 &&
+ tags[first][i] == 0) {
+ return first;
+ }
+
+ /* First, find first matching tag from table. */
+ while(tagc > (tags[tabi])[i] &&
+ tabi < last) {
+ ++tabi;
+ }
+ first = tabi;
+
+ /* Second, find last matching tag from table. */
+ while(tagc == (tags[tabi])[i] &&
+ tabi < last) {
+ ++tabi;
+ }
+ last = tabi;
+
+ /* If first and last matching tags are equal, we have a match and
+ return. Else we continue with the next character. */
+ ++i;
+ tabi = first;
+ } while(last != first);
+ return TAG_LAST;
+}
+/*-----------------------------------------------------------------------------------*/
+static void FASTCALL
+parse_char(unsigned char c)
+{
+ if(c < 0x80) {
+ if(s.majorstate == MAJORSTATE_LINK) {
+ if(s.linktextptr < sizeof(s.linktext)) {
+ if(iswhitespace(c)) {
+ c = ISO_space;
+ }
+ s.linktext[s.linktextptr] = c;
+ ++s.linktextptr;
+ }
+ } else if(s.majorstate != MAJORSTATE_DISCARD) {
+ htmlparser_char(c);
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+switch_majorstate(unsigned char newstate)
+{
+ if(s.majorstate != newstate) {
+ PRINTF(("Switching state from %d to %d (%d)\n", s.majorstate, newstate, s.lastmajorstate));
+ s.lastmajorstate = s.majorstate;
+ s.majorstate = newstate;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+parse_tag(void)
+{
+ static char *tagattrparam;
+ static unsigned char size, i;
+
+ PRINTF(("Parsing tag '%s' '%s' '%s'\n",
+ s.tag, s.tagattr, s.tagattrparam));
+
+ switch(find_tag(s.tag)) {
+ case TAG_P:
+ case TAG_H1:
+ case TAG_H2:
+ case TAG_H3:
+ case TAG_H4:
+ parse_char(ISO_nl);
+ /* FALLTHROUGH */
+ case TAG_BR:
+ case TAG_TR:
+ case TAG_SLASHH:
+ parse_char(ISO_nl);
+ break;
+ case TAG_LI:
+ parse_char(ISO_nl);
+ parse_char(ISO_asterisk);
+ parse_char(ISO_space);
+ break;
+ case TAG_SCRIPT:
+ case TAG_STYLE:
+ case TAG_SELECT:
+ switch_majorstate(MAJORSTATE_DISCARD);
+ break;
+ case TAG_SLASHSCRIPT:
+ case TAG_SLASHSTYLE:
+ case TAG_SLASHSELECT:
+ switch_majorstate(s.lastmajorstate);
+ break;
+ case TAG_BODY:
+ s.majorstate = s.lastmajorstate = MAJORSTATE_BODY;
+ break;
+ case TAG_FRAME:
+ if(strncmp(s.tagattr, html_src, sizeof(html_src)) == 0 &&
+ s.tagattrparam[0] != 0) {
+ switch_majorstate(MAJORSTATE_BODY);
+ parse_char(ISO_nl);
+ parse_char(ISO_rbrack);
+ parse_char(ISO_space);
+ htmlparser_link(html_frame, s.tagattrparam);
+ PRINTF(("Frame [%s]\n", s.tagattrparam));
+ parse_char(ISO_space);
+ parse_char(ISO_lbrack);
+ parse_char(ISO_nl);
+ }
+ break;
+ case TAG_IMG:
+ if(strncmp(s.tagattr, html_alt, sizeof(html_alt)) == 0 &&
+ s.tagattrparam[0] != 0) {
+ parse_char(ISO_lt);
+ tagattrparam = &s.tagattrparam[0];
+ while(*tagattrparam) {
+ parse_char(*tagattrparam);
+ ++tagattrparam;
+ }
+ parse_char(ISO_gt);
+ }
+ break;
+ case TAG_A:
+ PRINTF(("A %s %s\n", s.tagattr, s.tagattrparam));
+ if(strncmp(s.tagattr, html_href, sizeof(html_href)) == 0 &&
+ s.tagattrparam[0] != 0) {
+ strcpy(s.linkurl, s.tagattrparam);
+ switch_majorstate(MAJORSTATE_LINK);
+ s.linktextptr = 0;
+ }
+ break;
+ case TAG_SLASHA:
+ if(s.majorstate == MAJORSTATE_LINK) {
+ switch_majorstate(s.lastmajorstate);
+ s.linktext[s.linktextptr] = 0;
+ htmlparser_link(s.linktext, s.linkurl);
+ PRINTF(("Link '%s' [%s]\n", s.linktext, s.linkurl));
+ }
+ break;
+#if WWW_CONF_FORMS
+ case TAG_FORM:
+ PRINTF(("Form tag\n"));
+ switch_majorstate(MAJORSTATE_FORM);
+ if(strncmp(s.tagattr, html_action, sizeof(html_action)) == 0) {
+ PRINTF(("Form action '%s'\n", s.tagattrparam));
+ strncpy(s.formaction, s.tagattrparam, WWW_CONF_MAX_FORMACTIONLEN - 1);
+ } else if(strncmp(s.tagattr, html_name, sizeof(html_name)) == 0) {
+ PRINTF(("Form name '%s'\n", s.tagattrparam));
+ strncpy(s.formname, s.tagattrparam, WWW_CONF_MAX_FORMNAMELEN - 1);
+ }
+ s.inputname[0] = s.inputvalue[0] = 0;
+ break;
+ case TAG_SLASHFORM:
+ switch_majorstate(MAJORSTATE_BODY);
+ s.formaction[0] = s.formname[0] = 0;
+ break;
+ case TAG_INPUT:
+ if(s.majorstate == MAJORSTATE_FORM) {
+ /* First check if we are called at the end of an input tag. If
+ so, we should render the input widget. */
+ if(s.tagattr[0] == 0 &&
+ s.inputname[0] != 0) {
+ PRINTF(("Render input type %d\n", s.inputtype));
+ switch(s.inputtype) {
+ case HTMLPARSER_INPUTTYPE_NONE:
+ case HTMLPARSER_INPUTTYPE_TEXT:
+ for(i = 0; i < s.inputvaluesize; ++i) {
+ if(s.inputvalue[i] == 0) {
+ memset(&s.inputvalue[i], ISO_space, s.inputvaluesize - i);
+ s.inputvalue[s.inputvaluesize] = 0;
+ break;
+ }
+ }
+ htmlparser_inputfield(s.inputvalue, s.inputname,
+ s.formname, s.formaction);
+ break;
+ case HTMLPARSER_INPUTTYPE_SUBMIT:
+ case HTMLPARSER_INPUTTYPE_IMAGE:
+ htmlparser_submitbutton(s.inputvalue, s.inputname,
+ s.formname, s.formaction);
+ break;
+ }
+ s.inputtype = HTMLPARSER_INPUTTYPE_NONE;
+ } else {
+ PRINTF(("Input '%s' '%s'\n", s.tagattr, s.tagattrparam));
+ if(strncmp(s.tagattr, html_type, sizeof(html_type)) == 0) {
+ if(strncmp(s.tagattrparam, html_submit,
+ sizeof(html_submit)) == 0) {
+ s.inputtype = HTMLPARSER_INPUTTYPE_SUBMIT;
+ } else if(strncmp(s.tagattrparam, html_image,
+ sizeof(html_image)) == 0) {
+ s.inputtype = HTMLPARSER_INPUTTYPE_IMAGE;
+ } else if(strncmp(s.tagattrparam, html_text,
+ sizeof(html_text)) == 0) {
+ s.inputtype = HTMLPARSER_INPUTTYPE_TEXT;
+ } else {
+ s.inputtype = HTMLPARSER_INPUTTYPE_OTHER;
+ }
+ } else if(strncmp(s.tagattr, html_name,
+ sizeof(html_name)) == 0) {
+ strncpy(s.inputname, s.tagattrparam,
+ WWW_CONF_MAX_INPUTNAMELEN);
+ } else if(strncmp(s.tagattr, html_alt,
+ sizeof(html_alt)) == 0 &&
+ s.inputtype == HTMLPARSER_INPUTTYPE_IMAGE) {
+ strncpy(s.inputvalue, s.tagattrparam,
+ WWW_CONF_MAX_INPUTVALUELEN);
+ } else if(strncmp(s.tagattr, html_value,
+ sizeof(html_value)) == 0) {
+ strncpy(s.inputvalue, s.tagattrparam,
+ WWW_CONF_MAX_INPUTVALUELEN);
+ } else if(strncmp(s.tagattr, html_size,
+ sizeof(html_size)) == 0) {
+ size = 0;
+ if(s.tagattrparam[0] >= '0' &&
+ s.tagattrparam[0] <= '9') {
+ size = s.tagattrparam[0] - '0';
+ if(s.tagattrparam[1] >= '0' &&
+ s.tagattrparam[1] <= '9') {
+ size = size * 10 + (s.tagattrparam[1] - '0');
+ }
+ }
+ if(size >= WWW_CONF_MAX_INPUTVALUELEN) {
+ size = WWW_CONF_MAX_INPUTVALUELEN - 1;
+ }
+ s.inputvaluesize = size;
+ /* strncpy(s.inputvalue, s.tagattrparam,
+ WWW_CONF_MAX_INPUTVALUELEN);*/
+ }
+ }
+
+ }
+ break;
+#endif /* WWW_CONF_FORMS */
+#if WWW_CONF_RENDERSTATE
+ case TAG_CENTER:
+ parse_char(ISO_nl);
+ htmlparser_renderstate(HTMLPARSER_RENDERSTATE_BEGIN |
+ HTMLPARSER_RENDERSTATE_CENTER);
+ break;
+ case TAG_SLASHCENTER:
+ parse_char(ISO_nl);
+ htmlparser_renderstate(HTMLPARSER_RENDERSTATE_END |
+ HTMLPARSER_RENDERSTATE_CENTER);
+ break;
+#endif /* WWW_CONF_RENDERSTATE */
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_init(void)
+{
+ s.majorstate = s.lastmajorstate = MAJORSTATE_DISCARD;
+ s.minorstate = MINORSTATE_TEXT;
+ s.lastchar = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static char FASTCALL
+lowercase(char c)
+{
+ /* XXX: This is a *brute force* approach to lower-case
+ converting and should *not* be used anywhere else! It
+ works for our purposes, however (i.e., HTML tags). */
+ if(c > 0x40) {
+ return (c & 0x1f) | 0x60;
+ } else {
+ return c;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+endtagfound(void)
+{
+ s.tag[s.tagptr] = 0;
+ s.tagattr[s.tagattrptr] = 0;
+ s.tagattrparam[s.tagattrparamptr] = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/* htmlparser_parse():
+ *
+ * This is the main function in the HTML parser module and it parses
+ * the HTML data in the input buffer. The htmlparser_state is updated
+ * as the buffer is parsed character by character. The functions
+ * parse_char() and parse_tag() (defined earlier in this file) are
+ * called to process regular characters and HTML tags,
+ * respectively.
+ *
+ * Note that the input buffer does not have to contain full HTML tags;
+ * the parser is state machine driven in order to be able to work with
+ * buffers that have been divided in any way.
+ */
+void
+htmlparser_parse(char *data, u16_t len)
+{
+ static char c;
+
+ while(len > 0) {
+ c = *data;
+ --len;
+ ++data;
+
+ switch(s.minorstate) {
+ case MINORSTATE_NONE:
+ break;
+ case MINORSTATE_TEXT:
+ /* We are currently parsing some text, so we look for signs of
+ an HTML tag starting (i.e., a '<' character). We also
+ compress any whitespace character to one single space
+ character (' '). */
+ if(c == ISO_lt) {
+ s.minorstate = MINORSTATE_TAG;
+ s.tagptr = 0;
+ endtagfound();
+ } else if(c == ISO_ampersand) {
+ s.minorstate = MINORSTATE_EXTCHAR;
+ } else {
+ if(iswhitespace(c)) {
+ if(s.lastchar != ISO_space) {
+ parse_char(' ');
+ s.lastchar = ISO_space;
+ c = ISO_space;
+ }
+ } else {
+ parse_char(c);
+ }
+ }
+ break;
+ case MINORSTATE_EXTCHAR:
+ if(c == ISO_semicolon) {
+ s.minorstate = MINORSTATE_TEXT;
+ parse_char(' ');
+ } else if(iswhitespace(c)) {
+ s.minorstate = MINORSTATE_TEXT;
+ parse_char('&');
+ parse_char(' ');
+ }
+ break;
+ case MINORSTATE_TAG:
+ /* We are currently parsing within the name of a tag. We check
+ for the end of a tag (the '>' character) or whitespace (which
+ indicates that we should parse a tag attr argument
+ instead). */
+ if(c == ISO_gt) {
+ /* Full tag found. We continue parsing regular text. */
+ s.minorstate = MINORSTATE_TEXT;
+ s.tagattrptr = s.tagattrparamptr = 0;
+ endtagfound();
+ parse_tag();
+ } else if(iswhitespace(c)) {
+ /* The name of the tag found. We continue parsing the tag
+ attr.*/
+ s.minorstate = MINORSTATE_TAGATTR;
+ s.tagattrptr = 0;
+ endtagfound();
+ } else {
+ /* Keep track of the name of the tag, but convert it to
+ lower case. */
+
+ s.tag[s.tagptr] = lowercase(c);
+ ++s.tagptr;
+ /* Check if the ->tag field is full. If so, we just eat up
+ any data left in the tag. */
+ if(s.tagptr == sizeof(s.tag)) {
+ s.minorstate = MINORSTATE_TAGEND;
+ }
+ }
+
+ /* Check for HTML comment, indicated by <!-- */
+ if(s.tagptr == 3 &&
+ s.tag[0] == ISO_bang &&
+ s.tag[1] == ISO_dash &&
+ s.tag[2] == ISO_dash) {
+ PRINTF(("Starting comment...\n"));
+ s.minorstate = MINORSTATE_HTMLCOMMENT;
+ s.tagptr = 0;
+ endtagfound();
+ }
+ break;
+ case MINORSTATE_TAGATTR:
+ /* We parse the "tag attr", i.e., the "href" in <a
+ href="...">. */
+ if(c == ISO_gt) {
+ /* Full tag found. */
+ s.minorstate = MINORSTATE_TEXT;
+ s.tagattrparamptr = 0;
+ s.tagattrptr = 0;
+ endtagfound();
+ parse_tag();
+ s.tagptr = 0;
+ endtagfound();
+
+ } else if(iswhitespace(c)) {
+ if(s.tagattrptr == 0) {
+ /* Discard leading spaces. */
+ } else {
+ /* A non-leading space is the end of the attribute. */
+ s.tagattrparamptr = 0;
+ endtagfound();
+ parse_tag();
+ s.minorstate = MINORSTATE_TAGATTRSPACE;
+ /* s.tagattrptr = 0;
+ endtagfound();*/
+ }
+ } else if(c == ISO_eq) {
+ s.minorstate = MINORSTATE_TAGATTRPARAMNQ;
+ s.tagattrparamptr = 0;
+ endtagfound();
+ } else {
+ s.tagattr[s.tagattrptr] = lowercase(c);
+ ++s.tagattrptr;
+ /* Check if the "tagattr" field is full. If so, we just eat
+ up any data left in the tag. */
+ if(s.tagattrptr == sizeof(s.tagattr)) {
+ s.minorstate = MINORSTATE_TAGEND;
+ }
+ }
+ break;
+ case MINORSTATE_TAGATTRSPACE:
+ if(iswhitespace(c)) {
+ /* Discard spaces. */
+ } else if(c == ISO_eq) {
+ s.minorstate = MINORSTATE_TAGATTRPARAMNQ;
+ s.tagattrparamptr = 0;
+ endtagfound();
+ parse_tag();
+ } else {
+ s.tagattr[0] = lowercase(c);
+ s.tagattrptr = 1;
+ s.minorstate = MINORSTATE_TAGATTR;
+ }
+ break;
+ case MINORSTATE_TAGATTRPARAMNQ:
+ /* We are parsing the "tag attr parameter", i.e., the link part
+ in <a href="link">. */
+ if(c == ISO_gt) {
+ /* Full tag found. */
+ endtagfound();
+ parse_tag();
+ s.minorstate = MINORSTATE_TEXT;
+ s.tagattrptr = 0;
+ endtagfound();
+ parse_tag();
+ s.tagptr = 0;
+ endtagfound();
+ } else if(iswhitespace(c) &&
+ s.tagattrparamptr == 0) {
+ /* Discard leading spaces. */
+ } else if((c == ISO_citation ||
+ c == ISO_citation2) &&
+ s.tagattrparamptr == 0) {
+ s.minorstate = MINORSTATE_TAGATTRPARAM;
+ s.quotechar = c;
+ PRINTF(("tag attr param q found\n"));
+ } else if(iswhitespace(c)) {
+ PRINTF(("Non-leading space found at %d\n",
+ s.tagattrparamptr));
+ /* Stop parsing if a non-leading space was found */
+ endtagfound();
+ parse_tag();
+
+ s.minorstate = MINORSTATE_TAGATTR;
+ s.tagattrptr = 0;
+ endtagfound();
+ } else {
+ s.tagattrparam[s.tagattrparamptr] = c;
+ ++s.tagattrparamptr;
+ /* Check if the "tagattr" field is full. If so, we just eat
+ up any data left in the tag. */
+ if(s.tagattrparamptr >= sizeof(s.tagattrparam) - 1) {
+ s.minorstate = MINORSTATE_TAGEND;
+ }
+ }
+
+ break;
+ case MINORSTATE_TAGATTRPARAM:
+ /* We are parsing the "tag attr parameter", i.e., the link
+ part in <a href="link">. */
+ if(c == s.quotechar) {
+ /* Found end of tag attr parameter. */
+ endtagfound();
+ parse_tag();
+
+ s.minorstate = MINORSTATE_TAGATTR;
+ s.tagattrptr = 0;
+ endtagfound();
+ } else {
+ if(iswhitespace(c)) {
+ c = ISO_space;
+ }
+ s.tagattrparam[s.tagattrparamptr] = c;
+ ++s.tagattrparamptr;
+ /* Check if the "tagattr" field is full. If so, we just eat
+ up any data left in the tag. */
+ if(s.tagattrparamptr >= sizeof(s.tagattrparam) - 1) {
+ s.minorstate = MINORSTATE_TAGEND;
+ }
+ }
+
+ break;
+ case MINORSTATE_HTMLCOMMENT:
+ if(c == ISO_dash) {
+ ++s.tagptr;
+ } else if(c == ISO_gt && s.tagptr > 0) {
+ PRINTF(("Comment done.\n"));
+ s.minorstate = MINORSTATE_TEXT;
+ } else {
+ s.tagptr = 0;
+ }
+ break;
+ case MINORSTATE_TAGEND:
+ /* Discard characters until a '>' is seen. */
+ if(c == ISO_gt) {
+ s.minorstate = MINORSTATE_TEXT;
+ s.tagattrptr = 0;
+ endtagfound();
+ parse_tag();
+ }
+ break;
+ }
+
+ s.lastchar = c;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/htmlparser.h b/contiki/apps/htmlparser.h
new file mode 100644
index 0000000..77ac035
--- /dev/null
+++ b/contiki/apps/htmlparser.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: htmlparser.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __HTMLPARSER_H__
+#define __HTMLPARSER_H__
+
+#include "uip.h"
+
+/* Callbacks. */
+void htmlparser_char(char c);
+void htmlparser_link(char *text, char *url);
+void htmlparser_submitbutton(char *value,
+ char *name,
+ char *formname,
+ char *formaction);
+void htmlparser_inputfield(char *value,
+ char *name,
+ char *formname,
+ char *formaction);
+
+
+void htmlparser_renderstate(unsigned char state);
+#define HTMLPARSER_RENDERSTATE_STATUSMASK 0x80
+#define HTMLPARSER_RENDERSTATE_BEGIN 0x00
+#define HTMLPARSER_RENDERSTATE_END 0x80
+
+#define HTMLPARSER_RENDERSTATE_NONE 0x00
+#define HTMLPARSER_RENDERSTATE_CENTER 0x01
+#define HTMLPARSER_RENDERSTATE_TABLE 0x02
+#define HTMLPARSER_RENDERSTATE_TR 0x04
+#define HTMLPARSER_RENDERSTATE_TD 0x08
+
+
+#define HTMLPARSER_INPUTTYPE_NONE 0
+#define HTMLPARSER_INPUTTYPE_TEXT 1
+#define HTMLPARSER_INPUTTYPE_PASSWORD 2
+#define HTMLPARSER_INPUTTYPE_SUBMIT 3
+#define HTMLPARSER_INPUTTYPE_IMAGE 4
+#define HTMLPARSER_INPUTTYPE_OTHER 5
+
+
+/* Functions. */
+void htmlparser_init(void);
+void htmlparser_parse(char *data, u16_t len);
+
+
+#endif /* __HTMLPARSER_H__ */
diff --git a/contiki/apps/http-strings b/contiki/apps/http-strings
new file mode 100644
index 0000000..df833e2
--- /dev/null
+++ b/contiki/apps/http-strings
@@ -0,0 +1,15 @@
+http_http "http://"
+http_200 "200 "
+http_301 "301 "
+http_302 "302 "
+http_get "GET "
+http_10 "HTTP/1.0"
+http_11 "HTTP/1.1"
+http_content_type "Content-Type: "
+http_texthtml "text/html"
+http_location "Location: "
+http_host "Host: "
+http_fields "Connection: close\r\nUser-Agent: Contiki/1.0 (Commodore 64; http://dunkels.com/adam/contiki/)\r\n\r\n"
+http_crnl "\r\n"
+http_webserver_d64_headers "HTTP/1.0 200 OK\r\nServer: Contiki/1.0\r\nContent-Type: application/octet-stream\r\nContent-Length: 174848\r\n\r\n"
+
diff --git a/contiki/apps/http-strings.c b/contiki/apps/http-strings.c
new file mode 100644
index 0000000..64c9018
--- /dev/null
+++ b/contiki/apps/http-strings.c
@@ -0,0 +1,42 @@
+char http_http[8] =
+/* "http://" */
+{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, };
+char http_200[5] =
+/* "200 " */
+{0x32, 0x30, 0x30, 0x20, };
+char http_301[5] =
+/* "301 " */
+{0x33, 0x30, 0x31, 0x20, };
+char http_302[5] =
+/* "302 " */
+{0x33, 0x30, 0x32, 0x20, };
+char http_get[5] =
+/* "GET " */
+{0x47, 0x45, 0x54, 0x20, };
+char http_10[9] =
+/* "HTTP/1.0" */
+{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, };
+char http_11[9] =
+/* "HTTP/1.1" */
+{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, };
+char http_content_type[15] =
+/* "Content-Type: " */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, };
+char http_texthtml[10] =
+/* "text/html" */
+{0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, };
+char http_location[11] =
+/* "Location: " */
+{0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, };
+char http_host[7] =
+/* "Host: " */
+{0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, };
+char http_fields[96] =
+/* "Connection: close\r\nUser-Agent: Contiki/1.0 (Commodore 64; http://dunkels.com/adam/contiki/)\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x28, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x64, 0x6f, 0x72, 0x65, 0x20, 0x36, 0x34, 0x3b, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x64, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0x29, 0xd, 0xa, 0xd, 0xa, };
+char http_crnl[3] =
+/* "\r\n" */
+{0xd, 0xa, };
+char http_webserver_d64_headers[105] =
+/* "HTTP/1.0 200 OK\r\nServer: Contiki/1.0\r\nContent-Type: application/octet-stream\r\nContent-Length: 174848\r\n\r\n" */
+{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0x31, 0x2e, 0x30, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x31, 0x37, 0x34, 0x38, 0x34, 0x38, 0xd, 0xa, 0xd, 0xa, };
diff --git a/contiki/apps/http-strings.h b/contiki/apps/http-strings.h
new file mode 100644
index 0000000..122ca49
--- /dev/null
+++ b/contiki/apps/http-strings.h
@@ -0,0 +1,14 @@
+extern char http_http[8];
+extern char http_200[5];
+extern char http_301[5];
+extern char http_302[5];
+extern char http_get[5];
+extern char http_10[9];
+extern char http_11[9];
+extern char http_content_type[15];
+extern char http_texthtml[10];
+extern char http_location[11];
+extern char http_host[7];
+extern char http_fields[96];
+extern char http_crnl[3];
+extern char http_webserver_d64_headers[105];
diff --git a/contiki/apps/makestrings b/contiki/apps/makestrings
new file mode 100755
index 0000000..e511bf3
--- /dev/null
+++ b/contiki/apps/makestrings
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+
+sub stringify {
+ my $name = shift(@_);
+ open(OUTPUTC, "> $name.c");
+ open(OUTPUTH, "> $name.h");
+
+ open(FILE, "$name");
+
+ while(<FILE>) {
+ if(/(.+) "(.+)"/) {
+ $var = $1;
+ $data = $2;
+
+ $datan = $data;
+ $datan =~ s/\\r/\r/g;
+ $datan =~ s/\\n/\n/g;
+ $datan =~ s/\\0/\0/g;
+
+ printf(OUTPUTC "char $var\[%d] = \n", length($datan) + 1);
+ printf(OUTPUTC "/* \"$data\" */\n");
+ printf(OUTPUTC "{");
+ for($j = 0; $j < length($datan); $j++) {
+ printf(OUTPUTC "%#02x, ", unpack("C", substr($datan, $j, 1)));
+ }
+ printf(OUTPUTC "};\n");
+
+ printf(OUTPUTH "extern char $var\[%d];\n", length($datan) + 1);
+
+ }
+ }
+ close(OUTPUTC);
+ close(OUTPUTH);
+}
+
+stringify("http-strings");
+stringify("smtp-strings");
+stringify("html-strings");
+
+exit 0;
+
diff --git a/contiki/apps/programs.c b/contiki/apps/programs.c
new file mode 100644
index 0000000..ae581d4
--- /dev/null
+++ b/contiki/apps/programs.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: programs.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+#include "ctk.h"
+#include "ek.h"
+#include "dispatcher.h"
+
+#include "webserver.h"
+#include "www.h"
+#include "email.h"
+#include "simpletelnet.h"
+
+
+static struct ctk_menu menu;
+
+static unsigned char menuitem_www,
+ menuitem_email, menuitem_telnet, menuitem_webserver;
+
+#if WITH_WWW
+/* The icon for the WWW browser */
+static unsigned char wwwicon_bitmap[3*3*8] = {
+ 0x00, 0x7e, 0x40, 0x73, 0x46, 0x4c, 0x18, 0x13,
+ 0x00, 0x00, 0xff, 0x81, 0x34, 0xc9, 0x00, 0xb6,
+ 0x00, 0x7e, 0x02, 0xce, 0x72, 0x32, 0x18, 0x48,
+
+ 0x30, 0x27, 0x24, 0x20, 0x37, 0x24, 0x20, 0x33,
+ 0x00, 0x7b, 0x42, 0x00, 0x7b, 0x42, 0x00, 0x3b,
+ 0x0c, 0x24, 0x24, 0x04, 0xa4, 0x24, 0x04, 0x4c,
+
+ 0x12, 0x19, 0x4c, 0x46, 0x63, 0x40, 0x7c, 0x00,
+ 0x22, 0x91, 0x00, 0xc4, 0x81, 0xff, 0x00, 0x00,
+ 0x08, 0x18, 0x32, 0x62, 0xc6, 0x02, 0x3e, 0x00
+};
+
+static char wwwicon_textmap[9] = {
+ 'w', 'w', 'w',
+ '(', ')', ' ',
+ ' ', '(', ')'
+};
+
+static struct ctk_icon wwwicon =
+ {CTK_ICON("Web browser", wwwicon_bitmap, wwwicon_textmap)};
+#endif /* WITH_WWW */
+
+#if WITH_WEBSERVER
+/* The icon for the web server */
+static unsigned char webservericon_bitmap[3*3*8] = {
+ 0x00, 0x7f, 0x40, 0x41, 0x44, 0x48, 0x40, 0x50,
+ 0x00, 0xff, 0x5a, 0x00, 0x00, 0x00, 0x3c, 0x81,
+ 0x00, 0xfe, 0x02, 0x82, 0x22, 0x12, 0x02, 0x0a,
+
+ 0x41, 0x60, 0x42, 0x62, 0x62, 0x42, 0x60, 0x41,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18,
+ 0x82, 0x06, 0x42, 0x46, 0x46, 0x42, 0x06, 0x82,
+
+ 0x50, 0x40, 0x48, 0x44, 0x41, 0x40, 0x7e, 0x00,
+ 0xc5, 0x34, 0x3c, 0x52, 0x7a, 0x7e, 0xa1, 0xfd,
+ 0x0a, 0x02, 0x12, 0x22, 0x82, 0x02, 0x7e, 0x00
+};
+
+static char webservericon_textmap[9] = {
+ '+', '-', '+',
+ '|', ')', '|',
+ '+', '-', '+'
+};
+
+static struct ctk_icon webservericon =
+ {CTK_ICON("Web server", webservericon_bitmap, webservericon_textmap)};
+#endif /* WITH_WEBSERVER */
+
+
+#if WITH_TELNET
+/* The icon for the telnet client */
+static unsigned char telneticon_bitmap[3*3*8] = {
+ 0x00, 0x7f, 0x43, 0x4c, 0x58, 0x53, 0x60, 0x6f,
+ 0x00, 0xff, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xfe, 0xc2, 0x32, 0x1a, 0xca, 0x06, 0xf6,
+
+ 0x40, 0x5f, 0x40, 0x5f, 0x40, 0x5f, 0x40, 0x4f,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xfc, 0x01, 0xf3,
+ 0x02, 0xfa, 0x02, 0x82, 0x3e, 0xfe, 0xfe, 0xfe,
+
+ 0x60, 0x67, 0x50, 0x59, 0x4c, 0x43, 0x7f, 0x00,
+ 0x07, 0xe7, 0x0f, 0xef, 0x0f, 0x0f, 0xff, 0x00,
+ 0x8e, 0x06, 0x06, 0x06, 0x8e, 0xfe, 0xfe, 0x00
+};
+
+static char telneticon_textmap[9] = {
+ 't', 'e', 'l',
+ 'n', 'e', 't',
+ '-', '-', '-'
+};
+
+static struct ctk_icon telneticon =
+ {CTK_ICON("Telnet client", telneticon_bitmap, telneticon_textmap)};
+#endif /* WITH_TELNET */
+
+
+static void sighandler(ek_signal_t s, ek_data_t data);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("Program handler", NULL, sighandler, NULL)};
+static ek_id_t id;
+
+/*-----------------------------------------------------------------------------------*/
+void
+programs_init(void)
+{
+ id = dispatcher_start(&p);
+
+ ctk_menu_new(&menu, "Programs");
+ ctk_menu_add(&menu);
+#ifdef WITH_WWW
+ menuitem_www = ctk_menuitem_add(&menu, "Web browser");
+#endif /* WITH_WWW */
+#ifdef WITH_EMAIL
+ menuitem_email = ctk_menuitem_add(&menu, "E-mail");
+#endif /* WITH_EMAIL */
+#ifdef WITH_WEBSERVER
+ menuitem_webserver = ctk_menuitem_add(&menu, "Web server");
+#endif /* WITH_WEBSERVER */
+#ifdef WITH_TELNET
+ menuitem_telnet = ctk_menuitem_add(&menu, "Telnet client");
+#endif /* WITH_TELNET */
+
+#ifdef WITH_WWW
+ CTK_ICON_ADD(&wwwicon, id);
+#endif /* WITH_WWW */
+#ifdef WITH_WEBSERVER
+ CTK_ICON_ADD(&webservericon, id);
+#endif /* WITH_WEBSERVER */
+#ifdef WITH_TELNET
+ CTK_ICON_ADD(&telneticon, id);
+#endif /* WITH_TELNET */
+
+ dispatcher_listen(ctk_signal_menu_activate);
+ dispatcher_listen(ctk_signal_button_activate);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sighandler(ek_signal_t s, ek_data_t data)
+{
+ if(s == ctk_signal_menu_activate) {
+ if((struct ctk_menu *)data == &menu) {
+ if(menu.active == menuitem_www) {
+#ifdef WITH_WWW
+ www_init();
+ ctk_redraw();
+#endif /* WITH_WWW */
+#ifdef WITH_EMAIL
+ } else if(menu.active == menuitem_email) {
+ email_init();
+ ctk_redraw();
+#endif /* WITH_EMAIL */
+#ifdef WITH_TELNET
+ } else if(menu.active == menuitem_telnet) {
+ simpletelnet_init();
+ ctk_redraw();
+#endif /* WITH_TELNET */
+#ifdef WITH_WEBSERVER
+ } else if(menu.active == menuitem_webserver) {
+ webserver_init();
+ ctk_redraw();
+#endif /* WITH_WEBSERVER */
+ }
+ }
+ } else if(s == ctk_signal_button_activate) {
+#ifdef WITH_WWW
+ if((struct ctk_widget *)data == (struct ctk_widget *)&wwwicon) {
+ www_init();
+ ctk_redraw();
+ }
+#endif /* WITH_WWW */
+#ifdef WITH_WEBSERVER
+ if((struct ctk_widget *)data ==
+ (struct ctk_widget *)&webservericon) {
+ webserver_init();
+ ctk_redraw();
+ }
+#endif /* WITH_WEBSERVER */
+#ifdef WITH_TELNET
+ if((struct ctk_widget *)data ==
+ (struct ctk_widget *)&telneticon) {
+ simpletelnet_init();
+ ctk_redraw();
+ }
+#endif /* WITH_TELNET */
+ }
+
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/programs.h b/contiki/apps/programs.h
new file mode 100644
index 0000000..86f8858
--- /dev/null
+++ b/contiki/apps/programs.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: programs.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __PROGRAMS_H__
+#define __PROGRAMS_H__
+
+void programs_init(void);
+
+#endif /* __PROGRAMS_H__ */
diff --git a/contiki/apps/simpletelnet.c b/contiki/apps/simpletelnet.c
new file mode 100644
index 0000000..17e12e9
--- /dev/null
+++ b/contiki/apps/simpletelnet.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: simpletelnet.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+#include "petsciiconv.h"
+#include "uip_main.h"
+#include "uip.h"
+#include "ctk.h"
+#include "dispatcher.h"
+#include "resolv.h"
+#include "telnet.h"
+#include "simpletelnet.h"
+
+/* Telnet window */
+static struct ctk_window telnetwindow;
+
+static struct ctk_label telnethostlabel =
+ {CTK_LABEL(1, 0, 4, 1, "Host")};
+static char telnethost[25];
+static struct ctk_textentry telnethosttextentry =
+ {CTK_TEXTENTRY(0, 1, 24, 1, telnethost, 24)};
+
+static struct ctk_label telnetportlabel =
+ {CTK_LABEL(31, 0, 4, 1, "Port")};
+static char telnetport[6];
+static struct ctk_textentry telnetporttextentry =
+ {CTK_TEXTENTRY(30, 1, 5, 1, telnetport, 5)};
+
+static struct ctk_button telnetconnectbutton =
+ {CTK_BUTTON(2, 3, 7, "Connect")};
+static struct ctk_button telnetdisconnectbutton =
+ {CTK_BUTTON(25, 3, 10, "Disconnect")};
+
+static char telnetline[31];
+static struct ctk_textentry telnetlinetextentry =
+ {CTK_TEXTENTRY(0, 5, 30, 1, telnetline, 30)};
+
+
+static struct ctk_button telnetsendbutton =
+ {CTK_BUTTON(32, 5, 4, "Send")};
+
+static struct ctk_label telnetstatus =
+ {CTK_LABEL(0, 19, 38, 1, "")};
+
+static struct ctk_separator telnetsep1 =
+ {CTK_SEPARATOR(0, 7, 38)};
+
+static struct ctk_separator telnetsep2 =
+ {CTK_SEPARATOR(0, 18, 38)};
+
+static char telnettext[38*10];
+static struct ctk_label telnettextarea =
+ {CTK_LABEL(0, 8, 38, 10, telnettext)};
+
+static struct telnet_state ts_appstate;
+
+#define ISO_NL 0x0a
+#define ISO_CR 0x0d
+
+static void sighandler(ek_signal_t s, ek_data_t data);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("Simple telnet", NULL, sighandler,
+ (void (*)(void *))telnet_app)};
+static ek_id_t id;
+
+/*-----------------------------------------------------------------------------------*/
+void
+simpletelnet_init(void)
+{
+ if(id == EK_ID_NONE) {
+ id = dispatcher_start(&p);
+
+ /* Create Telnet window. */
+ ctk_window_new(&telnetwindow, 38, 20, "Simple telnet");
+ ctk_window_move(&telnetwindow, 0, 1);
+
+ CTK_WIDGET_ADD(&telnetwindow, &telnethostlabel);
+ CTK_WIDGET_ADD(&telnetwindow, &telnetportlabel);
+ CTK_WIDGET_ADD(&telnetwindow, &telnethosttextentry);
+ CTK_WIDGET_ADD(&telnetwindow, &telnetporttextentry);
+ CTK_WIDGET_ADD(&telnetwindow, &telnetconnectbutton);
+ CTK_WIDGET_ADD(&telnetwindow, &telnetdisconnectbutton);
+ CTK_WIDGET_ADD(&telnetwindow, &telnetlinetextentry);
+ CTK_WIDGET_ADD(&telnetwindow, &telnetsendbutton);
+
+ CTK_WIDGET_ADD(&telnetwindow, &telnetsep1);
+ CTK_WIDGET_ADD(&telnetwindow, &telnettextarea);
+
+ CTK_WIDGET_ADD(&telnetwindow, &telnetsep2);
+ CTK_WIDGET_ADD(&telnetwindow, &telnetstatus);
+
+ CTK_WIDGET_FOCUS(&telnetwindow, &telnethosttextentry);
+
+ /* Attach as a listener to the CTK button press signal. */
+ dispatcher_listen(ctk_signal_button_activate);
+
+ dispatcher_listen(resolv_signal_found);
+ }
+
+ ctk_window_open(&telnetwindow);
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+scrollup(void)
+{
+ unsigned char i;
+ for(i = 1; i < 10; ++i) {
+ memcpy(&telnettext[(i - 1) * 38], &telnettext[i * 38], 38);
+ }
+ memset(&telnettext[9 * 38], 0, 38);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+add_text(char *text)
+{
+ unsigned char i;
+ unsigned int len;
+
+ len = strlen(text);
+
+ i = 0;
+ while(len > 0) {
+ if(*text == '\n') {
+ scrollup();
+ i = 0;
+ } else if(*text == '\r') {
+ i = 0;
+ } else {
+ telnettext[9 * 38 + i] = *text;
+ ++i;
+ if(i == 38) {
+ scrollup();
+ i = 0;
+ }
+ }
+ ++text;
+ --len;
+ }
+
+ /* if(strlen(text) > 37) {
+ memcpy(&telnettext[9 * 38], text, 37);
+ } else {
+ memcpy(&telnettext[9 * 38], text, strlen(text));
+ }
+ */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+show(char *text)
+{
+ add_text(text);
+ add_text("\n");
+ ctk_label_set_text(&telnetstatus, text);
+ ctk_window_redraw(&telnetwindow);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+connect(void)
+{
+ u16_t addr[2], *addrptr;
+ u16_t port;
+ char *cptr;
+ struct uip_conn *conn;
+
+ /* Find the first space character in host and put a zero there
+ to end the string. */
+ for(cptr = telnethost; *cptr != ' ' && *cptr != 0; ++cptr);
+ *cptr = 0;
+
+ addrptr = &addr[0];
+ if(uip_main_ipaddrconv(telnethost, (unsigned char *)addr) == 0) {
+ addrptr = resolv_lookup(telnethost);
+ if(addrptr == NULL) {
+ resolv_query(telnethost);
+ show("Resolving host...");
+ return;
+ }
+ }
+
+ port = 0;
+ for(cptr = telnetport; *cptr != ' ' && *cptr != 0; ++cptr) {
+ if(*cptr < '0' || *cptr > '9') {
+ show("Port number error");
+ return;
+ }
+ port = 10 * port + *cptr - '0';
+ }
+
+
+ conn = uip_connect(addrptr, port);
+ if(conn == NULL) {
+ show("Out of memory error");
+ return;
+ }
+
+ dispatcher_markconn(conn, &ts_appstate);
+
+ show("Connecting...");
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sighandler(ek_signal_t s, ek_data_t data)
+{
+ struct ctk_widget *w;
+ char *ptr;
+
+ if(s == ctk_signal_button_activate) {
+
+ w = (struct ctk_widget *)data;
+ if(w == (struct ctk_widget *)&telnetsendbutton) {
+ petsciiconv_toascii(telnetline, sizeof(telnetline));
+ ptr = telnetline + strlen(telnetline);
+ *ptr++ = ISO_CR;
+ *ptr++ = ISO_NL;
+ if(telnet_send(&ts_appstate, telnetline, ptr - telnetline)) {
+ /* Could not send. */
+ ctk_label_set_text(&telnetstatus, "Could not send");
+ ctk_window_redraw(&telnetwindow);
+ /* } else {*/
+ /* Could send */
+ }
+ } else if(w == (struct ctk_widget *)&telnetdisconnectbutton) {
+ telnet_close(&ts_appstate);
+ show("Closing...");
+ } else if(w == (struct ctk_widget *)&telnetconnectbutton) {
+ connect();
+ ctk_window_redraw(&telnetwindow);
+ }
+ } else if(s == resolv_signal_found) {
+ if(strcmp(data, telnethost) == 0) {
+ if(resolv_lookup(telnethost) != NULL) {
+ connect();
+ } else {
+ show("Host not found");
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+telnet_connected(struct telnet_state *s)
+{
+ show("Connected");
+}
+void
+telnet_closed(struct telnet_state *s)
+{
+ show("Connection closed");
+}
+void
+telnet_sent(struct telnet_state *s)
+{
+ petsciiconv_topetscii(telnetline, sizeof(telnetline));
+ add_text(telnetline);
+ memset(telnetline, 0, sizeof(telnetline));
+ ctk_window_redraw(&telnetwindow);
+}
+void
+telnet_aborted(struct telnet_state *s)
+{
+ show("Connection reset by peer");
+}
+void
+telnet_timedout(struct telnet_state *s)
+{
+ show("Connection timed out");
+}
+void
+telnet_newdata(struct telnet_state *s, char *data, u16_t len)
+{
+ petsciiconv_topetscii(data, len);
+ data[len] = 0;
+ add_text(data);
+ ctk_window_redraw(&telnetwindow);
+}
diff --git a/contiki/apps/simpletelnet.h b/contiki/apps/simpletelnet.h
new file mode 100644
index 0000000..e3d5165
--- /dev/null
+++ b/contiki/apps/simpletelnet.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: simpletelnet.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __SIMPLETELNET_H__
+#define __SIMPLETELNET_H__
+
+void simpletelnet_init(void);
+void simpletelnet_open(void);
+
+#endif /* __SIMPLETELNET_H__ */
diff --git a/contiki/apps/smtp-strings b/contiki/apps/smtp-strings
new file mode 100644
index 0000000..a9e937c
--- /dev/null
+++ b/contiki/apps/smtp-strings
@@ -0,0 +1,9 @@
+smtp_220 "220"
+smtp_helo "HELO "
+smtp_mail_from "MAIL FROM: "
+smtp_rcpt_to "RCPT TO: "
+smtp_data "DATA"
+smtp_to "To: "
+smtp_from "From: "
+smtp_subject "Subject: "
+smtp_quit "QUIT"
\ No newline at end of file
diff --git a/contiki/apps/smtp-strings.c b/contiki/apps/smtp-strings.c
new file mode 100644
index 0000000..fa50ab6
--- /dev/null
+++ b/contiki/apps/smtp-strings.c
@@ -0,0 +1,27 @@
+char smtp_220[4] =
+/* "220" */
+{0x32, 0x32, 0x30, };
+char smtp_helo[6] =
+/* "HELO " */
+{0x48, 0x45, 0x4c, 0x4f, 0x20, };
+char smtp_mail_from[12] =
+/* "MAIL FROM: " */
+{0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x20, };
+char smtp_rcpt_to[10] =
+/* "RCPT TO: " */
+{0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x20, };
+char smtp_data[5] =
+/* "DATA" */
+{0x44, 0x41, 0x54, 0x41, };
+char smtp_to[5] =
+/* "To: " */
+{0x54, 0x6f, 0x3a, 0x20, };
+char smtp_from[7] =
+/* "From: " */
+{0x46, 0x72, 0x6f, 0x6d, 0x3a, 0x20, };
+char smtp_subject[10] =
+/* "Subject: " */
+{0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, };
+char smtp_quit[5] =
+/* "QUIT" */
+{0x51, 0x55, 0x49, 0x54, };
diff --git a/contiki/apps/smtp-strings.h b/contiki/apps/smtp-strings.h
new file mode 100644
index 0000000..15bed46
--- /dev/null
+++ b/contiki/apps/smtp-strings.h
@@ -0,0 +1,9 @@
+extern char smtp_220[4];
+extern char smtp_helo[6];
+extern char smtp_mail_from[12];
+extern char smtp_rcpt_to[10];
+extern char smtp_data[5];
+extern char smtp_to[5];
+extern char smtp_from[7];
+extern char smtp_subject[10];
+extern char smtp_quit[5];
diff --git a/contiki/apps/smtp.c b/contiki/apps/smtp.c
new file mode 100644
index 0000000..19cd097
--- /dev/null
+++ b/contiki/apps/smtp.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: smtp.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+#include "uip.h"
+#include "smtp.h"
+
+#include "smtp-strings.h"
+
+#include <string.h>
+
+#define STATE_SEND_NONE 0
+#define STATE_SEND_HELO 1
+#define STATE_SEND_MAIL_FROM 2
+#define STATE_SEND_RCPT_TO 3
+#define STATE_SEND_DATA 4
+#define STATE_SEND_DATA_HEADERS 5
+#define STATE_SEND_DATA_MESSAGE 6
+#define STATE_SEND_DATA_END 7
+#define STATE_SEND_QUIT 8
+#define STATE_SEND_DONE 9
+
+static char *localhostname;
+static u16_t smtpserver[2];
+
+
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+
+#define ISO_period 0x2e
+
+#define ISO_2 0x32
+#define ISO_3 0x33
+#define ISO_4 0x34
+#define ISO_5 0x35
+
+
+struct smtp_state {
+ u8_t state;
+ char *to;
+ char *from;
+ char *subject;
+ char *msg;
+ u16_t msglen;
+
+ u16_t sentlen, textlen;
+ u16_t sendptr;
+
+};
+
+
+static struct smtp_state s;
+
+/*-----------------------------------------------------------------------------------*/
+static void
+senddata(void)
+{
+ char *textptr;
+
+ if(s.textlen != 0 &&
+ s.textlen == s.sendptr) {
+ return;
+ }
+
+ textptr = (char *)uip_appdata;
+ switch(s.state) {
+ case STATE_SEND_HELO:
+ /* Create HELO message. */
+ strcpy(textptr, smtp_helo);
+ textptr += sizeof(smtp_helo) - 1;
+ strcpy(textptr, localhostname);
+ textptr += strlen(localhostname);
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+ /* printf("s.sendptr %d\n", s.sendptr);*/
+ if(s.sendptr == 0) {
+ s.textlen = textptr - (char *)uip_appdata;
+ /* printf("s.textlen %d\n", s.textlen);*/
+ }
+ textptr = (char *)uip_appdata;
+ break;
+ case STATE_SEND_MAIL_FROM:
+ /* Create MAIL FROM message. */
+ strcpy(textptr, smtp_mail_from);
+ textptr += sizeof(smtp_mail_from) - 1;
+ strcpy(textptr, s.from);
+ textptr += strlen(s.from);
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+ if(s.sendptr == 0) {
+ s.textlen = textptr - (char *)uip_appdata;
+ }
+ textptr = (char *)uip_appdata;
+ break;
+ case STATE_SEND_RCPT_TO:
+ /* Create RCPT_TO message. */
+ strcpy(textptr, smtp_rcpt_to);
+ textptr += sizeof(smtp_rcpt_to) - 1;
+ strcpy(textptr, s.to);
+ textptr += strlen(s.to);
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+ if(s.sendptr == 0) {
+ s.textlen = textptr - (char *)uip_appdata;
+ }
+ textptr = (char *)uip_appdata;
+ break;
+ case STATE_SEND_DATA:
+ strcpy(textptr, smtp_data);
+ textptr += sizeof(smtp_data) - 1;
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+ if(s.sendptr == 0) {
+ s.textlen = textptr - (char *)uip_appdata;
+ }
+ textptr = (char *)uip_appdata;
+ break;
+ case STATE_SEND_DATA_HEADERS:
+ /* Create mail headers. */
+ strcpy(textptr, smtp_to);
+ textptr += sizeof(smtp_to) - 1;
+ strcpy(textptr, s.to);
+ textptr += strlen(s.to);
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+
+ strcpy(textptr, smtp_from);
+ textptr += sizeof(smtp_from) - 1;
+ strcpy(textptr, s.from);
+ textptr += strlen(s.from);
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+
+ strcpy(textptr, smtp_subject);
+ textptr += sizeof(smtp_subject) - 1;
+ strcpy(textptr, s.subject);
+ textptr += strlen(s.subject);
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+
+ if(s.sendptr == 0) {
+ s.textlen = textptr - (char *)uip_appdata;
+ }
+ textptr = (char *)uip_appdata;
+ break;
+ case STATE_SEND_DATA_MESSAGE:
+ textptr = s.msg;
+ if(s.sendptr == 0) {
+ s.textlen = s.msglen;
+ }
+ break;
+ case STATE_SEND_DATA_END:
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+ *textptr = ISO_period;
+ ++textptr;
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+ if(s.sendptr == 0) {
+ s.textlen = 5;
+ }
+ textptr = (char *)uip_appdata;
+ break;
+ case STATE_SEND_QUIT:
+ strcpy(textptr, smtp_quit);
+ textptr += sizeof(smtp_quit) - 1;
+ *textptr = ISO_cr;
+ ++textptr;
+ *textptr = ISO_nl;
+ ++textptr;
+ if(s.sendptr == 0) {
+ s.textlen = textptr - (char *)uip_appdata;
+ }
+ textptr = (char *)uip_appdata;
+ break;
+ default:
+ return;
+ }
+
+ textptr += s.sendptr;
+
+ /* printf("Senidng '%s'\n", textptr);*/
+
+ if(s.textlen - s.sendptr > uip_mss()) {
+ s.sentlen = uip_mss();
+ } else {
+ s.sentlen = s.textlen - s.sendptr;
+ }
+ uip_send(textptr, s.sentlen);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+acked(void)
+{
+ s.sendptr += s.sentlen;
+ s.sentlen = 0;
+
+ if(s.sendptr == s.textlen) {
+ switch(s.state) {
+ case STATE_SEND_DATA_HEADERS:
+ s.state = STATE_SEND_DATA_MESSAGE;
+ break;
+ case STATE_SEND_DATA_MESSAGE:
+ s.state = STATE_SEND_DATA_END;
+ break;
+ case STATE_SEND_DATA_END:
+ s.state = STATE_SEND_QUIT;
+ break;
+ case STATE_SEND_QUIT:
+ s.state = STATE_SEND_DONE;
+ smtp_done(SMTP_ERR_OK);
+ uip_close();
+ break;
+ }
+ s.sendptr = s.textlen = 0;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+newdata(void)
+{
+ if(*(char *)uip_appdata == ISO_5) {
+ smtp_done(1);
+ uip_abort();
+ return;
+ }
+ /* printf("Got %d bytes: '%s'\n", uip_datalen(),
+ uip_appdata);*/
+ switch(s.state) {
+ case STATE_SEND_NONE:
+ if(strncmp((char *)uip_appdata, smtp_220, 3) == 0) {
+ /* printf("Got 220\n");*/
+ s.state = STATE_SEND_HELO;
+ }
+ break;
+ case STATE_SEND_HELO:
+ if(*(char *)uip_appdata == ISO_2) {
+ /* printf("2\n");*/
+ s.state = STATE_SEND_MAIL_FROM;
+ s.sendptr = 0;
+ }
+ break;
+ case STATE_SEND_MAIL_FROM:
+ if(*(char *)uip_appdata == ISO_2) {
+ /* printf("2\n");*/
+ s.state = STATE_SEND_RCPT_TO;
+ s.textlen = s.sendptr = 0;
+ }
+ break;
+ case STATE_SEND_RCPT_TO:
+ if(*(char *)uip_appdata == ISO_2) {
+ /* printf("2\n");*/
+ s.state = STATE_SEND_DATA;
+ s.textlen = s.sendptr = 0;
+ }
+ break;
+ case STATE_SEND_DATA:
+ if(*(char *)uip_appdata == ISO_3) {
+ /* printf("3\n");*/
+ s.state = STATE_SEND_DATA_HEADERS;
+ s.textlen = s.sendptr = 0;
+ }
+ break;
+ case STATE_SEND_DATA_HEADERS:
+ if(*(char *)uip_appdata == ISO_3) {
+ /* printf("3\n");*/
+ s.state = STATE_SEND_DATA_MESSAGE;
+ s.textlen = s.sendptr = 0;
+ }
+ break;
+ }
+
+}
+/*-----------------------------------------------------------------------------------*/
+void
+smtp_appcall(void *state)
+{
+ if(uip_connected()) {
+ /* senddata();*/
+ return;
+ }
+ if(uip_acked()) {
+ acked();
+ }
+ if(uip_newdata()) {
+ newdata();
+ }
+ if(uip_rexmit() ||
+ uip_newdata() ||
+ uip_acked()) {
+ senddata();
+ } else if(uip_poll()) {
+ senddata();
+ }
+ /* if(uip_closed()) {
+ printf("Dnoe\n");
+ }*/
+
+
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+smtp_send(char *to, char *from, char *subject,
+ char *msg, u16_t msglen)
+{
+ struct uip_conn *conn;
+
+ conn = uip_connect(smtpserver, 25);
+ if(conn == NULL) {
+ return 0;
+ }
+ dispatcher_markconn(conn, NULL);
+
+ s.state = STATE_SEND_NONE;
+ s.sentlen = s.sendptr = s.textlen = 0;
+ s.to = to;
+ s.from = from;
+ s.subject = subject;
+ s.msg = msg;
+ s.msglen = msglen;
+
+ return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+smtp_configure(char *lhostname, u16_t *server)
+{
+ localhostname = lhostname;
+ smtpserver[0] = server[0];
+ smtpserver[1] = server[1];
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/smtp.h b/contiki/apps/smtp.h
new file mode 100644
index 0000000..1f9feed
--- /dev/null
+++ b/contiki/apps/smtp.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: smtp.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __SMTP_H__
+#define __SMTP_H__
+
+#include "uipopt.h"
+
+/* Callbacks. */
+#define SMTP_ERR_OK 0
+void smtp_done(unsigned char error);
+
+/* Functions. */
+void smtp_configure(char *localhostname, u16_t *smtpserver);
+unsigned char smtp_send(char *to, char *from,
+ char *subject, char *msg,
+ u16_t msglen);
+
+void smtp_appcall(void *);
+
+
+#ifndef UIP_APPCALL
+#define UIP_APPCALL smtp_appcall
+#endif
+
+#ifndef UIP_APPSTATE_SIZE
+#define UIP_APPSTATE_SIZE (sizeof(struct smtp_state))
+#endif
+
+
+#endif /* __SMTP_H__ */
diff --git a/contiki/apps/telnet.c b/contiki/apps/telnet.c
new file mode 100644
index 0000000..f28bda9
--- /dev/null
+++ b/contiki/apps/telnet.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: telnet.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+#include "uip.h"
+
+#include "telnet.h"
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+#define FLAG_CLOSE 1
+#define FLAG_ABORT 2
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+telnet_send(struct telnet_state *s, char *text, u16_t len)
+{
+ if(s->text != NULL) {
+ return 1;
+ }
+ s->text = text;
+ s->textlen = len;
+ s->sentlen = 0;
+ return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+telnet_close(struct telnet_state *s)
+{
+ s->flags = FLAG_CLOSE;
+ if(s->text != NULL) {
+ return 1;
+ }
+ return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+telnet_abort(struct telnet_state *s)
+{
+ s->flags = FLAG_ABORT;
+ if(s->text != NULL) {
+ return 1;
+ }
+ return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+acked(struct telnet_state *s)
+{
+ s->textlen -= s->sentlen;
+ if(s->textlen == 0) {
+ s->text = NULL;
+ telnet_sent(s);
+ } else {
+ s->text += s->sentlen;
+ }
+ s->sentlen = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+senddata(struct telnet_state *s)
+{
+ if(s->text == NULL) {
+ uip_send(s->text, 0);
+ return;
+ }
+ if(s->textlen > uip_mss()) {
+ s->sentlen = uip_mss();
+ } else {
+ s->sentlen = s->textlen;
+ }
+ uip_send(s->text, s->sentlen);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+telnet_app(struct telnet_state *s)
+{
+ if(uip_connected()) {
+ s->flags = 0;
+ telnet_connected(s);
+ senddata(s);
+ return;
+ }
+
+ if(uip_closed()) {
+ telnet_closed(s);
+ }
+
+ if(uip_aborted()) {
+ telnet_aborted(s);
+ }
+ if(uip_timedout()) {
+ telnet_timedout(s);
+ }
+
+
+ if(s->flags & FLAG_CLOSE) {
+ uip_close();
+ return;
+ }
+ if(s->flags & FLAG_ABORT) {
+ uip_abort();
+ return;
+ }
+ if(uip_acked()) {
+ acked(s);
+ }
+ if(uip_newdata()) {
+ telnet_newdata(s, (char *)uip_appdata, uip_datalen());
+ }
+ if(uip_rexmit() ||
+ uip_newdata() ||
+ uip_acked()) {
+ senddata(s);
+ } else if(uip_poll()) {
+ senddata(s);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/telnet.h b/contiki/apps/telnet.h
new file mode 100644
index 0000000..f52ba94
--- /dev/null
+++ b/contiki/apps/telnet.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: telnet.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __TELNET_H__
+#define __TELNET_H__
+
+#include "uipopt.h"
+
+struct telnet_state {
+ unsigned char flags;
+ char *text;
+ u16_t textlen;
+ u16_t sentlen;
+};
+
+void telnet_app(struct telnet_state *s);
+unsigned char telnet_send(struct telnet_state *s, char *text, u16_t len);
+unsigned char telnet_close(struct telnet_state *s);
+unsigned char telnet_abort(struct telnet_state *s);
+
+/* Callbacks, implemented by the caller. */
+void telnet_connected(struct telnet_state *s);
+void telnet_closed(struct telnet_state *s);
+void telnet_sent(struct telnet_state *s);
+void telnet_aborted(struct telnet_state *s);
+void telnet_timedout(struct telnet_state *s);
+void telnet_newdata(struct telnet_state *s, char *data, u16_t len);
+#endif /* __TELNET_H__ */
diff --git a/contiki/apps/webclient.c b/contiki/apps/webclient.c
new file mode 100644
index 0000000..5a72f84
--- /dev/null
+++ b/contiki/apps/webclient.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "contiki" web browser.
+ *
+ * $Id: webclient.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+#include "uip.h"
+#include "webclient.h"
+#include "resolv.h"
+#include "uip_main.h"
+
+#include <string.h>
+
+#define WEBCLIENT_TIMEOUT 100
+
+#define WEBCLIENT_STATE_STATUSLINE 0
+#define WEBCLIENT_STATE_HEADERS 1
+#define WEBCLIENT_STATE_DATA 2
+#define WEBCLIENT_STATE_CLOSE 3
+
+#define HTTPFLAG_NONE 0
+#define HTTPFLAG_OK 1
+#define HTTPFLAG_MOVED 2
+#define HTTPFLAG_ERROR 3
+
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+#define ISO_space 0x20
+
+struct webclient_state {
+ u8_t timer;
+ u8_t state;
+ u8_t httpflag;
+
+ u16_t port;
+ char host[40];
+ char file[100];
+ u16_t getrequestptr;
+ u16_t getrequestleft;
+
+ char httpheaderline[200];
+ u16_t httpheaderlineptr;
+
+ char mimetype[32];
+};
+
+static struct webclient_state s;
+
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_mimetype(void)
+{
+ return &s.mimetype;
+}
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_filename(void)
+{
+ return &s.file;
+}
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_hostname(void)
+{
+ return &s.host;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned short
+webclient_port(void)
+{
+ return s.port;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+webclient_init(void)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+init_connection(void)
+{
+ s.state = WEBCLIENT_STATE_STATUSLINE;
+
+ s.getrequestleft = sizeof(http_get) - 1 + 1 +
+ sizeof(http_10) - 1 +
+ sizeof(http_crnl) - 1 +
+ sizeof(http_host) - 1 +
+ sizeof(http_crnl) - 1 +
+ sizeof(http_fields) - 1 +
+ strlen(s.file) + strlen(s.host);
+ s.getrequestptr = 0;
+
+ s.httpheaderlineptr = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+webclient_close(void)
+{
+ s.state = WEBCLIENT_STATE_CLOSE;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+webclient_get(char *host, u16_t port, char *file)
+{
+ struct uip_conn *conn;
+ u16_t *ipaddr;
+
+
+ ipaddr = resolv_lookup(host);
+
+ if(ipaddr == NULL) {
+ return 0;
+ }
+
+ conn = uip_connect(ipaddr, port);
+
+ if(conn == NULL) {
+ return 0;
+ }
+
+ dispatcher_markconn(conn, NULL);
+
+ s.port = port;
+ strncpy(s.file, file, sizeof(s.file));
+ strncpy(s.host, host, sizeof(s.host));
+
+ init_connection();
+ return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char *
+copy_string(unsigned char *dest, unsigned char *src, unsigned char len)
+{
+ return strcpy(dest, src) + len;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+senddata(void)
+{
+ u16_t len;
+ char *getrequest;
+ char *cptr;
+
+ if(s.getrequestleft > 0) {
+ cptr = getrequest = (char *)uip_appdata;
+
+ cptr = copy_string(cptr, http_get, sizeof(http_get) - 1);
+ cptr = copy_string(cptr, s.file, strlen(s.file));
+ *cptr++ = ISO_space;
+ cptr = copy_string(cptr, http_10, sizeof(http_10) - 1);
+
+ cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
+
+ cptr = copy_string(cptr, http_host, sizeof(http_host) - 1);
+ cptr = copy_string(cptr, s.host, strlen(s.host));
+ cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
+
+ cptr = copy_string(cptr, http_fields, sizeof(http_fields) - 1);
+
+ len = s.getrequestleft > uip_mss()?
+ uip_mss():
+ s.getrequestleft;
+ uip_send(&(getrequest[s.getrequestptr]), len);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+acked(void)
+{
+ u16_t len;
+
+ if(s.getrequestleft > 0) {
+ len = s.getrequestleft > uip_mss()?
+ uip_mss():
+ s.getrequestleft;
+ s.getrequestleft -= len;
+ s.getrequestptr += len;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static u16_t
+parse_statusline(u16_t len)
+{
+ char *cptr;
+
+ while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
+ s.httpheaderline[s.httpheaderlineptr] = *uip_appdata;
+ ++uip_appdata;
+ --len;
+ if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
+
+ if((strncmp(s.httpheaderline, http_10,
+ sizeof(http_10) - 1) == 0) ||
+ (strncmp(s.httpheaderline, http_11,
+ sizeof(http_11) - 1) == 0)) {
+ cptr = &(s.httpheaderline[9]);
+ s.httpflag = HTTPFLAG_NONE;
+ if(strncmp(cptr, http_200, sizeof(http_200) - 1) == 0) {
+ /* 200 OK */
+ s.httpflag = HTTPFLAG_OK;
+ } else if(strncmp(cptr, http_301, sizeof(http_301) - 1) == 0 ||
+ strncmp(cptr, http_302, sizeof(http_302) - 1) == 0) {
+ /* 301 Moved permanently or 302 Found. Location: header line
+ will contain thw new location. */
+ s.httpflag = HTTPFLAG_MOVED;
+ } else {
+ s.httpheaderline[s.httpheaderlineptr - 1] = 0;
+ }
+ } else {
+ uip_abort();
+ webclient_aborted();
+ return 0;
+ }
+
+ /* We're done parsing the status line, so we reset the pointer
+ and start parsing the HTTP headers.*/
+ s.httpheaderlineptr = 0;
+ s.state = WEBCLIENT_STATE_HEADERS;
+ break;
+ } else {
+ ++s.httpheaderlineptr;
+ }
+ }
+ return len;
+}
+/*-----------------------------------------------------------------------------------*/
+static u16_t
+parse_headers(u16_t len)
+{
+ char *cptr;
+
+ while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
+ s.httpheaderline[s.httpheaderlineptr] = *uip_appdata;
+ ++uip_appdata;
+ --len;
+ if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
+ /* We have an entire HTTP header line in s.httpheaderline, so
+ we parse it. */
+ if(s.httpheaderline[0] == ISO_cr) {
+ /* This was the last header line (i.e., and empty "\r\n"), so
+ we are done with the headers and proceed with the actual
+ data. */
+ s.state = WEBCLIENT_STATE_DATA;
+ return len;
+ }
+
+ s.httpheaderline[s.httpheaderlineptr - 1] = 0;
+ /* Check for specific HTTP header fields. */
+ if(strncmp(s.httpheaderline, http_content_type,
+ sizeof(http_content_type) - 1) == 0) {
+ /* Found Content-type field. */
+ cptr = strchr(s.httpheaderline, ';');
+ if(cptr != NULL) {
+ *cptr = 0;
+ }
+ strncpy(s.mimetype, s.httpheaderline +
+ sizeof(http_content_type) - 1, sizeof(s.mimetype));
+ } else if(strncmp(s.httpheaderline, http_location,
+ sizeof(http_location) - 1) == 0) {
+ strncpy(s.file, s.httpheaderline +
+ sizeof(http_location) - 1, sizeof(s.file));
+ s.file[s.httpheaderlineptr - 1] = 0;
+ }
+
+
+ /* We're done parsing, so we reset the pointer and start the
+ next line. */
+ s.httpheaderlineptr = 0;
+ } else {
+ ++s.httpheaderlineptr;
+ }
+ }
+ return len;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+newdata(void)
+{
+ u16_t len;
+
+ len = uip_datalen();
+
+ if(s.state == WEBCLIENT_STATE_STATUSLINE) {
+ len = parse_statusline(len);
+ }
+
+ if(s.state == WEBCLIENT_STATE_HEADERS && len > 0) {
+ len = parse_headers(len);
+ }
+
+ if(len > 0 && s.state == WEBCLIENT_STATE_DATA &&
+ s.httpflag != HTTPFLAG_MOVED) {
+ webclient_datahandler((char *)uip_appdata, len);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+webclient_appcall(void *state)
+{
+ struct uip_conn *conn;
+
+ if(s.state == WEBCLIENT_STATE_CLOSE) {
+ webclient_closed();
+ uip_abort();
+ return;
+ }
+
+ if(uip_connected()) {
+ s.timer = 0;
+ s.state = WEBCLIENT_STATE_STATUSLINE;
+ senddata();
+ webclient_connected();
+ return;
+ }
+
+ if(uip_aborted()) {
+ webclient_aborted();
+ }
+ if(uip_timedout()) {
+ webclient_timedout();
+ }
+
+
+ if(uip_acked()) {
+ s.timer = 0;
+ acked();
+ }
+ if(uip_newdata()) {
+ s.timer = 0;
+ newdata();
+ }
+ if(uip_rexmit() ||
+ uip_newdata() ||
+ uip_acked()) {
+ senddata();
+ } else if(uip_poll()) {
+ ++s.timer;
+ if(s.timer == WEBCLIENT_TIMEOUT) {
+ webclient_timedout();
+ uip_abort();
+ return;
+ }
+ /* senddata();*/
+ }
+
+ if(uip_closed()) {
+ if(s.httpflag != HTTPFLAG_MOVED) {
+ /* Send NULL data to signal EOF. */
+ webclient_datahandler(NULL, 0);
+ } else {
+ conn = uip_connect(uip_conn->ripaddr, s.port);
+ if(conn != NULL) {
+ dispatcher_markconn(conn, NULL);
+ init_connection();
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/webclient.h b/contiki/apps/webclient.h
new file mode 100644
index 0000000..b365428
--- /dev/null
+++ b/contiki/apps/webclient.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "contiki" web browser.
+ *
+ * $Id: webclient.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __WEBCLIENT_H__
+#define __WEBCLIENT_H__
+
+
+#include "http-strings.h"
+
+/* Callback functions that have to be implemented by the application
+ program. */
+struct webclient_state;
+void webclient_datahandler(char *data, u16_t len);
+void webclient_connected(void);
+void webclient_timedout(void);
+void webclient_aborted(void);
+void webclient_closed(void);
+
+
+/* Functions. */
+void webclient_init(void);
+unsigned char webclient_get(char *host, u16_t port, char *file);
+void webclient_close(void);
+void webclient_appcall(void *);
+
+char *webclient_mimetype(void);
+char *webclient_filename(void);
+char *webclient_hostname(void);
+unsigned short webclient_port(void);
+
+#endif /* __WEBCLIENT_H__ */
diff --git a/contiki/apps/webserver.c b/contiki/apps/webserver.c
new file mode 100644
index 0000000..e317673
--- /dev/null
+++ b/contiki/apps/webserver.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: webserver.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+
+#include "ctk.h"
+#include "dispatcher.h"
+#include "http-strings.h"
+#include "uip_main.h"
+#include "petsciiconv.h"
+
+#include <c64.h>
+#include <cbm.h>
+
+
+/* The main window. */
+static struct ctk_window mainwindow;
+
+static struct ctk_label message =
+ {CTK_LABEL(0, 0, 14, 1, "Web server is ")};
+static struct ctk_label onoffmessage =
+ {CTK_LABEL(14, 0, 3, 1, "Off")};
+
+
+static struct ctk_label tracklabel =
+ {CTK_LABEL(1, 2, 5, 1, "Track")};
+static struct ctk_label sectorlabel =
+ {CTK_LABEL(1, 3, 6, 1, "Sector")};
+
+static char tracknum[3], sectornum[3];
+
+static struct ctk_label tracknumlabel =
+ {CTK_LABEL(14, 2, 2, 1, tracknum)};
+static struct ctk_label sectornumlabel =
+ {CTK_LABEL(14, 3, 2, 1, sectornum)};
+
+static struct ctk_button onbutton =
+ {CTK_BUTTON(0, 5, 2, "On")};
+static struct ctk_label statuslabel =
+ {CTK_LABEL(4, 5, 8, 1, "")};
+static struct ctk_button offbutton =
+ {CTK_BUTTON(12, 5, 3, "Off")};
+
+static unsigned char onoff;
+#define ON 1
+#define OFF 0
+
+static void sighandler(ek_signal_t s, ek_data_t data);
+static void uipappcall(void *state);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("Web server", NULL, sighandler, uipappcall)};
+static ek_id_t id;
+
+
+struct drv_state {
+ u8_t state;
+#define STATE_NONE 0
+#define STATE_RECEIVING_REQUEST 1
+#define STATE_SENDING_HEADERS 2
+#define STATE_SENDING_DATA 3
+#define STATE_DONE 4
+
+ /* char filename[40];*/
+
+ u8_t track;
+ u8_t sect;
+};
+
+#define ISO_slash 0x2f
+#define ISO_space 0x20
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+
+
+static struct drv_state ds;
+
+/*-----------------------------------------------------------------------------------*/
+void
+webserver_init(void)
+{
+ if(id == EK_ID_NONE) {
+ id = dispatcher_start(&p);
+
+ ctk_window_new(&mainwindow, 17, 6, "Web server");
+ ctk_window_move(&mainwindow, 21, 16);
+
+ CTK_WIDGET_ADD(&mainwindow, &message);
+ CTK_WIDGET_ADD(&mainwindow, &onoffmessage);
+
+ CTK_WIDGET_ADD(&mainwindow, &tracklabel);
+ CTK_WIDGET_ADD(&mainwindow, &tracknumlabel);
+ CTK_WIDGET_ADD(&mainwindow, §orlabel);
+ CTK_WIDGET_ADD(&mainwindow, §ornumlabel);
+
+ CTK_WIDGET_ADD(&mainwindow, &onbutton);
+ CTK_WIDGET_ADD(&mainwindow, &offbutton);
+
+ CTK_WIDGET_FOCUS(&mainwindow, &onbutton);
+
+ /* Attach listeners to signals. */
+ dispatcher_listen(ctk_signal_button_activate);
+
+ dispatcher_uiplisten(80);
+
+ onoff = OFF;
+ }
+
+ ctk_window_open(&mainwindow);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sighandler(ek_signal_t s, ek_data_t data)
+{
+ struct ctk_button *b;
+ unsigned char i;
+
+ if(s == ctk_signal_button_activate) {
+ b = (struct ctk_button *)data;
+ if(b == &onbutton) {
+ ctk_label_set_text(&onoffmessage, "On ");
+ CTK_WIDGET_REDRAW(&onoffmessage);
+ onoff = ON;
+ } else if(b == &offbutton) {
+ ctk_label_set_text(&onoffmessage, "Off");
+ CTK_WIDGET_REDRAW(&onoffmessage);
+ onoff = OFF;
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+x_open(u8_t f, u8_t d, u8_t cmd, u8_t *fname)
+{
+ u8_t ret;
+
+ ret = cbm_open(f, d, cmd, fname);
+ if(ret != 0) {
+ /* printf("open: error %d\n", ret);*/
+ ctk_label_set_text(&statuslabel, "Open err");
+ CTK_WIDGET_REDRAW(&statuslabel);
+ }
+
+}
+
+static u8_t cmd[32];
+static void
+read_sector(u8_t device, u8_t track, u8_t sect, void *mem)
+{
+ int ret;
+
+ x_open(15, device, 15, NULL);
+ x_open(2, device, 2, "#");
+
+ /* sprintf(cmd, "u1: 2 0%3d%3d", track, sect); */
+ strcpy(cmd, "u1: 2 0");
+ cmd[8] = ' ';
+ cmd[9] = '0' + track / 10;
+ cmd[10] = '0' + track % 10;
+ cmd[11] = ' ';
+ cmd[12] = '0' + sect / 10;
+ cmd[13] = '0' + sect % 10;
+ cmd[14] = 0;
+ cbm_write(15, cmd, strlen(cmd));
+ /* printf("%s\n", cmd);*/
+
+ ret = cbm_read(2, mem, 256);
+ if(ret == -1) {
+ ctk_label_set_text(&statuslabel, "Read err");
+ CTK_WIDGET_REDRAW(&statuslabel);
+ }
+ /* printf("read: read %d bytes\n", ret);*/
+
+ cbm_close(2);
+ cbm_close(15);
+
+}
+
+static void
+write_sector(u8_t device, u8_t track, u8_t sect, void *mem)
+{
+/* u16_t ret;
+ u8_t cmd[32];
+
+ x_open(15, device, 15, NULL);
+ x_open(2, device, 2, "#");
+
+ sprintf(cmd, "u2: 2 0%3d%3d", track, sect);
+ cbm_write(15, cmd, strlen(cmd));
+ printf("%s\n", cmd);
+
+ ret = cbm_write(2, mem, 256);
+ printf("write: wrote %d bytes\n", ret);
+
+ cbm_close(2);
+ cbm_close(15);*/
+}
+
+static u8_t
+next_sector(void)
+{
+ ++ds.sect;
+ if(ds.track < 18) {
+ if(ds.sect == 21) {
+ ++ds.track;
+ ds.sect = 0;
+ }
+ } else if(ds.track < 25) {
+ if(ds.sect == 19) {
+ ++ds.track;
+ ds.sect = 0;
+ }
+ } else if(ds.track < 31) {
+ if(ds.sect == 18) {
+ ++ds.track;
+ ds.sect = 0;
+ }
+ } else if(ds.track < 36) {
+ if(ds.sect == 17) {
+ ++ds.track;
+ ds.sect = 0;
+ }
+ }
+
+ tracknum[0] = '0' + ds.track / 10;
+ tracknum[1] = '0' + ds.track % 10;
+
+ CTK_WIDGET_REDRAW(&tracknumlabel);
+
+ sectornum[0] = '0' + ds.sect / 10;
+ sectornum[1] = '0' + ds.sect % 10;
+
+ CTK_WIDGET_REDRAW(§ornumlabel);
+
+
+ if(ds.track == 36) {
+ return 1;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------------------*/
+static void
+uipappcall(void *state)
+{
+ u8_t i;
+ int len;
+
+ if(onoff == OFF) {
+ cbm_close(4);
+ uip_abort();
+ return;
+ }
+
+ if(uip_connected()) {
+ ds.state = STATE_RECEIVING_REQUEST;
+ } else if(uip_acked()) {
+ switch(ds.state) {
+ case STATE_SENDING_HEADERS:
+ ds.state = STATE_SENDING_DATA;
+ ds.track = 1;
+ ds.sect = 0;
+ break;
+ case STATE_SENDING_DATA:
+ if(next_sector() != 0) {
+ cbm_close(4);
+ uip_close();
+ ds.state = STATE_NONE;
+ return;
+ }
+ }
+ } else if(uip_newdata()) {
+ if(ds.state == STATE_RECEIVING_REQUEST) {
+ ds.state = STATE_SENDING_HEADERS;
+#if 0
+ if(strncmp(uip_appdata, http_get, sizeof(http_get)) == 0 &&
+ uip_appdata[4] == ISO_slash) {
+ /* if(uip_appdata[5] == ISO_space) {
+ ds.filename[0] = '$';
+ ds.filename[1] = 0;
+ } else {
+ for(i = 0; i < sizeof(ds.filename); ++i) {
+ ds.filename[i] = uip_appdata[6 + i];
+ if(ds.filename[i] == ISO_space ||
+ ds.filename[i] == ISO_nl ||
+ ds.filename[i] == ISO_cr) {
+ ds.filename[i] = 0;
+ break;
+ }
+ }
+ }
+ cbm_open(4, 8, 4, ds.filename);*/
+ ds.state = STATE_SENDING_HEADERS;
+ }
+#endif
+ }
+ }
+ switch(ds.state) {
+ case STATE_SENDING_HEADERS:
+ uip_send(http_webserver_d64_headers, sizeof(http_webserver_d64_headers) - 1);
+ break;
+ case STATE_SENDING_DATA:
+ read_sector(8, ds.track, ds.sect, (void *)uip_appdata);
+ /* len = cbm_read(4, uip_appdata, 256);
+ if(len > 0) {*/
+ uip_send(uip_appdata, 256);
+ /* }*/
+ break;
+ }
+
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/webserver.h b/contiki/apps/webserver.h
new file mode 100644
index 0000000..6fb77fd
--- /dev/null
+++ b/contiki/apps/webserver.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: webserver.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __WEBSERVER_H__
+#define __WEBSERVER_H__
+
+void webserver_init(void);
+
+#endif /* __WEBSERVER_H__ */
diff --git a/contiki/apps/www-conf.h b/contiki/apps/www-conf.h
new file mode 100644
index 0000000..385c3a7
--- /dev/null
+++ b/contiki/apps/www-conf.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: www-conf.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __WWW_CONF_H__
+#define __WWW_CONF_H__
+
+#define WWW_CONF_MAX_URLLEN 100
+
+#define WWW_CONF_RENDERSTATE 1
+#define WWW_CONF_FORMS 1
+
+
+#define WWW_CONF_MAX_FORMACTIONLEN 40
+#define WWW_CONF_MAX_FORMNAMELEN 20
+#define WWW_CONF_MAX_INPUTNAMELEN 20
+#define WWW_CONF_MAX_INPUTVALUELEN 34
+
+#endif /* __WWW_CONF_H__ */
diff --git a/contiki/apps/www.c b/contiki/apps/www.c
new file mode 100644
index 0000000..f61fda9
--- /dev/null
+++ b/contiki/apps/www.c
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: www.c,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+
+#include "ctk.h"
+#include "dispatcher.h"
+#include "webclient.h"
+#include "htmlparser.h"
+#include "http-strings.h"
+#include "resolv.h"
+
+#include "petsciiconv.h"
+
+#include "www-conf.h"
+
+#if 0
+#define PRINTF(x)
+#else
+#include <stdio.h>
+#define PRINTF(x) printf x
+#endif
+
+
+/* The array that holds the current URL. */
+static char url[WWW_CONF_MAX_URLLEN + 1];
+static char tmpurl[WWW_CONF_MAX_URLLEN + 1];
+
+/* The array that holds the web page text. */
+#define WEBPAGE_WIDTH 36
+#define WEBPAGE_HEIGHT 17
+static char webpage[WEBPAGE_WIDTH * WEBPAGE_HEIGHT + 1];
+
+/* The CTK widgets for the main window. */
+static struct ctk_window mainwindow;
+
+static struct ctk_button backbutton =
+ {CTK_BUTTON(0, 0, 4, "Back")};
+static struct ctk_button downbutton =
+ {CTK_BUTTON(10, 0, 4, "Down")};
+static struct ctk_button stopbutton =
+ {CTK_BUTTON(20, 0, 4, "Stop")};
+static struct ctk_button gobutton =
+ {CTK_BUTTON(32, 0, 2, "Go")};
+
+static struct ctk_separator sep1 =
+ {CTK_SEPARATOR(0, 2, 36)};
+
+static char editurl[WWW_CONF_MAX_URLLEN + 1];
+static struct ctk_textentry urlentry =
+ {CTK_TEXTENTRY(0, 1, 34, 1, editurl, WWW_CONF_MAX_URLLEN)};
+static struct ctk_label webpagelabel =
+ {CTK_LABEL(0, 3, WEBPAGE_WIDTH, WEBPAGE_HEIGHT, webpage)};
+
+static char statustexturl[36];
+static struct ctk_label statustext =
+ {CTK_LABEL(0, 21, 36, 1, "")};
+static struct ctk_separator sep2 =
+ {CTK_SEPARATOR(0, 20, 36)};
+
+/* The char arrays that hold the history of visited URLs. */
+#define HISTORY_SIZE 4
+static char history[HISTORY_SIZE][WWW_CONF_MAX_URLLEN];
+static char history_last, history_first;
+
+
+/* The CTK widget definitions for the hyperlinks and the char arrays
+ that hold the link URLs. */
+struct formattribs {
+ char formaction[WWW_CONF_MAX_FORMACTIONLEN];
+ char formname[WWW_CONF_MAX_FORMNAMELEN];
+#define FORMINPUTTYPE_SUBMITBUTTON 1
+#define FORMINPUTTYPE_INPUTFIELD 2
+ unsigned char inputtype;
+ char inputname[WWW_CONF_MAX_INPUTNAMELEN];
+ char *inputvalue;
+};
+
+union pagewidgetattrib {
+ char url[WWW_CONF_MAX_URLLEN];
+ struct formattribs form;
+};
+#define MAX_NUMPAGEWIDGETS 20
+static struct ctk_widget pagewidgets[MAX_NUMPAGEWIDGETS];
+static union pagewidgetattrib pagewidgetattribs[MAX_NUMPAGEWIDGETS];
+static unsigned char pagewidgetptr;
+
+
+/* The "scrolly" variable holds the line number (in the web page) of
+ the first line of text shown on screen. */
+static unsigned short scrolly;
+
+#if WWW_CONF_RENDERSTATE
+static unsigned char renderstate;
+#endif /* WWW_CONF_RENDERSTATE */
+
+/* The "run" flag is used to determine if the web page should be
+ continuosly scrolled upward with new data coming in from below. */
+static unsigned char run;
+
+#define ISO_nl 0x0a
+#define ISO_space 0x20
+#define ISO_ampersand 0x26
+#define ISO_plus 0x2b
+#define ISO_slash 0x2f
+#define ISO_eq 0x3d
+#define ISO_questionmark 0x3f
+
+/* The state of the rendering code. */
+static u8_t x;
+static u16_t starty;
+static char nextword[WEBPAGE_WIDTH + 1];
+static unsigned char nextwordptr;
+
+static unsigned char count;
+static char receivingmsgs[4][23] = {
+ "Receiving web page ...",
+ "Receiving web page. ..",
+ "Receiving web page.. .",
+ "Receiving web page... "
+};
+
+
+static void sighandler(ek_signal_t s, ek_data_t data);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("Web browser", NULL, sighandler, webclient_appcall)};
+static ek_id_t id;
+
+
+static void formsubmit(struct formattribs *attribs);
+/*-----------------------------------------------------------------------------------*/
+/* make_window()
+ *
+ * Creates the web browser's window.
+ */
+static void
+make_window(void)
+{
+
+ CTK_WIDGET_ADD(&mainwindow, &backbutton);
+ CTK_WIDGET_ADD(&mainwindow, &downbutton);
+ CTK_WIDGET_ADD(&mainwindow, &stopbutton);
+ CTK_WIDGET_ADD(&mainwindow, &gobutton);
+ CTK_WIDGET_ADD(&mainwindow, &urlentry);
+ CTK_WIDGET_ADD(&mainwindow, &sep1);
+ CTK_WIDGET_ADD(&mainwindow, &webpagelabel);
+ CTK_WIDGET_ADD(&mainwindow, &sep2);
+ CTK_WIDGET_ADD(&mainwindow, &statustext);
+
+ CTK_WIDGET_FOCUS(&mainwindow, &stopbutton);
+
+ pagewidgetptr = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/* redraw_window():
+ *
+ * Convenience function that calls upon CTK to redraw the browser
+ * window. */
+static void
+redraw_window(void)
+{
+ ctk_window_redraw(&mainwindow);
+}
+/*-----------------------------------------------------------------------------------*/
+/* www_init();
+ *
+ * Initializes and starts the web browser. Called either at startup or
+ * to open the browser window.
+ */
+void
+www_init(void)
+{
+ if(id == EK_ID_NONE) {
+ id = dispatcher_start(&p);
+
+ /* Create the main window. */
+ memset(webpage, 0, sizeof(webpage));
+ ctk_window_new(&mainwindow, 36, 22, "WWW");
+ make_window();
+ CTK_WIDGET_FOCUS(&mainwindow, &urlentry);
+
+ /* Attach as a listener to a number of signals ("Button activate",
+ "Hyperlink activate" and "Hyperlink hover", and the resolver's
+ signal. */
+ dispatcher_listen(ctk_signal_button_activate);
+ dispatcher_listen(ctk_signal_hyperlink_activate);
+ dispatcher_listen(ctk_signal_hyperlink_hover);
+ dispatcher_listen(resolv_signal_found);
+ }
+ ctk_window_open(&mainwindow);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+clear_page(void)
+{
+ if(ctk_window_isopen(&mainwindow)) {
+ ctk_window_close(&mainwindow);
+ }
+ ctk_window_clear(&mainwindow);
+ make_window();
+ ctk_window_open(&mainwindow);
+ memset(webpage, 0, WEBPAGE_WIDTH * WEBPAGE_HEIGHT);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+show_url(void)
+{
+ memcpy(editurl, url, WWW_CONF_MAX_URLLEN);
+ strncpy(editurl, "http://", 7);
+ petsciiconv_topetscii(editurl + 7, WWW_CONF_MAX_URLLEN - 7);
+ CTK_WIDGET_REDRAW(&urlentry);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+show_statustext(char *text)
+{
+ ctk_label_set_text(&statustext, text);
+ CTK_WIDGET_REDRAW(&statustext);
+}
+/*-----------------------------------------------------------------------------------*/
+/* open_url():
+ *
+ * Called when the URL present in the global "url" variable should be
+ * opened. It will call the hostname resolver as well as the HTTP
+ * client requester.
+ */
+static void
+open_url(void)
+{
+ unsigned char i;
+ static char host[32];
+ char *file;
+ register char *urlptr;
+ unsigned short port;
+
+ /* Trim off any spaces in the end of the url. */
+ urlptr = url + strlen(url) - 1;
+ while(*urlptr == ' ' && urlptr > url) {
+ *urlptr = 0;
+ --urlptr;
+ }
+
+ /* Don't even try to go further if the URL is empty. */
+ if(urlptr == url) {
+ return;
+ }
+
+ /* See if the URL starts with http://, otherwise prepend it. */
+ if(strncmp(url, http_http, 7) != 0) {
+ while(urlptr >= url) {
+ *(urlptr + 7) = *urlptr;
+ --urlptr;
+ }
+ strncpy(url, http_http, 7);
+ }
+
+ /* Find host part of the URL. */
+ urlptr = &url[7];
+ for(i = 0; i < sizeof(host); ++i) {
+ if(*urlptr == 0 ||
+ *urlptr == '/' ||
+ *urlptr == ' ' ||
+ *urlptr == ':') {
+ host[i] = 0;
+ break;
+ }
+ host[i] = *urlptr;
+ ++urlptr;
+ }
+
+ /* XXX: Here we should find the port part of the URL, but this isn't
+ currently done because of laziness from the programmer's side
+ :-) */
+
+ /* Find file part of the URL. */
+ while(*urlptr != '/' && *urlptr != 0) {
+ ++urlptr;
+ }
+ if(*urlptr == '/') {
+ file = urlptr;
+ } else {
+ file = "/";
+ }
+
+ /* Try to lookup the hostname. If it fails, we initiate a hostname
+ lookup and print out an informative message on the statusbar. */
+ if(resolv_lookup(host) == NULL) {
+ resolv_query(host);
+ show_statustext("Resolving host...");
+ return;
+ }
+
+ /* The hostname we present in the hostname table, so we send out the
+ initial GET request. */
+ if(webclient_get(host, 80, file) == 0) {
+ show_statustext("Out of memory error.");
+ } else {
+ show_statustext("Connecting...");
+ }
+ redraw_window();
+}
+/*-----------------------------------------------------------------------------------*/
+/* open_link(link):
+ *
+ * Will format a link from the current web pages so that it suits the
+ * open_url() function and finally call it to open the requested URL.
+ */
+static void
+open_link(char *link)
+{
+ char *urlptr;
+
+ if(strncmp(link, http_http, 7) == 0) {
+ /* The link starts with http://. We just copy the contents of the
+ link into the url string and jump away. */
+ strncpy(url, link, WWW_CONF_MAX_URLLEN);
+ } else if(*link == ISO_slash &&
+ *(link + 1) == ISO_slash) {
+ /* The link starts with //, so we'll copy it into the url
+ variable, starting after the http (which already is present in
+ the url variable since we were able to open the web page on
+ which this link was found in the first place). */
+ strncpy(&url[5], link, WWW_CONF_MAX_URLLEN);
+ } else if(*link == ISO_slash) {
+ /* The link starts with a slash, so it is a non-relative link
+ within the same web site. We find the start of the filename of
+ the current URL and paste the contents of this link there, and
+ head off to the new URL. */
+ for(urlptr = &url[7];
+ *urlptr != 0 && *urlptr != ISO_slash;
+ ++urlptr);
+ strncpy(urlptr, link, WWW_CONF_MAX_URLLEN - (urlptr - url));
+ } else {
+ /* A fully relative link is found. We find the last slash in the
+ current URL and paste the link there. */
+
+ /* XXX: we should really parse any ../ in the link as well. */
+ for(urlptr = url + strlen(url);
+ urlptr != url && *urlptr != ISO_slash;
+ --urlptr);
+ ++urlptr;
+ strncpy(urlptr, link, WWW_CONF_MAX_URLLEN - (urlptr - url));
+ }
+
+ /* Open the URL. */
+ scrolly = 0;
+ show_url();
+ open_url();
+}
+/*-----------------------------------------------------------------------------------*/
+/* log_back():
+ *
+ * Copies the current URL from the url variable and into the log for
+ * the back button.
+ */
+static void
+log_back(void)
+{
+ memcpy(history[history_last], url, WWW_CONF_MAX_URLLEN);
+ ++history_last;
+ if(history_last > HISTORY_SIZE) {
+ history_last = 0;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+/* www_dispatcher():
+ *
+ * The program's signal dispatcher function. Is called by the ek
+ * dispatcher whenever a signal arrives.
+ */
+static void
+sighandler(ek_signal_t s, ek_data_t data)
+{
+ static struct ctk_widget *w;
+ static unsigned char i;
+
+
+ w = (struct ctk_widget *)data;
+ if(s == ctk_signal_button_activate) {
+ if(w == (struct ctk_widget *)&backbutton) {
+ scrolly = 0;
+ run = 1;
+
+ --history_last;
+ if(history_last > HISTORY_SIZE) {
+ history_last = HISTORY_SIZE - 1;
+ }
+ memcpy(url, history[history_last], WWW_CONF_MAX_URLLEN);
+ open_url();
+ CTK_WIDGET_FOCUS(&mainwindow, &backbutton);
+ } else if(w == (struct ctk_widget *)&downbutton) {
+ run = 1;
+ open_url();
+ CTK_WIDGET_FOCUS(&mainwindow, &downbutton);
+ } else if(w == (struct ctk_widget *)&gobutton) {
+ scrolly = 0;
+ run = 1;
+ log_back();
+ memcpy(url, editurl, WWW_CONF_MAX_URLLEN);
+ petsciiconv_toascii(url, WWW_CONF_MAX_URLLEN);
+ open_url();
+ CTK_WIDGET_FOCUS(&mainwindow, &gobutton);
+ } else if(w == (struct ctk_widget *)&stopbutton) {
+ run = 0;
+ webclient_close();
+#if WWW_CONF_FORMS
+ } else {
+ /* Check form buttons */
+ for(i = 0; i < pagewidgetptr; ++i) {
+ if(&pagewidgets[i] == w) {
+ formsubmit(&pagewidgetattribs[i].form);
+ /* show_statustext(pagewidgetattribs[i].form.formaction);*/
+ /* PRINTF(("Formaction %s formname %s inputname %s\n",
+ pagewidgetattribs[i].form.formaction,
+ pagewidgetattribs[i].form.formname,
+ pagewidgetattribs[i].form.inputname));*/
+ break;
+ }
+ }
+#endif /* WWW_CONF_FORMS */
+ }
+ } else if(s == ctk_signal_hyperlink_activate) {
+ log_back();
+ open_link(w->widget.hyperlink.url);
+ CTK_WIDGET_FOCUS(&mainwindow, &stopbutton);
+ run = 1;
+ } else if(s == ctk_signal_hyperlink_hover) {
+ strncpy(statustexturl, w->widget.hyperlink.url,
+ sizeof(statustexturl));
+ petsciiconv_topetscii(statustexturl, sizeof(statustexturl));
+ show_statustext(statustexturl);
+ } else if(s == resolv_signal_found) {
+ /* Either found a hostname, or not. */
+ if((char *)data != NULL &&
+ resolv_lookup((char *)data) != NULL) {
+ open_url();
+ } else {
+ show_statustext("Host not found.");
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+/* set_url():
+ *
+ * Constructs an URL from the arguments and puts it into the global
+ * "url" variable and the visible "editurl" (which is shown in the URL
+ * text entry widget in the browser window).
+ */
+static void
+set_url(char *host, u16_t port, char *file)
+{
+ char *urlptr;
+
+ memset(url, 0, WWW_CONF_MAX_URLLEN);
+
+ if(strncmp(file, http_http, 7) == 0) {
+ strncpy(url, file, sizeof(url));
+ } else {
+ strncpy(url, http_http, 7);
+ urlptr = url + 7;
+ strcpy(urlptr, host);
+ urlptr += strlen(host);
+ strcpy(urlptr, file);
+ }
+
+ show_url();
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_aborted():
+ *
+ * Callback function. Called from the webclient when the HTTP
+ * connection was abruptly aborted.
+ */
+void
+webclient_aborted(void)
+{
+ show_statustext("Connection reset by peer");
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_timedout():
+ *
+ * Callback function. Called from the webclient when the HTTP
+ * connection timed out.
+ */
+void
+webclient_timedout(void)
+{
+ show_statustext("Connection timed out");
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_closed():
+ *
+ * Callback function. Called from the webclient when the HTTP
+ * connection was closed after a request from the "webclient_close()"
+ * function. .
+ */
+void
+webclient_closed(void)
+{
+ show_statustext("Stopped.");
+ petsciiconv_topetscii(&webpage[(WEBPAGE_HEIGHT - 1) *
+ WEBPAGE_WIDTH], WEBPAGE_WIDTH);
+ redraw_window();
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_closed():
+ *
+ * Callback function. Called from the webclient when the HTTP
+ * connection is connected.
+ */
+void
+webclient_connected(void)
+{
+ x = nextwordptr = 0;
+ starty = scrolly;
+ nextword[0] = 0;
+
+ if(scrolly == 0) {
+ clear_page();
+ redraw_window();
+ }
+
+ show_statustext("Request sent...");
+ set_url(webclient_hostname(), webclient_port(), webclient_filename());
+
+#if WWW_CONF_RENDERSTATE
+ renderstate = HTMLPARSER_RENDERSTATE_NONE;
+#endif /* WWW_CONF_RENDERSTATE */
+ htmlparser_init();
+}
+/*-----------------------------------------------------------------------------------*/
+/* scroll():
+ *
+ * Scrolls the entire web page display (text and hyperlinks) one line
+ * upwards.
+ */
+static void
+scroll(void)
+{
+ unsigned char i;
+ unsigned char lptr, linkptrtmp;
+ struct ctk_widget *linksptr;
+ char *statustexttext;
+ struct ctk_widget *focuswidget;
+
+ /* Scroll text up. */
+ memcpy(webpage, &webpage[WEBPAGE_WIDTH],
+ (WEBPAGE_HEIGHT - 1) * WEBPAGE_WIDTH);
+
+ /* Clear last line of text. */
+ memset(&webpage[(WEBPAGE_HEIGHT - 1) * WEBPAGE_WIDTH],
+ ' ', WEBPAGE_WIDTH);
+
+ /* Scroll links up. */
+
+ lptr = 0;
+ linksptr = pagewidgets;
+ for(i = 0; i < pagewidgetptr; ++i) {
+ /* First, check which links that scroll off the top of the page
+ and should be removed. */
+ if(CTK_WIDGET_YPOS(linksptr) == 3) {
+ lptr = i + 1;
+ } else {
+ /* Else, move them upward one notch. */
+
+ /* XXX: this is really a hack! These values should not be used
+ like this, but should be obtained and set using some CTK API
+ function. */
+ linksptr->widget.hyperlink.text -= WEBPAGE_WIDTH;
+
+ --(linksptr->y);
+ }
+ ++linksptr;
+ }
+
+ /* See if there are any links that scroll off the top. */
+ if(lptr != 0) {
+ memcpy(pagewidgets, &pagewidgets[lptr],
+ sizeof(struct ctk_widget) * (MAX_NUMPAGEWIDGETS - lptr));
+ memcpy(pagewidgetattribs, &pagewidgetattribs[lptr],
+ sizeof(union pagewidgetattrib) * (MAX_NUMPAGEWIDGETS - lptr));
+
+ /* Compute new value of linkptr and tuck it away in
+ linkptrtmp. make_window() destroys linkptr, so we need to
+ restore it after the call. */
+ linkptrtmp = pagewidgetptr - lptr;
+
+ /* XXX: hack - these values should *not* be obtained this way, but
+ through some CTK API instead! */
+ statustexttext = statustext.text;
+ focuswidget = mainwindow.focused;
+ ctk_window_clear(&mainwindow);
+ make_window();
+ CTK_WIDGET_FOCUS(&mainwindow, focuswidget);
+ show_statustext(statustexttext);
+
+ pagewidgetptr = linkptrtmp;
+
+ linksptr = pagewidgets;
+ for(i = 0; i < pagewidgetptr; ++i) {
+ if(linksptr->type == CTK_WIDGET_HYPERLINK) {
+ linksptr->widget.hyperlink.url -= lptr *
+ sizeof(union pagewidgetattrib);
+ }
+ CTK_WIDGET_ADD(&mainwindow, linksptr);
+ ++linksptr;
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static char tmpcenterline[WEBPAGE_WIDTH];
+/* inc_y():
+ *
+ * Called from the rendering code when it is time to move on line
+ * downwards.
+ */
+static void
+inc_y(void)
+{
+ unsigned char spaces, i;
+ char *cptr;
+ struct ctk_widget *linksptr;
+
+ if(starty > 0) {
+ --starty;
+ } else {
+#if WWW_CONF_RENDERSTATE
+ /* Check if current line should be centered and if so, center
+ it. */
+ if(renderstate & HTMLPARSER_RENDERSTATE_CENTER) {
+ cptr = &webpage[(WEBPAGE_HEIGHT - 0) * WEBPAGE_WIDTH - 1];
+ for(spaces = 0; spaces < WEBPAGE_WIDTH; ++spaces) {
+ if(*cptr-- != ' ') {
+ break;
+ }
+ }
+
+ spaces = spaces / 2;
+
+ strncpy(tmpcenterline,
+ &webpage[(WEBPAGE_HEIGHT - 1) *
+ WEBPAGE_WIDTH],
+ WEBPAGE_WIDTH);
+ strncpy(&webpage[(WEBPAGE_HEIGHT - 1) *
+ WEBPAGE_WIDTH] + spaces,
+ tmpcenterline,
+ WEBPAGE_WIDTH - spaces);
+ memset(&webpage[(WEBPAGE_HEIGHT - 1) *
+ WEBPAGE_WIDTH], ' ', spaces);
+
+ linksptr = pagewidgets;
+ for(i = 0; i < pagewidgetptr; ++i) {
+ if(CTK_WIDGET_YPOS(linksptr) == 3 + WEBPAGE_HEIGHT - 1) {
+ linksptr->x += spaces;
+ linksptr->widget.hyperlink.text += spaces;
+ }
+ ++linksptr;
+ }
+ }
+#endif /* WWW_CONF_RENDERSTATE */
+
+ petsciiconv_topetscii(&webpage[(WEBPAGE_HEIGHT - 1) *
+ WEBPAGE_WIDTH], WEBPAGE_WIDTH);
+ redraw_window();
+ scroll();
+ ++scrolly;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_datahandler():
+ *
+ * Callback function. Called from the webclient module when HTTP data
+ * has arrived.
+ */
+void
+webclient_datahandler(char *data, u16_t len)
+{
+ if(len > 0) {
+ /* if(strcmp(webclient_mimetype(), http_texthtml) == 0) {*/
+ count = (count + 1) & 3;
+ show_statustext(receivingmsgs[count]);
+ htmlparser_parse(data, len);
+ /* } else {
+ show_statustext("Receiving non-HTML data...");
+ }*/
+ } else {
+ /* Clear remaining parts of page. */
+ run = 0;
+ }
+
+ if(data == NULL) {
+ run = 0;
+ show_statustext("Done.");
+ petsciiconv_topetscii(&webpage[(WEBPAGE_HEIGHT - 1) *
+ WEBPAGE_WIDTH], WEBPAGE_WIDTH);
+ redraw_window();
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+/* output_word():
+ *
+ * Called from the rendering code when a full word has been received
+ * and should be put on screen.
+ */
+static void
+output_word(char c)
+{
+ char *webpageptr;
+
+ if(nextwordptr == 0) {
+ if(c == ISO_nl) {
+ x = 0;
+ inc_y();
+ }
+ return;
+ }
+
+ if(x + nextwordptr > WEBPAGE_WIDTH) {
+ inc_y();
+ x = 0;
+ }
+
+ nextword[nextwordptr] = 0;
+ if(starty == 0) {
+ webpageptr = &webpage[(WEBPAGE_HEIGHT - 1) * WEBPAGE_WIDTH + x];
+ if(nextwordptr > 0) {
+ strcpy(webpageptr, nextword);
+ }
+ webpageptr[nextwordptr] = ' ';
+ }
+ if(c == ISO_nl) {
+ x = 0;
+ inc_y();
+ } else {
+ x += nextwordptr + 1;
+ }
+ nextwordptr = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static void *
+add_pagewidget(char *text, unsigned char type,
+ unsigned char border)
+{
+ static unsigned char len, maxwidth;
+ static unsigned char *webpageptr;
+ static void *dataptr;
+ register struct ctk_widget *lptr;
+
+ len = strlen(text);
+
+ if(len + border == 0) {
+ return NULL;
+ }
+
+ maxwidth = WEBPAGE_WIDTH - (1 + 2 * border);
+
+ /* If the text of the link is too long so that it does not fit into
+ the width of the current window, counting from the current x
+ coordinate, we first try to jump to the next line. */
+ if(len + x > maxwidth) {
+ output_word(ISO_nl);
+ }
+
+ /* If the text of the link still is too long, we just chop it off!
+ XXX: this is not really the right thing to do, we should probably
+ either make the link a multiline button, or add multiple
+ buttons. But this will do for now. */
+ if(len > maxwidth) {
+ text[maxwidth] = 0;
+ len = maxwidth;
+ }
+
+ dataptr = NULL;
+
+ if(starty == 0) {
+ webpageptr = &webpage[(WEBPAGE_HEIGHT - 1) * WEBPAGE_WIDTH + x];
+ /* To save memory, we'll copy the widget text to the web page
+ drawing area and reference it from there. */
+ webpageptr[0] = 0;
+ webpageptr += border;
+ strncpy(webpageptr, text, len);
+ webpageptr[len] = 0;
+ webpageptr[len + border] = ' ';
+ if(pagewidgetptr < MAX_NUMPAGEWIDGETS) {
+ dataptr = &pagewidgetattribs[pagewidgetptr];
+ lptr = &pagewidgets[pagewidgetptr];
+
+ switch(type) {
+ case CTK_WIDGET_HYPERLINK:
+ CTK_HYPERLINK_NEW((struct ctk_hyperlink *)lptr, x,
+ WEBPAGE_HEIGHT + 2, len,
+ webpageptr, dataptr);
+ break;
+ case CTK_WIDGET_BUTTON:
+ CTK_BUTTON_NEW((struct ctk_button *)lptr, x,
+ WEBPAGE_HEIGHT + 2, len,
+ webpageptr);
+ ((struct formattribs *)dataptr)->inputvalue = webpageptr;
+ break;
+ case CTK_WIDGET_TEXTENTRY:
+ CTK_TEXTENTRY_NEW((struct ctk_textentry *)lptr,
+ x, WEBPAGE_HEIGHT + 2, len, 1,
+ webpageptr, len);
+ ((struct formattribs *)dataptr)->inputvalue = webpageptr;
+ break;
+ }
+ CTK_WIDGET_ADD(&mainwindow, lptr);
+
+ ++pagewidgetptr;
+ }
+ }
+ /* Increase the x coordinate with the length of the link text plus
+ the extra space behind it and the CTK button markers. */
+ x += len + 1 + 2 * border;
+
+ if(x >= WEBPAGE_WIDTH) {
+ inc_y();
+ x = 0;
+ }
+
+ return dataptr;
+}
+/*-----------------------------------------------------------------------------------*/
+/* htmlparser_link:
+ *
+ * Callback function. Will be called when the HTML parser has parsed a
+ * link. We will put a CTK hyperlink widget at the appropriate position
+ * in the window.
+ */
+void
+htmlparser_link(char *text, char *url)
+{
+ static unsigned char *linkurlptr;
+
+ linkurlptr = add_pagewidget(text, CTK_WIDGET_HYPERLINK, 0);
+ if(linkurlptr != NULL &&
+ strlen(url) < WWW_CONF_MAX_URLLEN) {
+ strcpy(linkurlptr, url);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+/* htmlparser_char():
+ *
+ * Callback function. Called by the HTML parser module for every
+ * printable character in the HTML file.
+ */
+void
+htmlparser_char(char c)
+{
+ if(c == ' ' ||
+ c == ISO_nl) {
+ output_word(c);
+ } else if(c != 0) {
+ nextword[nextwordptr] = c;
+ if(nextwordptr < WEBPAGE_WIDTH) {
+ ++nextwordptr;
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+#if WWW_CONF_RENDERSTATE
+void
+htmlparser_renderstate(unsigned char s)
+{
+ if((s & HTMLPARSER_RENDERSTATE_STATUSMASK) ==
+ HTMLPARSER_RENDERSTATE_BEGIN) {
+ renderstate |= s & ~HTMLPARSER_RENDERSTATE_STATUSMASK;
+ } else {
+ renderstate &= ~(s & ~HTMLPARSER_RENDERSTATE_STATUSMASK);
+ }
+}
+#endif /* WWW_CONF_RENDERSTATE */
+
+#if WWW_CONF_FORMS
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_submitbutton(char *text, char *name,
+ char *formname, char *formaction)
+{
+ register struct formattribs *form;
+ form = add_pagewidget(text, CTK_WIDGET_BUTTON, 1);
+ if(form != NULL) {
+ strncpy(form->formaction, formaction, WWW_CONF_MAX_FORMACTIONLEN);
+ strncpy(form->formname, formname, WWW_CONF_MAX_FORMNAMELEN);
+ strncpy(form->inputname, name, WWW_CONF_MAX_INPUTNAMELEN);
+ form->inputtype = FORMINPUTTYPE_SUBMITBUTTON;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_inputfield(char *text, char *name,
+ char *formname, char *formaction)
+{
+ register struct formattribs *form;
+
+ form = add_pagewidget(text, CTK_WIDGET_TEXTENTRY, 1);
+ if(form != NULL) {
+ strncpy(form->formaction, formaction, WWW_CONF_MAX_FORMACTIONLEN);
+ strncpy(form->formname, formname, WWW_CONF_MAX_FORMNAMELEN);
+ strncpy(form->inputname, name, WWW_CONF_MAX_INPUTNAMELEN);
+ form->inputtype = FORMINPUTTYPE_INPUTFIELD;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+formsubmit(struct formattribs *attribs)
+{
+ unsigned char i, j;
+ char *urlptr, *valueptr;
+ struct formattribs *faptr;
+
+ urlptr = &tmpurl[0];
+
+ strncpy(urlptr, attribs->formaction, WWW_CONF_MAX_URLLEN);
+ tmpurl[WWW_CONF_MAX_URLLEN] = 0;
+ urlptr += strlen(urlptr);
+ *urlptr = ISO_questionmark;
+ ++urlptr;
+
+
+ /* Construct an URL by finding all input field forms with the same
+ formname as the current submit button, and add the submit button
+ URL stuff as well. */
+ for(i = 0; i < pagewidgetptr; ++i) {
+ if(urlptr - &tmpurl[0] >= WWW_CONF_MAX_URLLEN) {
+ break;
+ }
+
+ faptr = &pagewidgetattribs[i].form;
+
+ if(strcmp(attribs->formaction, faptr->formaction) == 0 &&
+ strcmp(attribs->formname, faptr->formname) == 0 &&
+ (faptr->inputtype == FORMINPUTTYPE_INPUTFIELD ||
+ faptr == attribs)) {
+
+ /* Copy the name of the input field into the URL and append a
+ questionmark. */
+ strncpy(urlptr, faptr->inputname, WWW_CONF_MAX_URLLEN - strlen(tmpurl));
+ tmpurl[WWW_CONF_MAX_URLLEN] = 0;
+ urlptr += strlen(urlptr);
+ *urlptr = ISO_eq;
+ ++urlptr;
+
+ /* Convert and copy the contents of the input field to the URL
+ and append an ampersand. */
+ valueptr = pagewidgets[i].widget.textentry.text;
+ petsciiconv_toascii(valueptr, WWW_CONF_MAX_INPUTVALUELEN);
+ for(j = 0; j < WWW_CONF_MAX_INPUTVALUELEN; ++j) {
+ if(urlptr - &tmpurl[0] >= WWW_CONF_MAX_URLLEN) {
+ break;
+ }
+ *urlptr = *valueptr;
+ if(*urlptr == ISO_space) {
+ *urlptr = ISO_plus;
+ }
+ if(*urlptr == 0) {
+ break;
+ }
+ ++urlptr;
+ ++valueptr;
+ }
+
+ *urlptr = ISO_ampersand;
+ ++urlptr;
+ }
+ }
+ --urlptr;
+ *urlptr = 0;
+ /* PRINTF(("formsubmit: URL '%s'\n", tmpurl));*/
+ open_link(tmpurl);
+}
+/*-----------------------------------------------------------------------------------*/
+#endif /* WWW_CONF_FORMS */
diff --git a/contiki/apps/www.h b/contiki/apps/www.h
new file mode 100644
index 0000000..87a4a34
--- /dev/null
+++ b/contiki/apps/www.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: www.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+#ifndef __WWW_H__
+#define __WWW_H__
+
+void www_init(void);
+
+#endif /* __WWW_H__ */
diff --git a/contiki/ctk/ctk-conf.h b/contiki/ctk/ctk-conf.h
new file mode 100644
index 0000000..5c5c0dc
--- /dev/null
+++ b/contiki/ctk/ctk-conf.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ctk" console GUI toolkit for cc65
+ *
+ * $Id: ctk-conf.h,v 1.1 2003/03/19 14:13:33 adamdunkels Exp $
+ *
+ */
+
+#ifndef __CTK_CONF_H__
+#define __CTK_CONF_H__
+
+/*
+ * This file is used for setting various compile time settings for the
+ * CTK GUI toolkit.
+*/
+
+/* Defines which key that is to be used for activating the menus */
+#define CTK_CONF_MENU_KEY CH_F1
+
+/* Defines which key that is to be used for switching the frontmost
+ window. */
+#define CTK_CONF_WINDOWSWITCH_KEY CH_F3
+
+/* Toggles support for desktop icons. */
+#define CTK_CONF_ICONS 0 /* 107 bytes */
+
+/* Toggles support for movable windows. */
+#define CTK_CONF_WINDOWMOVE 0 /* 333 bytes */
+
+/* Toggles support for closable windows. */
+#define CTK_CONF_WINDOWCLOSE 0 /* 14 bytes */
+
+/* Toggles support for multiline text entry editing. */
+#define CTK_CONF_TEXTENTRY_MULTILINE 0 /* 118 bytes */
+
+/* Toggles support for menus. */
+#define CTK_CONF_MENUS 0 /* 1384 bytes */
+
+/* Defines the default width of a menu. */
+#define CTK_CONF_MENUWIDTH 16
+/* The maximum number of menu items in each menu. */
+#define CTK_CONF_MAXMENUITEMS 10
+
+#endif /* __CTK_CONF_H__ */
diff --git a/contiki/ctk/ctk-draw.h b/contiki/ctk/ctk-draw.h
new file mode 100644
index 0000000..8549e23
--- /dev/null
+++ b/contiki/ctk/ctk-draw.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ctk" console GUI toolkit for cc65
+ *
+ * $Id: ctk-draw.h,v 1.1 2003/03/19 14:13:34 adamdunkels Exp $
+ *
+ */
+
+#ifndef __CTK_DRAW_H__
+#define __CTK_DRAW_H__
+
+#include "ctk.h"
+
+#include "ctk-arch.h"
+
+
+void ctk_draw_init(void);
+
+void ctk_draw_clear(unsigned char clipy1, unsigned char clipy2);
+void ctk_draw_clear_window(struct ctk_window *window,
+ unsigned char focus,
+ unsigned char clipy1, unsigned char clipy2);
+
+void ctk_draw_widget(struct ctk_widget *w,
+ unsigned char focus,
+ unsigned char clipy1,
+ unsigned char clipy2);
+
+void ctk_draw_window(struct ctk_window *window,
+ unsigned char focus,
+ unsigned char clipy1,
+ unsigned char clipy2);
+
+void ctk_draw_dialog(struct ctk_window *dialog);
+
+void ctk_draw_menus(struct ctk_menus *menus);
+
+
+
+/* Returns width and height of screen. */
+unsigned char ctk_draw_width(void);
+unsigned char ctk_draw_height(void);
+
+
+#endif /* __CTK_DRAW_H__ */
diff --git a/contiki/ctk/ctk.c b/contiki/ctk/ctk.c
new file mode 100644
index 0000000..2c70085
--- /dev/null
+++ b/contiki/ctk/ctk.c
@@ -0,0 +1,1120 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ctk" console GUI toolkit for cc65
+ *
+ * $Id: ctk.c,v 1.1 2003/03/19 14:13:34 adamdunkels Exp $
+ *
+ */
+
+#include "ek.h"
+#include "dispatcher.h"
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ctk-conf.h"
+
+static unsigned char height, width;
+
+static unsigned char mode;
+
+static struct ctk_window desktop_window;
+static struct ctk_window *windows;
+static struct ctk_window *dialog;
+
+#if CTK_CONF_MENUS
+static struct ctk_menus menus;
+static struct ctk_menu *lastmenu;
+static struct ctk_menu desktopmenu;
+#endif /* CTK_CONF_MENUS */
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+
+#define REDRAW_NONE 0
+#define REDRAW_ALL 1
+#define REDRAW_FOCUS 2
+#define REDRAW_WIDGETS 4
+#define REDRAW_MENUS 8
+#define REDRAW_MENUPART 16
+
+#define MAX_REDRAWWIDGETS 4
+static unsigned char redraw;
+static struct ctk_widget *redraw_widgets[MAX_REDRAWWIDGETS];
+static unsigned char redraw_widgetptr;
+static unsigned char maxnitems;
+
+static unsigned char iconx, icony;
+#define ICONX_START (width - 5)
+#define ICONY_START 0
+#define ICONX_DELTA -8
+#define ICONY_DELTA 5
+#define ICONY_MAX (height - 4)
+
+static void idle(void);
+static void sighandler(ek_signal_t s, ek_data_t data);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("CTK Contiki GUI", idle, sighandler, NULL)};
+static ek_id_t ctkid;
+
+
+ek_signal_t ctk_signal_keypress,
+ ctk_signal_timer,
+ ctk_signal_button_activate,
+ ctk_signal_button_hover,
+ ctk_signal_hyperlink_activate,
+ ctk_signal_hyperlink_hover,
+ ctk_signal_menu_activate,
+ ctk_signal_window_close;
+
+
+static unsigned short screensaver_timer;
+#define SCREENSAVER_TIMEOUT (5*60)
+
+#if CTK_CONF_MENUS
+/*-----------------------------------------------------------------------------------*/
+/* make_desktopmenu(void)
+ *
+ * Creates the leftmost menu, "Desktop". Since the desktop menu
+ * contains the list of all open windows, this function will be called
+ * whenever a window is opened or closed.
+ */
+static void
+make_desktopmenu(void)
+{
+ struct ctk_window *w;
+
+ desktopmenu.nitems = 0;
+
+ if(windows == NULL) {
+ ctk_menuitem_add(&desktopmenu, "(No windows)");
+ } else {
+ for(w = windows; w != NULL; w = w->next) {
+ ctk_menuitem_add(&desktopmenu, w->title);
+ }
+ }
+}
+#endif /* CTK_CONF_MENUS */
+/*-----------------------------------------------------------------------------------*/
+/* ctk_init(void)
+ *
+ * Initializes CTK. Must be called before any other CTK function.
+ */
+void
+ctk_init(void)
+{
+ ctkid = dispatcher_start(&p);
+
+ windows = NULL;
+ dialog = NULL;
+
+#if CTK_CONF_MENUS
+ ctk_menu_new(&desktopmenu, "Desktop");
+ make_desktopmenu();
+ menus.menus = menus.desktopmenu = &desktopmenu;
+#endif /* CTK_CONF_MENUS */
+
+ ctk_draw_init();
+
+ height = ctk_draw_height();
+ width = ctk_draw_width();
+
+ desktop_window.active = NULL;
+
+
+ ctk_signal_keypress = dispatcher_sigalloc();
+ ctk_signal_timer = dispatcher_sigalloc();
+ ctk_signal_button_activate = dispatcher_sigalloc();
+ ctk_signal_button_hover = dispatcher_sigalloc();
+ ctk_signal_hyperlink_activate = dispatcher_sigalloc();
+ ctk_signal_hyperlink_hover = dispatcher_sigalloc();
+ ctk_signal_menu_activate = dispatcher_sigalloc();
+ ctk_signal_window_close = dispatcher_sigalloc();
+
+ dispatcher_listen(ctk_signal_timer);
+ dispatcher_timer(ctk_signal_timer, NULL, CLK_TCK);
+
+ mode = CTK_MODE_NORMAL;
+
+ iconx = ICONX_START;
+ icony = ICONY_START;
+
+}
+/*-----------------------------------------------------------------------------------*/
+/* void ctk_mode_set()
+ */
+void
+ctk_mode_set(unsigned char m) {
+ mode = m;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_mode_get(void) {
+ return mode;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_icon_add(register struct ctk_widget *icon,
+ ek_id_t id)
+{
+#if CTK_CONF_ICONS
+ icon->x = iconx;
+ icon->y = icony;
+ icon->widget.icon.owner = id;
+
+ icony += ICONY_DELTA;
+ if(icony >= ICONY_MAX) {
+ icony = ICONY_START;
+ iconx += ICONX_DELTA;
+ }
+
+ ctk_widget_add(&desktop_window, icon);
+#endif /* CTK_CONF_ICONS */
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_dialog_open(struct ctk_window *d)
+{
+ dialog = d;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_dialog_close(void)
+{
+ dialog = NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_open(register struct ctk_window *w)
+{
+ struct ctk_window *w2;
+
+ /* Check if already open. */
+ for(w2 = windows; w2 != w && w2 != NULL; w2 = w2->next);
+ if(w2 == NULL) {
+ /* Not open, so we add it at the head of the list of open
+ windows. */
+ w->next = windows;
+ if(windows != NULL) {
+ windows->prev = w;
+ }
+ windows = w;
+ w->prev = NULL;
+ } else {
+ /* Window already open, so we move it to the front of the windows
+ list. */
+ if(w != windows) {
+ if(w->next != NULL) {
+ w->next->prev = w->prev;
+ }
+ if(w->prev != NULL) {
+ w->prev->next = w->next;
+ }
+ w->next = windows;
+ windows->prev = w;
+ windows = w;
+ w->prev = NULL;
+ }
+ }
+
+#if CTK_CONF_MENUS
+ /* Recreate the Desktop menu's window entries.*/
+ make_desktopmenu();
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_close(struct ctk_window *w)
+{
+ struct ctk_window *w2;
+
+ if(w == NULL) {
+ return;
+ }
+
+ /* Check if the window to be closed is the first window on the
+ list. */
+ if(w == windows) {
+ windows = w->next;
+ if(windows != NULL) {
+ windows->prev = NULL;
+ }
+ w->next = w->prev = NULL;
+ } else {
+ /* Otherwise we step through the list until we find the window
+ before the one to be closed. We then redirect its ->next
+ pointer and its ->next->prev. */
+ for(w2 = windows; w2->next != w; w2 = w2->next);
+
+ if(w->next != NULL) {
+ w->next->prev = w->prev;
+ }
+ w2->next = w->next;
+
+ w->next = w->prev = NULL;
+ }
+
+#if CTK_CONF_MENUS
+ /* Recreate the Desktop menu's window entries.*/
+ make_desktopmenu();
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+make_windowbuttons(register struct ctk_window *window)
+{
+#if CTK_CONF_WINDOWMOVE
+ CTK_BUTTON_NEW(&window->titlebutton, 0, -1, window->titlelen, window->title);
+#else
+ CTK_LABEL_NEW(&window->titlebutton, 0, -1, window->titlelen, 1, window->title);
+#endif /* CTK_CONF_WINDOWMOVE */
+ CTK_WIDGET_ADD(window, &window->titlebutton);
+
+
+#if CTK_CONF_WINDOWCLOSE
+ CTK_BUTTON_NEW(&window->closebutton, window->w - 3, -1, 1, "x");
+#else
+ CTK_LABEL_NEW(&window->closebutton, window->w - 4, -1, 3, 1, " ");
+#endif /* CTK_CONF_WINDOWCLOSE */
+ CTK_WIDGET_ADD(window, &window->closebutton);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_clear(struct ctk_window *window)
+{
+ window->active = window->inactive = window->focused = NULL;
+
+ make_windowbuttons(window);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_menu_add(struct ctk_menu *menu)
+{
+#if CTK_CONF_MENUS
+ struct ctk_menu *m;
+
+ if(lastmenu == NULL) {
+ lastmenu = menu;
+ }
+
+ for(m = menus.menus; m->next != NULL; m = m->next) {
+ if(m == menu) {
+ return;
+ }
+ }
+ m->next = menu;
+ menu->next = NULL;
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_menu_remove(struct ctk_menu *menu)
+{
+#if CTK_CONF_MENUS
+ struct ctk_menu *m;
+
+ for(m = menus.menus; m->next != NULL; m = m->next) {
+ if(m->next == menu) {
+ m->next = menu->next;
+ return;
+ }
+ }
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+do_redraw_all(unsigned char clipy1, unsigned char clipy2)
+{
+ struct ctk_window *w;
+ struct ctk_widget *widget;
+
+ if(mode != CTK_MODE_NORMAL &&
+ mode != CTK_MODE_WINDOWMOVE) {
+ return;
+ }
+
+ ctk_draw_clear(clipy1, clipy2);
+
+ /* Draw widgets in root window */
+ for(widget = desktop_window.active;
+ widget != NULL; widget = widget->next) {
+ ctk_draw_widget(widget, 0, clipy1, clipy2);
+ }
+
+ /* Draw windows */
+ if(windows != NULL) {
+ /* Find the last window.*/
+ for(w = windows; w->next != NULL; w = w->next);
+
+ /* Draw the windows from back to front. */
+ for(; w != windows; w = w->prev) {
+ ctk_draw_clear_window(w, 0, clipy1, clipy2);
+ ctk_draw_window(w, 0, clipy1, clipy2);
+ }
+ /* Draw focused window */
+ ctk_draw_clear_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
+ ctk_draw_window(windows, CTK_FOCUS_WINDOW, clipy1, clipy2);
+ }
+
+ /* Draw dialog (if any) */
+ if(dialog != NULL) {
+ ctk_draw_dialog(dialog);
+ }
+
+#if CTK_CONF_MENUS
+ ctk_draw_menus(&menus);
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_redraw(void)
+{
+ if(DISPATCHER_CURRENT() == ctkid) {
+ if(mode == CTK_MODE_NORMAL ||
+ mode == CTK_MODE_WINDOWMOVE) {
+ do_redraw_all(1, height);
+ }
+ } else {
+ redraw |= REDRAW_ALL;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_redraw(struct ctk_window *w)
+{
+ /* Only redraw the window if it is a dialog or if it is the foremost
+ window. */
+ if(mode != CTK_MODE_NORMAL) {
+ return;
+ }
+
+ if(w == dialog) {
+ ctk_draw_dialog(w);
+ } else if(dialog == NULL &&
+#if CTK_CONF_MENUS
+ menus.open == NULL &&
+#endif /* CTK_CONF_MENUS */
+ windows == w) {
+ ctk_draw_window(w, CTK_FOCUS_WINDOW,
+ 0, height);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+window_new(register struct ctk_window *window,
+ unsigned char w, unsigned char h,
+ char *title)
+{
+ window->x = window->y = 0;
+ window->w = w;
+ window->h = h;
+ window->title = title;
+ if(title != NULL) {
+ window->titlelen = strlen(title);
+ } else {
+ window->titlelen = 0;
+ }
+ window->next = window->prev = NULL;
+ window->owner = DISPATCHER_CURRENT();
+ window->active = window->inactive = window->focused = NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_new(struct ctk_window *window,
+ unsigned char w, unsigned char h,
+ char *title)
+{
+ window_new(window, w, h, title);
+
+ make_windowbuttons(window);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_dialog_new(register struct ctk_window *window,
+ unsigned char w, unsigned char h)
+{
+ window_new(window, w, h, NULL);
+
+ window->x = (width - w) / 2;
+ window->y = (height - h - 1) / 2;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_menu_new(register struct ctk_menu *menu,
+ char *title)
+{
+#if CTK_CONF_MENUS
+ menu->next = NULL;
+ menu->title = title;
+ menu->titlelen = strlen(title);
+ menu->active = 0;
+ menu->nitems = 0;
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_menuitem_add(register struct ctk_menu *menu,
+ char *name)
+{
+#if CTK_CONF_MENUS
+ if(menu->nitems == CTK_CONF_MAXMENUITEMS) {
+ return 0;
+ }
+ menu->items[menu->nitems].title = name;
+ menu->items[menu->nitems].titlelen = strlen(name);
+ return menu->nitems++;
+#else
+ return 0;
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+add_redrawwidget(struct ctk_widget *w)
+{
+ static unsigned char i;
+
+ if(redraw_widgetptr == MAX_REDRAWWIDGETS) {
+ redraw |= REDRAW_FOCUS;
+ } else {
+ redraw |= REDRAW_WIDGETS;
+ /* Check if it is in the queue already. If so, we don't add it
+ again. */
+ for(i = 0; i < redraw_widgetptr; ++i) {
+ if(redraw_widgets[i] == w) {
+ return;
+ }
+ }
+ redraw_widgets[redraw_widgetptr++] = w;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_widget_redraw(struct ctk_widget *widget)
+{
+ struct ctk_window *window;
+
+ if(mode != CTK_MODE_NORMAL) {
+ return;
+ }
+
+ /* If this function isn't called by CTK itself, we only queue the
+ redraw request. */
+ if(DISPATCHER_CURRENT() != ctkid) {
+ redraw |= REDRAW_WIDGETS;
+ add_redrawwidget(widget);
+ } else {
+
+ /* Only redraw widgets that are in the foremost window. If we
+ would allow redrawing widgets in non-focused windows, we would
+ have to redraw all the windows that cover the non-focused
+ window as well, which would lead to flickering.
+
+ Also, we avoid drawing any widgets when the menus are active.
+ */
+
+#if CTK_CONF_MENUS
+ if(menus.open == NULL)
+#endif /* CTK_CONF_MENUS */
+ {
+ window = widget->window;
+ if(window == dialog) {
+ ctk_draw_widget(widget, CTK_FOCUS_DIALOG, 0, height);
+ } else if(window == windows) {
+ ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
+ } else if(window == &desktop_window) {
+ ctk_draw_widget(widget, 0, 0, height);
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_widget_add(register struct ctk_window *window,
+ register struct ctk_widget *widget)
+{
+ if(widget->type == CTK_WIDGET_LABEL ||
+ widget->type == CTK_WIDGET_SEPARATOR) {
+ widget->next = window->inactive;
+ window->inactive = widget;
+ widget->window = window;
+ } else {
+ widget->next = window->active;
+ window->active = widget;
+ widget->window = window;
+ if(window->focused == NULL) {
+ window->focused = widget;
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+#define UP 0
+#define DOWN 1
+#define LEFT 2
+#define RIGHT 3
+static void
+switch_focus_widget(unsigned char direction)
+{
+ register struct ctk_window *window;
+ register struct ctk_widget *focus;
+ struct ctk_widget *widget;
+
+
+ if(dialog != NULL) {
+ window = dialog;
+ } else {
+ window = windows;
+ }
+
+ /* If there are no windows open, we move focus around between the
+ icons on the root window instead. */
+ if(window == NULL) {
+ window = &desktop_window;
+ }
+
+ focus = window->focused;
+ add_redrawwidget(focus);
+
+ if((direction & 1) == 0) {
+ /* Move focus "up" */
+ focus = focus->next;
+ } else {
+ /* Move focus "down" */
+ for(widget = window->active;
+ widget != NULL; widget = widget->next) {
+ if(widget->next == focus) {
+ break;
+ }
+ }
+ focus = widget;
+ if(focus == NULL) {
+ if(window->active != NULL) {
+ for(focus = window->active;
+ focus->next != NULL; focus = focus->next);
+ }
+ }
+ }
+ if(focus == NULL) {
+ focus = window->active;
+ }
+
+ if(focus != window->focused) {
+ window->focused = focus;
+ /* The operation changed the focus, so we emit a "hover" signal
+ for those widgets that support it. */
+
+ if(window->focused->type == CTK_WIDGET_HYPERLINK) {
+ dispatcher_emit(ctk_signal_hyperlink_hover, window->focused,
+ window->owner);
+ } else if(window->focused->type == CTK_WIDGET_BUTTON) {
+ dispatcher_emit(ctk_signal_button_hover, window->focused,
+ window->owner);
+ }
+
+ add_redrawwidget(window->focused);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_MENUS
+static void
+switch_open_menu(unsigned char rightleft)
+{
+ struct ctk_menu *menu;
+
+ if(rightleft == 0) {
+ /* Move right */
+ for(menu = menus.menus; menu != NULL; menu = menu->next) {
+ if(menu->next == menus.open) {
+ break;
+ }
+ }
+ lastmenu = menus.open;
+ menus.open = menu;
+ if(menus.open == NULL) {
+ for(menu = menus.menus;
+ menu->next != NULL; menu = menu->next);
+ menus.open = menu;
+ }
+ } else {
+ /* Move to left */
+ lastmenu = menus.open;
+ menus.open = menus.open->next;
+ if(menus.open == NULL) {
+ menus.open = menus.menus;
+ }
+ }
+
+ menus.open->active = 0;
+ /* ctk_redraw();*/
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+switch_menu_item(unsigned char updown)
+{
+ register struct ctk_menu *m;
+
+ m = menus.open;
+
+ if(updown == 0) {
+ /* Move up */
+ if(m->active == 0) {
+ m->active = m->nitems - 1;
+ } else {
+ --m->active;
+ if(m->items[m->active].title[0] == '-') {
+ --m->active;
+ }
+ }
+ } else {
+ /* Move down */
+ if(m->active >= m->nitems - 1) {
+ m->active = 0;
+ } else {
+ ++m->active;
+ if(m->items[m->active].title[0] == '-') {
+ ++m->active;
+ }
+ }
+ }
+
+}
+#endif /* CTK_CONF_MENUS */
+/*-----------------------------------------------------------------------------------*/
+static unsigned char
+activate(register struct ctk_widget *w)
+{
+ static unsigned char len;
+
+ if(w->type == CTK_WIDGET_BUTTON) {
+ if(w == (struct ctk_widget *)&windows->closebutton) {
+#if CTK_CONF_WINDOWCLOSE
+ /*dispatcher_emit(ctk_signal_window_close, windows, w->window->owner);*/
+ ctk_window_close(windows);
+ return REDRAW_ALL;
+#endif /* CTK_CONF_WINDOWCLOSE */
+ } else if(w == (struct ctk_widget *)&windows->titlebutton) {
+#if CTK_CONF_WINDOWCLOSE
+ mode = CTK_MODE_WINDOWMOVE;
+#endif /* CTK_CONF_WINDOWCLOSE */
+ } else {
+ dispatcher_emit(ctk_signal_button_activate, w,
+ w->window->owner);
+ }
+#if CTK_CONF_ICONS
+ } else if(w->type == CTK_WIDGET_ICON) {
+ dispatcher_emit(ctk_signal_button_activate, w,
+ w->widget.icon.owner);
+#endif /* CTK_CONF_ICONS */
+ } else if(w->type == CTK_WIDGET_HYPERLINK) {
+ dispatcher_emit(ctk_signal_hyperlink_activate, w,
+ DISPATCHER_BROADCAST);
+ } else if(w->type == CTK_WIDGET_TEXTENTRY) {
+ if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
+ w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
+ len = strlen(w->widget.textentry.text);
+ if(w->widget.textentry.xpos > len) {
+ w->widget.textentry.xpos = len;
+ }
+ } else if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
+ w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
+ }
+ add_redrawwidget(w);
+ return REDRAW_WIDGETS;
+ }
+ return REDRAW_NONE;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+textentry_input(ctk_arch_key_t c,
+ register struct ctk_textentry *t)
+{
+ static char *cptr, *cptr2;
+ static unsigned char len, txpos, typos, tlen;
+
+ txpos = t->xpos;
+ typos = t->ypos;
+ tlen = t->len;
+
+ cptr = &t->text[txpos + typos * tlen];
+
+ switch(c) {
+ case CH_CURS_LEFT:
+ if(txpos > 0) {
+ --txpos;
+ }
+ break;
+
+ case CH_CURS_RIGHT:
+ if(txpos < tlen &&
+ *cptr != 0) {
+ ++txpos;
+ }
+ break;
+
+ case CH_CURS_UP:
+#if CTK_CONF_TEXTENTRY_MULTILINE
+ if(t->h == 1) {
+ txpos = 0;
+ } else {
+ if(typos > 0) {
+ --typos;
+ } else {
+ t->state = CTK_TEXTENTRY_NORMAL;
+ }
+ }
+#else
+ txpos = 0;
+#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
+ break;
+
+ case CH_CURS_DOWN:
+#if CTK_CONF_TEXTENTRY_MULTILINE
+ if(t->h == 1) {
+ txpos = strlen(t->text);
+ } else {
+ if(typos < t->h - 1) {
+ ++typos;
+ } else {
+ t->state = CTK_TEXTENTRY_NORMAL;
+ }
+ }
+#else
+ txpos = strlen(t->text);
+#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
+ break;
+
+ case CH_ENTER:
+#if CTK_CONF_TEXTENTRY_MULTILINE
+ if(t->h == 1) {
+ t->state = CTK_TEXTENTRY_NORMAL;
+ } else {
+ if(typos < t->h - 1) {
+ ++typos;
+ txpos = 0;
+ } else {
+ t->state = CTK_TEXTENTRY_NORMAL;
+ }
+ }
+#else
+ t->state = CTK_TEXTENTRY_NORMAL;
+#endif /* CTK_CONF_TEXTENTRY_MULTILINE */
+ break;
+
+ default:
+ len = tlen - txpos - 1;
+ if(c == CH_DEL) {
+ if(txpos > 0 && len > 0) {
+ strncpy(cptr - 1, cptr,
+ len);
+ *(cptr + len - 1) = 0;
+ --txpos;
+ }
+ } else {
+ if(len > 0) {
+ cptr2 = cptr + len - 1;
+ while(cptr2 + 1 > cptr) {
+ *(cptr2 + 1) = *cptr2;
+ --cptr2;
+ }
+
+ *cptr = c;
+ ++txpos;
+ }
+ }
+ break;
+ }
+
+ t->xpos = txpos;
+ t->ypos = typos;
+}
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_MENUS
+static unsigned char
+menus_input(ctk_arch_key_t c)
+{
+ struct ctk_window *w;
+
+ if(menus.open->nitems > maxnitems) {
+ maxnitems = menus.open->nitems;
+ }
+
+
+ switch(c) {
+ case CH_CURS_RIGHT:
+ switch_open_menu(1);
+
+ return REDRAW_MENUPART;
+
+ case CH_CURS_DOWN:
+ switch_menu_item(1);
+ return REDRAW_MENUS;
+
+ case CH_CURS_LEFT:
+ switch_open_menu(0);
+ return REDRAW_MENUPART;
+
+ case CH_CURS_UP:
+ switch_menu_item(0);
+ return REDRAW_MENUS;
+
+ case CH_ENTER:
+ lastmenu = menus.open;
+ if(menus.open == &desktopmenu) {
+ for(w = windows; w != NULL; w = w->next) {
+ if(w->title == desktopmenu.items[desktopmenu.active].title) {
+ ctk_window_open(w);
+ menus.open = NULL;
+ return REDRAW_ALL;
+ }
+ }
+ } else {
+ dispatcher_emit(ctk_signal_menu_activate, menus.open,
+ DISPATCHER_BROADCAST);
+ }
+ menus.open = NULL;
+ return REDRAW_MENUPART;
+
+ case CH_F1:
+ lastmenu = menus.open;
+ menus.open = NULL;
+ return REDRAW_MENUPART;
+ }
+}
+#endif /* CTK_CONF_MENUS */
+/*-----------------------------------------------------------------------------------*/
+static void
+idle(void)
+{
+ static ctk_arch_key_t c;
+ static unsigned char i;
+ register struct ctk_window *window;
+ register struct ctk_widget *widget;
+
+#if CTK_CONF_MENUS
+ if(menus.open != NULL) {
+ maxnitems = menus.open->nitems;
+ } else {
+ maxnitems = 0;
+ }
+#endif /* CTK_CONF_MENUS */
+
+ if(mode == CTK_MODE_SCREENSAVER) {
+#ifdef CTK_SCREENSAVER_RUN
+ CTK_SCREENSAVER_RUN();
+#endif /* CTK_SCREENSAVER_RUN */
+ if(ctk_arch_keyavail()) {
+ mode = CTK_MODE_NORMAL;
+ ctk_draw_init();
+ ctk_redraw();
+ }
+ } else if(mode == CTK_MODE_NORMAL) {
+ while(ctk_arch_keyavail()) {
+
+ screensaver_timer = 0;
+
+ c = ctk_arch_getkey();
+
+
+ if(dialog != NULL) {
+ window = dialog;
+ } else if(windows != NULL) {
+ window = windows;
+ } else {
+ window = &desktop_window;
+ }
+ widget = window->focused;
+
+
+ if(widget != NULL &&
+ widget->type == CTK_WIDGET_TEXTENTRY &&
+ widget->widget.textentry.state == CTK_TEXTENTRY_EDIT) {
+ textentry_input(c, (struct ctk_textentry *)widget);
+ add_redrawwidget(widget);
+#if CTK_CONF_MENUS
+ } else if(menus.open != NULL) {
+ redraw |= menus_input(c);
+#endif /* CTK_CONF_MENUS */
+ } else {
+ switch(c) {
+ case CH_CURS_RIGHT:
+ switch_focus_widget(RIGHT);
+ break;
+ case CH_CURS_DOWN:
+ switch_focus_widget(DOWN);
+ break;
+ case CH_CURS_LEFT:
+ switch_focus_widget(LEFT);
+ break;
+ case CH_CURS_UP:
+ switch_focus_widget(UP);
+ break;
+ case CH_ENTER:
+ redraw |= activate(widget);
+ break;
+#if CTK_CONF_MENUS
+ case CTK_CONF_MENU_KEY:
+ if(dialog == NULL) {
+ if(lastmenu == NULL) {
+ menus.open = menus.menus;
+ } else {
+ menus.open = lastmenu;
+ }
+ menus.open->active = 0;
+ redraw |= REDRAW_MENUS;
+ }
+ break;
+#endif /* CTK_CONF_MENUS */
+ case CTK_CONF_WINDOWSWITCH_KEY:
+ if(windows != NULL) {
+ for(window = windows; window->next != NULL;
+ window = window->next);
+ ctk_window_open(window);
+ ctk_redraw();
+ }
+ break;
+ default:
+ if(widget->type == CTK_WIDGET_TEXTENTRY) {
+ widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
+ textentry_input(c, (struct ctk_textentry *)widget);
+ add_redrawwidget(widget);
+ } else {
+ dispatcher_emit(ctk_signal_keypress, (void *)c,
+ window->owner);
+ }
+ break;
+ }
+ }
+
+ if(redraw & REDRAW_WIDGETS) {
+ for(i = 0; i < redraw_widgetptr; ++i) {
+ ctk_widget_redraw(redraw_widgets[i]);
+ }
+ redraw &= ~REDRAW_WIDGETS;
+ redraw_widgetptr = 0;
+ }
+ }
+ if(redraw & REDRAW_ALL) {
+ do_redraw_all(1, height);
+#if CTK_CONF_MENUS
+ } else if(redraw & REDRAW_MENUPART) {
+ do_redraw_all(1, maxnitems + 1);
+ } else if(redraw & REDRAW_MENUS) {
+ ctk_draw_menus(&menus);
+#endif /* CTK_CONF_MENUS */
+ } else if(redraw & REDRAW_FOCUS) {
+ if(dialog != NULL) {
+ ctk_window_redraw(dialog);
+ } else if(windows != NULL) {
+ ctk_window_redraw(windows);
+ } else {
+ ctk_window_redraw(&desktop_window);
+ }
+ } else if(redraw & REDRAW_WIDGETS) {
+ for(i = 0; i < redraw_widgetptr; ++i) {
+ ctk_widget_redraw(redraw_widgets[i]);
+ }
+ }
+ redraw = 0;
+ redraw_widgetptr = 0;
+#if CTK_CONF_WINDOWMOVE
+ } else if(mode == CTK_MODE_WINDOWMOVE) {
+
+ redraw = 0;
+
+ window = windows;
+
+ while(mode == CTK_MODE_WINDOWMOVE && ctk_arch_keyavail()) {
+
+ screensaver_timer = 0;
+
+ c = ctk_arch_getkey();
+
+ switch(c) {
+ case CH_CURS_RIGHT:
+ ++window->x;
+ if(window->x + window->w + 1 >= width) {
+ --window->x;
+ }
+ redraw = REDRAW_ALL;
+ break;
+ case CH_CURS_LEFT:
+ if(window->x > 0) {
+ --window->x;
+ }
+ redraw = REDRAW_ALL;
+ break;
+ case CH_CURS_DOWN:
+ ++window->y;
+ if(window->y + window->h + 2 >= height) {
+ --window->y;
+ }
+ redraw = REDRAW_ALL;
+ break;
+ case CH_CURS_UP:
+ if(window->y > 0) {
+ --window->y;
+ }
+ redraw = REDRAW_ALL;
+ break;
+ case CH_ENTER:
+ case CH_ESC:
+ mode = CTK_MODE_NORMAL;
+ redraw = REDRAW_ALL;
+ break;
+ }
+ }
+ if(redraw & REDRAW_ALL) {
+ do_redraw_all(1, height);
+ }
+ redraw = 0;
+#endif /* CTK_CONF_WINDOWMOVE */
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sighandler(ek_signal_t s, ek_data_t data)
+{
+ if(s == ctk_signal_timer) {
+ if(mode == CTK_MODE_NORMAL) {
+ ++screensaver_timer;
+ if(screensaver_timer == SCREENSAVER_TIMEOUT) {
+#ifdef CTK_SCREENSAVER_INIT
+ CTK_SCREENSAVER_INIT();
+#endif /* CTK_SCREENSAVER_INIT */
+ mode = CTK_MODE_SCREENSAVER;
+ screensaver_timer = 0;
+ }
+ }
+ dispatcher_timer(ctk_signal_timer, data, CLK_TCK);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/ctk/ctk.h b/contiki/ctk/ctk.h
new file mode 100644
index 0000000..57779f6
--- /dev/null
+++ b/contiki/ctk/ctk.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ctk" console GUI toolkit for cc65
+ *
+ * $Id: ctk.h,v 1.1 2003/03/19 14:13:34 adamdunkels Exp $
+ *
+ */
+
+#ifndef __CTK_H__
+#define __CTK_H__
+
+#include "ctk-conf.h"
+#include "ek.h"
+
+/* Defintions for the CTK widget types. */
+#define CTK_WIDGET_SEPARATOR 1
+#define CTK_WIDGET_LABEL 2
+#define CTK_WIDGET_BUTTON 3
+#define CTK_WIDGET_HYPERLINK 4
+#define CTK_WIDGET_TEXTENTRY 5
+#define CTK_WIDGET_ICON 6
+
+struct ctk_widget;
+
+#define CTK_SEPARATOR(x, y, w) \
+ NULL, NULL, x, y, CTK_WIDGET_SEPARATOR, w
+struct ctk_separator {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+};
+
+#define CTK_BUTTON(x, y, w, text) \
+ NULL, NULL, x, y, CTK_WIDGET_BUTTON, w, text
+struct ctk_button {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+ char *text;
+};
+
+#define CTK_LABEL(x, y, w, h, text) \
+ NULL, NULL, x, y, CTK_WIDGET_LABEL, w, text, h
+struct ctk_label {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+ char *text;
+ unsigned char h;
+};
+
+#define CTK_HYPERLINK(x, y, w, text, url) \
+ NULL, NULL, x, y, CTK_WIDGET_HYPERLINK, w, text, url
+struct ctk_hyperlink {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+ char *text;
+ char *url;
+};
+
+/* Editing modes of the CTK textentry widget. */
+#define CTK_TEXTENTRY_NORMAL 0
+#define CTK_TEXTENTRY_EDIT 1
+
+
+#define CTK_TEXTENTRY(x, y, w, h, text, len) \
+ NULL, NULL, x, y, CTK_WIDGET_TEXTENTRY, w, text, h, len, \
+ CTK_TEXTENTRY_NORMAL, 0, 0
+struct ctk_textentry {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+ char *text;
+ unsigned char h;
+ unsigned char len;
+ unsigned char state;
+ unsigned char xpos, ypos;
+};
+
+
+#define CTK_ICON(title, bitmap, textmap) \
+ NULL, NULL, 0, 0, CTK_WIDGET_ICON, 0, title, 0, 0, 0, bitmap, textmap
+struct ctk_icon {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+ char *title;
+ ek_id_t owner;
+ unsigned char color, fcolor;
+ unsigned char *bitmap;
+ char *textmap;
+};
+
+#define CTK_BITMAP(x, y, w, h, bitmap) \
+ NULL, NULL, x, y, CTK_WIDGET_BITMAP, w, bitmap, h
+struct ctk_bitmap {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+ unsigned char *bitmap;
+ unsigned char h;
+};
+
+
+
+/* The following ctk_widget_* structures are internal to CTK. */
+struct ctk_widget_button {
+ char *text;
+};
+
+struct ctk_widget_label {
+ char *text;
+ unsigned char h;
+};
+
+struct ctk_widget_hyperlink {
+ char *text;
+ char *url;
+};
+
+struct ctk_widget_textentry {
+ char *text;
+ unsigned char h;
+ unsigned char len;
+ unsigned char state;
+ unsigned char xpos, ypos;
+};
+
+struct ctk_widget_icon {
+ char *title;
+ ek_id_t owner;
+ unsigned char color, fcolor;
+ unsigned char *bitmap;
+ char *textmap;
+};
+
+struct ctk_widget_bitmap {
+ unsigned char *bitmap;
+ unsigned char h;
+};
+
+struct ctk_widget {
+ struct ctk_widget *next;
+ struct ctk_window *window;
+ unsigned char x, y;
+ unsigned char type;
+ unsigned char w;
+ union {
+ struct ctk_widget_label label;
+ struct ctk_widget_button button;
+ struct ctk_widget_hyperlink hyperlink;
+ struct ctk_widget_textentry textentry;
+ struct ctk_widget_icon icon;
+ } widget;
+};
+
+/* Definition of the CTK window structure. */
+struct ctk_window {
+ struct ctk_window *next, *prev;
+ ek_id_t owner;
+
+#if CTK_CONF_WINDOWCLOSE
+ struct ctk_button closebutton;
+#else /* CTK_CONF_WINDOWCLOSE */
+ struct ctk_label closebutton;
+#endif /* CTK_CONF_WINDOWCLOSE */
+
+#if CTK_CONF_WINDOWMOVE
+ struct ctk_button titlebutton;
+#else /* CTK_CONF_WINDOWMOVE */
+ struct ctk_label titlebutton;
+#endif /* CTK_CONF_WINDOWMOVE */
+
+ struct ctk_widget *inactive;
+ struct ctk_widget *active;
+ struct ctk_widget *focused;
+ unsigned char x, y;
+ unsigned char w, h;
+ char *title;
+ unsigned char titlelen;
+};
+
+struct ctk_menuitem {
+ char *title;
+ unsigned char titlelen;
+};
+
+struct ctk_menu {
+ struct ctk_menu *next;
+ char *title;
+ unsigned char titlelen;
+ ek_id_t owner;
+ unsigned char active;
+ unsigned char nitems;
+ struct ctk_menuitem items[CTK_CONF_MAXMENUITEMS];
+};
+
+struct ctk_menus {
+ struct ctk_menu *menus;
+ struct ctk_menu *open;
+ struct ctk_menu *desktopmenu;
+};
+
+/* Global CTK modes. */
+#define CTK_MODE_NORMAL 0
+#define CTK_MODE_WINDOWMOVE 1
+#define CTK_MODE_SCREENSAVER 2
+#define CTK_MODE_EXTERNAL 3
+
+/* General ctk functions. */
+void ctk_init(void);
+void ctk_mode_set(unsigned char mode);
+unsigned char ctk_mode_get(void);
+void ctk_redraw(void);
+
+/* Functions for manipulating windows. */
+void ctk_window_new(struct ctk_window *window,
+ unsigned char w, unsigned char h,
+ char *title);
+void ctk_window_clear(struct ctk_window *w);
+void ctk_window_open(struct ctk_window *w);
+#define ctk_window_move(w,xpos,ypos) do {(w)->x=xpos; (w)->y=ypos;}while(0)
+void ctk_window_close(struct ctk_window *w);
+void ctk_window_redraw(struct ctk_window *w);
+#define ctk_window_isopen(w) ((w)->next != NULL)
+
+
+/* Functions for manipulating dialogs. */
+void ctk_dialog_new(struct ctk_window *window,
+ unsigned char w, unsigned char h);
+void ctk_dialog_open(struct ctk_window *d);
+void ctk_dialog_close(void);
+
+/* Functions for manipulating menus. */
+void ctk_menu_new(struct ctk_menu *menu, char *title);
+void ctk_menu_add(struct ctk_menu *menu);
+void ctk_menu_remove(struct ctk_menu *menu);
+unsigned char ctk_menuitem_add(struct ctk_menu *menu, char *name);
+
+/* Functions for icons. */
+#define CTK_ICON_ADD(icon, id) ctk_icon_add((struct ctk_widget *)icon, id)
+void ctk_icon_add(struct ctk_widget *icon, ek_id_t id);
+
+/* Functions for manipulating widgets. */
+#define CTK_WIDGET_ADD(win, widg) \
+ ctk_widget_add(win, (struct ctk_widget *)widg)
+void ctk_widget_add(struct ctk_window *window,
+ struct ctk_widget *widget);
+
+#define CTK_WIDGET_FOCUS(win, widg) \
+ (win)->focused = (struct ctk_widget *)(widg)
+#define CTK_WIDGET_REDRAW(widg) \
+ ctk_widget_redraw((struct ctk_widget *)widg)
+void ctk_widget_redraw(struct ctk_widget *w);
+
+#define CTK_WIDGET_YPOS(w) (((struct ctk_widget *)(w))->y)
+
+#define ctk_textentry_set_height(w, height) \
+ (w)->widget.textentry.h = (height)
+#define ctk_label_set_height(w, height) \
+ (w)->widget.label.h = (height)
+#define ctk_label_set_text(l, t) (l)->text = (t)
+
+#define CTK_BUTTON_NEW(widg, xpos, ypos, width, buttontext) \
+ (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_BUTTON; \
+ (widg)->x = (xpos); \
+ (widg)->y = (ypos); \
+ (widg)->w = (width); \
+ (widg)->text = (buttontext)
+
+#define CTK_LABEL_NEW(widg, xpos, ypos, width, height, labeltext) \
+ (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_LABEL; \
+ (widg)->x = (xpos); \
+ (widg)->y = (ypos); \
+ (widg)->w = (width); \
+ (widg)->h = (height); \
+ (widg)->text = (labeltext)
+
+#define CTK_TEXTENTRY_NEW(widg, xxpos, yypos, width, height, textptr, textlen) \
+ (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_TEXTENTRY; \
+ (widg)->x = (xxpos); \
+ (widg)->y = (yypos); \
+ (widg)->w = (width); \
+ (widg)->h = (height); \
+ (widg)->text = (textptr); \
+ (widg)->len = (textlen); \
+ (widg)->state = CTK_TEXTENTRY_NORMAL; \
+ (widg)->xpos = 0; \
+ (widg)->ypos = 0
+
+
+
+#define CTK_HYPERLINK_NEW(widg, xpos, ypos, width, linktext, linkurl) \
+ (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_HYPERLINK; \
+ (widg)->x = (xpos); \
+ (widg)->y = (ypos); \
+ (widg)->w = (width); \
+ (widg)->text = (linktext); \
+ (widg)->url = (linkurl)
+
+/* Signals. */
+extern ek_signal_t ctk_signal_keypress,
+ ctk_signal_timer,
+ ctk_signal_button_activate,
+ ctk_signal_button_hover,
+ ctk_signal_hyperlink_activate,
+ ctk_signal_hyperlink_hover,
+ ctk_signal_menu_activate,
+ ctk_signal_window_close;
+
+/* Focus flags */
+#define CTK_FOCUS_NONE 0
+#define CTK_FOCUS_WIDGET 1
+#define CTK_FOCUS_WINDOW 2
+#define CTK_FOCUS_DIALOG 4
+
+
+
+#endif /* __CTK_H__ */
diff --git a/contiki/ek/dispatcher.c b/contiki/ek/dispatcher.c
new file mode 100644
index 0000000..a2b0a76
--- /dev/null
+++ b/contiki/ek/dispatcher.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ek" event kernel.
+ *
+ * $Id: dispatcher.c,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+
+#include "ek.h"
+#include "dispatcher.h"
+
+#include "uip.h"
+
+#include <time.h>
+/*#include <conio.h>*/
+
+ek_id_t dispatcher_current;
+static struct dispatcher_proc *procs;
+static ek_id_t ids = 0;
+
+
+static ek_signal_t lastsig = 1;
+
+struct listenport {
+ u16_t port;
+ ek_id_t id;
+};
+static struct listenport listenports[UIP_LISTENPORTS];
+static u8_t listenportsptr;
+
+/*-----------------------------------------------------------------------------------*/
+ek_signal_t
+dispatcher_sigalloc(void)
+{
+ return lastsig++;
+}
+/*-----------------------------------------------------------------------------------*/
+ek_id_t
+dispatcher_start(struct dispatcher_proc *p)
+{
+ ek_id_t id;
+
+ id = ids++;
+
+ if(procs == NULL) {
+ procs = p;
+ } else {
+ p->next = procs;
+ procs = p;
+ }
+ p->id = id;
+
+ dispatcher_current = id;
+
+ return id;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ek_idle(void)
+{
+ struct dispatcher_proc *p;
+ for(p = procs; p != NULL; p = p->next) {
+ if(p->idle != NULL) {
+ dispatcher_current = p->id;
+ p->idle();
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+ek_clock_t
+ek_clock(void)
+{
+ return clock();
+}
+/*-----------------------------------------------------------------------------------*/
+ek_err_t
+ek_dispatcher(ek_signal_t s, ek_data_t data, ek_id_t id)
+{
+ struct dispatcher_proc *p;
+ for(p = procs; p != NULL; p = p->next) {
+ if(p->id == id &&
+ p->signalhandler != NULL) {
+ dispatcher_current = id;
+ p->signalhandler(s, data);
+ return EK_ERR_OK;
+ }
+ }
+ return EK_ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+#ifdef WITH_UIP
+void
+dispatcher_uipcall(void)
+{
+ struct dispatcher_proc *p;
+ struct dispatcher_uipstate *s;
+ u8_t i;
+
+ s = (struct dispatcher_uipstate *)uip_conn->appstate;
+
+ /* If this is a connection request for a listening port, we must
+ mark the connection with the right process ID. */
+ if(uip_connected()) {
+ for(i = 0; i < listenportsptr; ++i) {
+ if(listenports[i].port == uip_conn->lport) {
+ s->id = listenports[i].id;
+ break;
+ }
+ }
+ }
+
+
+ for(p = procs; p != NULL; p = p->next) {
+ if(p->id == s->id &&
+ p->uiphandler != NULL) {
+ dispatcher_current = p->id;
+ p->uiphandler(s->state);
+ }
+ }
+}
+#endif /* WITH_UIP */
+/*-----------------------------------------------------------------------------------*/
+void
+dispatcher_uiplisten(u16_t port)
+{
+ listenports[listenportsptr].port = htons(port);
+ listenports[listenportsptr].id = dispatcher_current;
+
+ ++listenportsptr;
+
+#ifdef WITH_UIP
+ uip_listen(port);
+#endif /* WITH_UIP */
+}
+/*-----------------------------------------------------------------------------------*/
+void
+dispatcher_markconn(struct uip_conn *conn,
+ void *appstate)
+{
+ struct dispatcher_uipstate *s;
+
+ s = (struct dispatcher_uipstate *)conn->appstate;
+ s->id = dispatcher_current;
+ s->state = appstate;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+dispatcher_listen(ek_signal_t s)
+{
+ ek_listen(s, dispatcher_current);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+dispatcher_timer(ek_signal_t s, ek_data_t data, ek_ticks_t t)
+{
+ ek_timer(s, data, dispatcher_current, t);
+}
+/*-----------------------------------------------------------------------------------*/
+struct dispatcher_proc *
+dispatcher_process(ek_id_t id)
+{
+ struct dispatcher_proc *p;
+ for(p = procs; p != NULL; p = p->next) {
+ if(p->id == id) {
+ return p;
+ }
+ }
+ return NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+dispatcher_init(void)
+{
+ listenportsptr = 0;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/ek/dispatcher.h b/contiki/ek/dispatcher.h
new file mode 100644
index 0000000..f636e88
--- /dev/null
+++ b/contiki/ek/dispatcher.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ek" event kernel.
+ *
+ * $Id: dispatcher.h,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+#ifndef __DISPATCHER_H__
+#define __DISPATCHER_H__
+
+#include "ek.h"
+
+void dispatcher_init(void);
+
+#define DISPATCHER_BROADCAST EK_ID_ALL
+
+#define DISPATCHER_PROC(name, idle, signal, uip) \
+ NULL, 0, name, idle, signal, uip
+struct dispatcher_proc {
+ struct dispatcher_proc *next;
+ ek_id_t id;
+ char *name;
+ void (* idle)(void);
+ void (* signalhandler)(ek_signal_t s, ek_data_t data);
+ void (* uiphandler)(void *state);
+};
+
+#define DISPATCHER_CURRENT() dispatcher_current
+
+ek_signal_t dispatcher_sigalloc(void);
+
+ek_id_t dispatcher_start(struct dispatcher_proc *p);
+void dispatcher_stop(struct dispatcher_proc *p);
+
+void dispatcher_listen(ek_signal_t s);
+void dispatcher_timer(ek_signal_t s, ek_data_t data, ek_ticks_t t);
+#define dispatcher_emit ek_emit
+
+struct dispatcher_proc *dispatcher_process(ek_id_t id);
+
+struct dispatcher_uipstate {
+ ek_id_t id;
+ void *state;
+};
+
+
+#define UIP_APPCALL dispatcher_uipcall
+#define UIP_APPSTATE_SIZE sizeof(struct dispatcher_uipstate)
+
+
+#include "uip.h"
+
+struct uip_conn;
+
+void dispatcher_uipcall(void);
+
+void dispatcher_markconn(struct uip_conn *conn,
+ void *appstate);
+void dispatcher_uiplisten(u16_t port);
+
+extern ek_id_t dispatcher_current;
+
+#endif /* __DISPATCHER_H__ */
diff --git a/contiki/ek/ek-conf.h b/contiki/ek/ek-conf.h
new file mode 100644
index 0000000..64207be
--- /dev/null
+++ b/contiki/ek/ek-conf.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ek" event kernel.
+ *
+ * $Id: ek-conf.h,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+
+
+#ifndef __EK_CONF_H__
+#define __EK_CONF_H__
+
+#include <time.h>
+
+typedef void *ek_data_t;
+
+typedef unsigned char ek_signal_t;
+typedef unsigned char ek_id_t;
+
+/* ek_ticks_t: should be defined to be the largest type that fits the
+ highest timeout value used by the system. For example, if all
+ timeouts are between 1 and 150, the ek_ticks_t can be typedef'd as
+ "unsigned char", but if the maximum timeout is over 256, "unsigned
+ short" is a better choise. */
+typedef unsigned short ek_ticks_t;
+
+/* ek_clock_t: should be defined to be the native clock ticks type
+ used by the underlying system. (Look for time_t or similar.) */
+typedef unsigned long ek_clock_t;
+
+#define EK_CONF_NUMSIGNALS 32 /* Must be 2^n */
+typedef unsigned char ek_num_signals_t;
+
+#define EK_CONF_NUMTIMERS 4 /* Must be 2^n */
+typedef unsigned char ek_num_timers_t;
+
+#define EK_CONF_NUMLISTENERS 32 /* Must be 2^n */
+typedef unsigned char ek_num_listeners_t;
+
+#define EK_CONF_UNLISTEN 0
+
+#endif /* __EK_CONF_H__ */
diff --git a/contiki/ek/ek.c b/contiki/ek/ek.c
new file mode 100644
index 0000000..3161df9
--- /dev/null
+++ b/contiki/ek/ek.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ek" event kernel.
+ *
+ * $Id: ek.c,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+
+#include "ek.h"
+#include "ek-conf.h"
+
+/* Structure definitions. */
+struct ek_listener {
+ ek_signal_t s;
+ ek_id_t id;
+};
+
+struct ek_timer {
+ struct ek_timer *next;
+ ek_ticks_t t;
+ ek_signal_t s;
+ ek_data_t data;
+ ek_id_t id;
+};
+
+struct ek_signal_data {
+ ek_signal_t s;
+ ek_data_t data;
+ ek_id_t id;
+};
+
+/* Static variables. */
+static ek_num_signals_t nsignals, fsignal;
+static struct ek_signal_data signals[EK_CONF_NUMSIGNALS];
+
+static struct ek_listener listeners[EK_CONF_NUMLISTENERS];
+
+static struct ek_timer timers[EK_CONF_NUMTIMERS];
+static struct ek_timer *timers_free, *timers_used;
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+/*-----------------------------------------------------------------------------------*/
+void
+ek_init(void)
+{
+ ek_num_timers_t i;
+
+ nsignals = fsignal = 0;
+
+ timers_used = NULL;
+ for(i = 0; i < EK_CONF_NUMTIMERS - 1; ++i) {
+ timers[i].next = &timers[i+1];
+ }
+ timers[i].next = NULL;
+ timers_free = &timers[0];
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ek_signals(void)
+{
+ static ek_signal_t s;
+ static ek_data_t data;
+ static ek_id_t id;
+ static ek_num_listeners_t i;
+
+ if(nsignals > 0) {
+ /* There are signals that we should deliver. */
+ s = signals[fsignal].s;
+
+ data = signals[fsignal].data;
+ id = signals[fsignal].id;
+
+ /* Since we have seen the new signal, we move pointer upwards
+ and decrese number. */
+ fsignal = (fsignal + 1) & (EK_CONF_NUMSIGNALS - 1);
+ --nsignals;
+ /* Check for listeners. */
+ for(i = 0; i < EK_CONF_NUMLISTENERS; ++i) {
+ if(listeners[i].s == s &&
+ (id == EK_ID_NONE ||
+ id == listeners[i].id)) {
+ ek_dispatcher(s, data, listeners[i].id);
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ek_run(void)
+{
+ static ek_clock_t lasttime, curtime;
+ static ek_signal_t s;
+ static ek_data_t data;
+ static ek_id_t id;
+ static struct ek_timer *tptr;
+
+ lasttime = ek_clock();
+
+ while(1) {
+ /* Check the signal list to see if we have signals that should be
+ emitted. */
+ ek_signals();
+
+ /* If no signals should be emitted, we first check outstanding
+ timers and then call the ek_idle function. */
+ curtime = ek_clock();
+
+ while(timers_used != NULL &&
+ (curtime - lasttime) >= (ek_clock_t)timers_used->t) {
+ s = timers_used->s;
+ data = timers_used->data;
+ id = timers_used->id;
+
+ /* Move this timer slot to the free list. */
+ tptr = timers_used;
+ timers_used = timers_used->next;
+ tptr->next = timers_free;
+ timers_free = tptr;
+ lasttime = curtime;
+
+ /* Emit the actual signal. Note that this will not trigger
+ any action until the dispatcher code is executed the next
+ run through the loop. */
+ ek_emit(s, data, id);
+ }
+ ek_idle();
+
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+ek_err_t
+ek_emit(ek_signal_t s, ek_data_t data, ek_id_t id)
+{
+ static unsigned char snum;
+
+ if(nsignals == EK_CONF_NUMSIGNALS) {
+ return EK_ERR_FULL;
+ }
+
+ if(s != EK_SIGNAL_NONE) {
+ snum = (fsignal + nsignals) & (EK_CONF_NUMSIGNALS - 1);
+ signals[snum].s = s;
+ signals[snum].data = data;
+ signals[snum].id = id;
+ ++nsignals;
+ }
+ return EK_ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+ek_err_t
+ek_listen(ek_signal_t s, ek_id_t id)
+{
+ ek_num_listeners_t i, empty;
+
+ /* Go through the listeners list to make sure that the registering
+ listener is unique. At the same time, we find the first empty
+ listener in the list. */
+ empty = EK_CONF_NUMLISTENERS;
+ for(i = 0; i < EK_CONF_NUMLISTENERS; ++i) {
+ if(listeners[i].id == id &&
+ listeners[i].s == s) {
+ return EK_ERR_NOTUNIQUE;
+ }
+ if(empty == EK_CONF_NUMLISTENERS &&
+ listeners[i].s == EK_SIGNAL_NONE) {
+ empty = i;
+ }
+ }
+
+ /* We return an error if there were no empty listener slots. */
+ if(empty == EK_CONF_NUMLISTENERS) {
+ return EK_ERR_FULL;
+ }
+
+ /* Else we register the listener and return OK. */
+ listeners[empty].s = s;
+ listeners[empty].id = id;
+
+ return EK_ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+#if EK_CONF_UNLISTEN
+ek_err_t
+ek_unlisten(ek_signal_t s, ek_id_t id)
+{
+ ek_num_listeners_t i;
+
+ /* Go through the listeners list to find the listener to
+ unregister. */
+ for(i = 0; i < EK_CONF_NUMLISTENERS; ++i) {
+ if(listeners[i].id == id &&
+ listeners[i].s == s) {
+ listeners[i].s = EK_SIGNAL_NONE;
+ return EK_ERR_OK;
+ }
+ }
+ return EK_ERR_NOTFOUND;
+}
+#endif /* EK_CONF_UNLISTEN */
+/*-----------------------------------------------------------------------------------*/
+ek_err_t
+ek_timer(ek_signal_t s, ek_data_t data, ek_id_t id, ek_ticks_t t)
+{
+ register struct ek_timer *tptr, *tptr2;
+
+ /* First check if all timer slots are used already. If so, we return
+ an error. */
+ if(timers_free == NULL) {
+ return EK_ERR_FULL;
+ }
+
+ /* We take the first unused timer slot. */
+ tptr = timers_free;
+ timers_free = timers_free->next;
+
+ tptr->next = NULL;
+ tptr->s = s;
+ tptr->data = data;
+ tptr->id = id;
+
+ /* If there are no running timers, we put this one first on the list
+ and return. */
+ if(timers_used == NULL) {
+
+ tptr->t = t;
+ timers_used = tptr;
+ return EK_ERR_OK;
+ }
+
+ /* Check if this timeout should be placed first in the list. */
+ if(timers_used->t > t) {
+ tptr->t = t;
+ timers_used->t -= t;
+ tptr->next = timers_used;
+ timers_used = tptr;
+
+ } else {
+ /* Calculate where in the list of timers this one should be
+ inserted. This is done by walking through the list while
+ subtracting the cumulative time in ticks from the delay for the
+ current timer. */
+
+ for(tptr2 = timers_used; tptr2 != NULL; tptr2 = tptr2->next) {
+ t -= tptr2->t;
+ if(tptr2->next == NULL ||
+ tptr2->next->t > t) {
+ if(tptr2->next != NULL) {
+ tptr2->next->t -= t;
+ }
+ tptr->t = t;
+ tptr->next = tptr2->next;
+ tptr2->next = tptr;
+ break;
+ }
+ }
+ }
+
+ return EK_ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/ek/ek.h b/contiki/ek/ek.h
new file mode 100644
index 0000000..bd69626
--- /dev/null
+++ b/contiki/ek/ek.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the "ek" event kernel.
+ *
+ * $Id: ek.h,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+#ifndef __EK_H__
+#define __EK_H__
+
+#include "ek-conf.h"
+
+/* Signals defined by ek: */
+#define EK_SIGNAL_NONE 0
+
+/* Errors: */
+#define EK_ERR_OK 0
+#define EK_ERR_FULL 1
+#define EK_ERR_NOTUNIQUE 2
+#define EK_ERR_NOTFOUND 3
+
+/* Special IDs defined by ek: */
+#define EK_ID_NONE 0
+#define EK_ID_ALL 0
+
+typedef unsigned char ek_err_t;
+
+/* Callback functions (must be implemented by the system/application
+ program using ek): */
+
+/* ek_idle:
+ *
+ * Is called repeatedly by ek when there is nothing else to do. This
+ * function can be used to implement polling operations by the
+ * system/application program using ek.
+ */
+void ek_idle(void);
+
+/* ek_dispatcher:
+ *
+ * Is called by ek when a signal has been omitted. The "id" parameter
+ * can be used to distinguish listeners.
+ *
+ * Return values: TBA
+ */
+ek_err_t ek_dispatcher(ek_signal_t s, ek_data_t data, ek_id_t id);
+
+/* ek_clock:
+ *
+ * Should return the current value of the system clock.
+ */
+ek_clock_t ek_clock(void);
+
+
+/* API functions (are used by programs using ek): */
+
+/* ek_listen:
+ *
+ * Registers the listener identified by "id" with the signal "s". When
+ * the signal "s" is emitted, the ek dispatcher callback will be
+ * invoked for the listener "id".
+ *
+ * The meaning of the identifier "id" is defined by the caller (i.e.,
+ * the application program using the ek kernel).
+ *
+ * Return values: TBA
+ */
+ek_err_t ek_listen(ek_signal_t s, ek_id_t id);
+
+/* ek_unlisten:
+ *
+ * Unregisters a previously registered listener.
+ *
+ * Return values: TBA
+ */
+ek_err_t ek_unlisten(ek_signal_t s, ek_id_t id);
+
+/* ek_emit:
+ *
+ * Emits the signal "s". When control returns to ek, the ek signal
+ * dispatcher will be called for each of the registered listeners for
+ * the signal. If no listeners are registered, the signal is
+ * dropped.
+ *
+ * Return values: TBA
+ */
+ek_err_t ek_emit(ek_signal_t s, ek_data_t data, ek_id_t id);
+
+/* ek_timer:
+ *
+ * Sets a timer that will make the signal "s" to be emitted after "t"
+ * number of clock ticks. The granularity of the clock ticks is
+ * determined by the underlying system on which ek is run.
+ *
+ * Return values: TBA
+ */
+ek_err_t ek_timer(ek_signal_t s, ek_data_t data, ek_id_t id,
+ ek_ticks_t t);
+
+/* ek_init:
+ *
+ * Initializes ek.
+ */
+void ek_init(void);
+
+/* ek_signals:
+ *
+ * Called internally by ek_run(). Processes signals.
+ */
+void ek_signals(void);
+
+/* ek_run:
+ *
+ * The main function in ek that is called to start ek. This function
+ * never returns.
+ */
+void ek_run(void);
+
+#endif /* __EK_H__ */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/libconio.c b/contiki/lib/libconio.c
new file mode 100644
index 0000000..7c5080d
--- /dev/null
+++ b/contiki/lib/libconio.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: libconio.c,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+
+#include "libconio.h"
+
+static unsigned char cursx, cursy;
+static unsigned char reversed;
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+wherex(void)
+{
+ return cursx;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+clrscr(void)
+{
+ unsigned char x, y;
+
+ for(x = 0; x < LIBCONIO_SCREEN_WIDTH; ++x) {
+ for(y = 0; y < LIBCONIO_SCREEN_HEIGHT; ++y) {
+ gotoxy(x, y);
+ cputc(' ');
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+revers(unsigned char c)
+{
+ reversed = c;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cputc(char c)
+{
+ ctk_arch_draw_char(c, cursx, cursy, reversed);
+ ++cursx;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cputs(char *str)
+{
+ int i;
+ for(i = 0; i < strlen(str); ++i) {
+ cputc(str[i]);
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cclear(unsigned char length)
+{
+ int i;
+ for(i = 0; i < length; ++i) {
+ cputc(' ');
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+chline(unsigned char length)
+{
+ int i;
+ for(i = 0; i < length; ++i) {
+ cputc('-');
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cvline(unsigned char length)
+{
+ int i;
+ for(i = 0; i < length; ++i) {
+ ctk_arch_draw_char('|', cursx, cursy, 0);
+ ++cursy;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+gotoxy(unsigned char x, unsigned char y)
+{
+ cursx = x;
+ cursy = y;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cclearxy(unsigned char x, unsigned char y, unsigned char length)
+{
+ gotoxy(x, y);
+ cclear(length);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+chlinexy(unsigned char x, unsigned char y, unsigned char length)
+{
+ gotoxy(x, y);
+ chline(length);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cvlinexy(unsigned char x, unsigned char y, unsigned char length)
+{
+ gotoxy(x, y);
+ cvline(length);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cputsxy(unsigned char x, unsigned char y, char *str)
+{
+ gotoxy(x, y);
+ cputs(str);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cputcxy(unsigned char x, unsigned char y, char c)
+{
+ gotoxy(x, y);
+ cputc(c);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+textcolor(unsigned char c)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/libconio.h b/contiki/lib/libconio.h
new file mode 100644
index 0000000..26c9c03
--- /dev/null
+++ b/contiki/lib/libconio.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment
+ *
+ * $Id: libconio.h,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+
+#ifndef __LIBCONIO_H__
+#define __LIBCONIO_H__
+
+
+/* This function must be implemented specifically for the architecure: */
+void ctk_arch_draw_char(char c,
+ unsigned char xpos,
+ unsigned char ypos,
+ unsigned char reversedflag);
+
+/* Default definitions that should be overridden by calling module. */
+#ifndef LIBCONIO_SCREEN_WIDTH
+#define LIBCONIO_SCREEN_WIDTH 40
+#endif /* LIBCONIO_SCREEN_WIDTH */
+
+#ifndef LIBCONIO_SCREEN_HEIGHT
+#define LIBCONIO_SCREEN_HEIGHT 25
+#endif /* LIBCONIO_SCREEN_HEIGHT */
+
+
+
+/* These are function declarations for functions implemented in libconio.c */
+unsigned char wherex(void);
+void clrscr(void);
+void revers(unsigned char c);
+void cputc(char c);
+void cputs(char *str);
+void cclear(unsigned char length);
+void chline(unsigned char length);
+void cvline(unsigned char length);
+void gotoxy(unsigned char x, unsigned char y);
+void cclearxy(unsigned char x, unsigned char y, unsigned char length);
+void chlinexy(unsigned char x, unsigned char y, unsigned char length);
+void cvlinexy(unsigned char x, unsigned char y, unsigned char length);
+void cputsxy(unsigned char x, unsigned char y, char *str);
+void cputcxy(unsigned char x, unsigned char y, char c);
+void textcolor(unsigned char c);
+
+
+
+#endif /* __LIBCONIO_H__ */
diff --git a/contiki/lib/petsciiconv.c b/contiki/lib/petsciiconv.c
new file mode 100644
index 0000000..696c8c5
--- /dev/null
+++ b/contiki/lib/petsciiconv.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: petsciiconv.c,v 1.1 2003/03/19 14:16:05 adamdunkels Exp $
+ *
+ */
+
+
+static unsigned char petscii2ascii[128] = {
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x14,0x09,0x0d,0x11,0x93,0x0a,0x0e,0x0f,
+ 0x10,0x0b,0x12,0x13,0x08,0x15,0x16,0x17,
+ 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x7e,0x5f,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
+ 0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0x7e,0xdf
+};
+
+static unsigned char ascii2petscii[128] = {
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x14,0x09,0x0d,0x11,0x93,0x0a,0x0e,0x0f,
+ 0x10,0x0b,0x12,0x13,0x08,0x15,0x16,0x17,
+ 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
+ 0xd8,0xd9,0xda,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0xc0,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
+ 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
+ 0x58,0x59,0x5a,0xdb,0xdd,0xdd,0x5e,0xdf,
+};
+
+static unsigned int i;
+static unsigned char *ptr;
+
+/*-----------------------------------------------------------------------------------*/
+void
+petsciiconv_toascii(char *buf, unsigned int len)
+{
+ ptr = buf;
+ for(i = len; i > 0; --i) {
+ *ptr = petscii2ascii[*ptr & 0x7f];
+ ++ptr;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+petsciiconv_topetscii(char *buf, unsigned int len)
+{
+ ptr = buf;
+ for(i = len; i > 0; --i) {
+ *ptr = ascii2petscii[*ptr & 0x7f];
+ ++ptr;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/petsciiconv.h b/contiki/lib/petsciiconv.h
new file mode 100644
index 0000000..f6b20a6
--- /dev/null
+++ b/contiki/lib/petsciiconv.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: petsciiconv.h,v 1.1 2003/03/19 14:16:06 adamdunkels Exp $
+ *
+ */
+#ifndef __PETSCIICONV_H__
+#define __PETSCIICONV_H__
+
+#ifdef WITH_ASCII
+
+#define petsciiconv_toascii(buf, len)
+#define petsciiconv_topetscii(buf, len)
+
+#else /* WITH_ASCII */
+
+void petsciiconv_toascii(char *buf, unsigned int len);
+void petsciiconv_topetscii(char *buf, unsigned int len);
+
+#endif /* WITH_ASCII */
+
+#endif /* __PETSCIICONV_H__ */
diff --git a/contiki/lib/strncasecmp.c b/contiki/lib/strncasecmp.c
new file mode 100644
index 0000000..54e99f6
--- /dev/null
+++ b/contiki/lib/strncasecmp.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: strncasecmp.c,v 1.1 2003/03/19 14:16:06 adamdunkels Exp $
+ *
+ */
+
+/* This file contains a naive and non-stanrdards compliant
+ implementation of strncasecmp() for systems that don't implement
+ the function. It works with Contiki, but should most probably not
+ be used anywhere else.
+
+ It copies the n first bytes two strings into two buffers and
+ compares them with strcasecmp.
+*/
+
+#include <string.h>
+
+#define MAX_STRLEN 40
+
+/*static char buf1[MAX_STRLEN],
+ buf2[MAX_STRLEN];*/
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+strncasecmp(const char *s1, const char *s2, unsigned char n)
+{
+ unsigned char len;
+
+ return strncmp(s1, s2, n);
+
+ /* len = MAX_STRLEN;
+ if(n < MAX_STRLEN) {
+ len = n;
+ }
+ strncpy(buf1, s1, len);
+ buf1[MAX_STRLEN - 1] = 0;
+ strncpy(buf2, s2, len);
+ buf2[MAX_STRLEN - 1] = 0;
+ return strcasecmp(buf1, buf2);*/
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/uip/resolv.c b/contiki/uip/resolv.c
new file mode 100644
index 0000000..919b8c5
--- /dev/null
+++ b/contiki/uip/resolv.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: resolv.c,v 1.1 2003/03/19 14:16:06 adamdunkels Exp $
+ *
+ */
+
+#include "resolv.h"
+#include "dispatcher.h"
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+#define MAX_RETRIES 8
+
+struct dns_hdr {
+ u16_t id;
+ u8_t flags1, flags2;
+#define DNS_FLAG1_RESPONSE 0x80
+#define DNS_FLAG1_OPCODE_STATUS 0x10
+#define DNS_FLAG1_OPCODE_INVERSE 0x08
+#define DNS_FLAG1_OPCODE_STANDARD 0x00
+#define DNS_FLAG1_AUTHORATIVE 0x04
+#define DNS_FLAG1_TRUNC 0x02
+#define DNS_FLAG1_RD 0x01
+#define DNS_FLAG2_RA 0x80
+#define DNS_FLAG2_ERR_MASK 0x0f
+#define DNS_FLAG2_ERR_NONE 0x00
+#define DNS_FLAG2_ERR_NAME 0x03
+ u16_t numquestions;
+ u16_t numanswers;
+ u16_t numauthrr;
+ u16_t numextrarr;
+};
+
+struct dns_answer {
+ /* DNS answer record starts with either a domain name or a pointer
+ to a name already present somewhere in the packet. */
+ u16_t type;
+ u16_t class;
+ u16_t ttl[2];
+ u16_t len;
+ u16_t ipaddr[2];
+};
+
+
+#define STATE_UNUSED 0
+#define STATE_NEW 1
+#define STATE_ASKING 2
+#define STATE_DONE 3
+#define STATE_ERROR 4
+struct namemap {
+ u8_t state;
+ u8_t tmr;
+ u8_t retries;
+ u8_t seqno;
+ u8_t err;
+ char name[64];
+ u16_t ipaddr[2];
+};
+
+#define RESOLV_ENTRIES 8
+
+static struct namemap names[RESOLV_ENTRIES];
+
+static u8_t seqno;
+
+static struct uip_udp_conn *resolv_conn = NULL;
+
+ek_signal_t resolv_signal_found = EK_SIGNAL_NONE;
+
+/*-----------------------------------------------------------------------------------*/
+/* parse_name(name):
+ *
+ * Returns the end of the name.
+ */
+static unsigned char *
+parse_name(unsigned char *query)
+{
+ unsigned char n;
+
+ do {
+ n = *query++;
+
+ while(n > 0) {
+ /* printf("%c", *query);*/
+ ++query;
+ --n;
+ };
+ /* printf(".");*/
+ } while(*query != 0);
+ /* printf("\n");*/
+ return query + 1;
+}
+/*-----------------------------------------------------------------------------------*/
+/* check_entries(void):
+ *
+ * Runs through the list of names to see if there are any that have
+ * not been queried yet. If so, a query is sent out.
+ */
+static void
+check_entries(void)
+{
+ struct dns_hdr *hdr;
+ char *query, *nptr, *nameptr;
+ u8_t i;
+ u8_t n;
+
+ for(i = 0; i < RESOLV_ENTRIES; ++i) {
+
+ if(names[i].state == STATE_NEW ||
+ names[i].state == STATE_ASKING) {
+ if(names[i].state == STATE_ASKING) {
+ --names[i].tmr;
+ if(names[i].tmr == 0) {
+ ++names[i].retries;
+ if(names[i].retries == MAX_RETRIES) {
+ names[i].state = STATE_ERROR;
+ resolv_found(names[i].name, NULL);
+ continue;
+ }
+ names[i].tmr = names[i].retries;
+ } else {
+ /* printf("Timer %d\n", names[i].tmr);*/
+ /* Its timer has not run out, so we move on to next
+ entry. */
+ continue;
+ }
+ } else {
+ names[i].state = STATE_ASKING;
+ names[i].tmr = 1;
+ names[i].retries = 0;
+ }
+ hdr = (struct dns_hdr *)uip_appdata;
+ hdr->id = htons(i);
+ hdr->flags1 = DNS_FLAG1_RD;
+ hdr->flags2 = 0;
+ hdr->numquestions = htons(1);
+ hdr->numanswers = hdr->numauthrr = hdr->numextrarr = 0;
+ query = (char *)uip_appdata + 12;
+ nameptr = names[i].name;
+ --nameptr;
+ /* Convert hostname into suitable query format. */
+ do {
+ ++nameptr;
+ nptr = query;
+ ++query;
+ for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) {
+ *query = *nameptr;
+ ++query;
+ ++n;
+ }
+ *nptr = n;
+ } while(*nameptr != 0);
+ nptr = query;
+ *nptr = 0; /* End of query name. */
+ ++nptr;
+ *nptr = 0; /* High byte of query type. */
+ ++nptr;
+ *nptr = 1; /* Low byte of query type. 1 == IP address query. */
+ ++nptr;
+ *nptr = 0; /* High byte of query class. */
+ ++nptr;
+ *nptr = 1; /* Low byte of query class. */
+ ++nptr;
+ uip_udp_send((unsigned char)(nptr - (char *)uip_appdata));
+ break;
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+newdata(void)
+{
+ char *nameptr;
+ struct dns_answer *ans;
+ struct dns_hdr *hdr;
+ u8_t nquestions, nanswers;
+ u8_t i;
+
+ hdr = (struct dns_hdr *)uip_appdata;
+ /* printf("ID %d\n", htons(hdr->id));
+ printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE);
+ printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK);
+ printf("Num questions %d, answers %d, authrr %d, extrarr %d\n",
+ htons(hdr->numquestions),
+ htons(hdr->numanswers),
+ htons(hdr->numauthrr),
+ htons(hdr->numextrarr));
+ */
+
+ /* The ID in the DNS header should be our entry into the name
+ table. */
+ i = htons(hdr->id);
+ if(i < RESOLV_ENTRIES &&
+ names[i].state == STATE_ASKING) {
+
+ /* This entry is now finished. */
+ names[i].state = STATE_DONE;
+ names[i].err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
+
+ /* Check for error. If so, call callback to inform. */
+ if(names[i].err != 0) {
+ names[i].state = STATE_ERROR;
+ resolv_found(names[i].name, NULL);
+ return;
+ }
+
+ /* We only care about the question(s) and the answers. The authrr
+ and the extrarr are simply discarded. */
+ nquestions = htons(hdr->numquestions);
+ nanswers = htons(hdr->numanswers);
+
+ /* Skip the name in the question. XXX: This should really be
+ checked agains the name in the question, to be sure that they
+ match. */
+ nameptr = parse_name((char *)uip_appdata + 12) + 4;
+
+ while(nanswers > 0) {
+ /* The first byte in the answer resource record determines if it
+ is a compressed record or a normal one. */
+ if(*nameptr & 0xc0) {
+ /* Compressed name. */
+ nameptr +=2;
+ /* printf("Compressed anwser\n");*/
+ } else {
+ /* Not compressed name. */
+ nameptr = parse_name((char *)nameptr);
+ }
+
+ ans = (struct dns_answer *)nameptr;
+ /* printf("Answer: type %x, class %x, ttl %x, length %x\n",
+ htons(ans->type), htons(ans->class),
+ (htons(ans->ttl[0]) << 16) | htons(ans->ttl[1]),
+ htons(ans->len));*/
+
+ /* Check for IP address type and Internet class. Others are
+ discarded. */
+ if(ans->type == htons(1) &&
+ ans->class == htons(1) &&
+ ans->len == htons(4)) {
+ /* printf("IP address %d.%d.%d.%d\n",
+ htons(ans->ipaddr[0]) >> 8,
+ htons(ans->ipaddr[0]) & 0xff,
+ htons(ans->ipaddr[1]) >> 8,
+ htons(ans->ipaddr[1]) & 0xff);*/
+ /* XXX: we should really check that this IP address is the one
+ we want. */
+ names[i].ipaddr[0] = ans->ipaddr[0];
+ names[i].ipaddr[1] = ans->ipaddr[1];
+ resolv_found(names[i].name, names[i].ipaddr);
+ return;
+ } else {
+ nameptr = nameptr + 10 + htons(ans->len);
+ }
+ --nanswers;
+ }
+ }
+
+}
+/*-----------------------------------------------------------------------------------*/
+/* udp_appcall():
+ *
+ * The main UDP function.
+ */
+void
+udp_appcall(void)
+{
+ if(uip_udp_conn->rport == htons(53)) {
+ if(uip_poll()) {
+ check_entries();
+ }
+ if(uip_newdata()) {
+ newdata();
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+/* resolv_query(name):
+ *
+ * Queues a name so that a question for the name will be sent out the
+ * next time the udp_appcall is polled.
+ */
+void
+resolv_query(char *name)
+{
+ u8_t i;
+ u8_t lseq, lseqi;
+
+ lseq = lseqi = 0;
+
+ for(i = 0; i < RESOLV_ENTRIES; ++i) {
+ if(names[i].state == STATE_UNUSED) {
+ break;
+ }
+ if(seqno - names[i].seqno > lseq) {
+ lseq = seqno - names[i].seqno;
+ lseqi = i;
+ }
+ }
+
+ if(i == RESOLV_ENTRIES) {
+ i = lseqi;
+ }
+
+ /* printf("Using entry %d\n", i);*/
+
+ strcpy(names[i].name, name);
+ names[i].state = STATE_NEW;
+ names[i].seqno = seqno;
+ ++seqno;
+
+}
+/*-----------------------------------------------------------------------------------*/
+u16_t *
+resolv_lookup(char *name)
+{
+ u8_t i;
+
+ /* Walk through the list to see if the name is in there. If it is
+ not, we return NULL. */
+ for(i = 0; i < RESOLV_ENTRIES; ++i) {
+ if(names[i].state == STATE_DONE &&
+ strcmp(name, names[i].name) == 0) {
+ return names[i].ipaddr;
+ }
+ }
+ return NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+resolv_conf(u16_t *dnsserver)
+{
+ if(resolv_conn != NULL) {
+ uip_udp_remove(resolv_conn);
+ }
+
+ resolv_conn = uip_udp_new(dnsserver, 53);
+
+}
+/*-----------------------------------------------------------------------------------*/
+void
+resolv_init(void)
+{
+ u8_t i;
+
+ for(i = 0; i < RESOLV_ENTRIES; ++i) {
+ names[i].state = STATE_DONE;
+ }
+
+ resolv_signal_found = dispatcher_sigalloc();
+}
+/*-----------------------------------------------------------------------------------*/
+void
+resolv_found(char *name, u16_t *ipaddr)
+{
+ dispatcher_emit(resolv_signal_found, name, DISPATCHER_BROADCAST);
+}
diff --git a/contiki/uip/resolv.h b/contiki/uip/resolv.h
new file mode 100644
index 0000000..6360fa1
--- /dev/null
+++ b/contiki/uip/resolv.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: resolv.h,v 1.1 2003/03/19 14:16:06 adamdunkels Exp $
+ *
+ */
+#ifndef __RESOLV_H__
+#define __RESOLV_H__
+
+#include "uip.h"
+#include "ek.h"
+
+/* Signals */
+extern ek_signal_t resolv_signal_found;
+
+/* Callbacks. */
+void resolv_found(char *name, u16_t *ipaddr);
+
+/* Functions. */
+void resolv_conf(u16_t *dnsserver);
+void resolv_init(void);
+u16_t *resolv_lookup(char *name);
+void resolv_query(char *name);
+
+#endif /* __RESOLV_H__ */
diff --git a/contiki/uip/uip.c b/contiki/uip/uip.c
new file mode 100644
index 0000000..ca289c8
--- /dev/null
+++ b/contiki/uip/uip.c
@@ -0,0 +1,1606 @@
+/*
+ * Copyright (c) 2001-2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.c,v 1.1 2003/03/19 14:16:06 adamdunkels Exp $
+ *
+ */
+
+/*
+This is a small implementation of the IP and TCP protocols (as well as
+some basic ICMP stuff). The implementation couples the IP, TCP and the
+application layers very tightly. To keep the size of the compiled code
+down, this code also features heavy usage of the goto statement.
+
+The principle is that we have a small buffer, called the uip_buf, in
+which the device driver puts an incoming packet. The TCP/IP stack
+parses the headers in the packet, and calls upon the application. If
+the remote host has sent data to the application, this data is present
+in the uip_buf and the application read the data from there. It is up
+to the application to put this data into a byte stream if needed. The
+application will not be fed with data that is out of sequence.
+
+If the application whishes to send data to the peer, it should put its
+data into the uip_buf, 40 bytes from the start of the buffer. The
+TCP/IP stack will calculate the checksums, and fill in the necessary
+header fields and finally send the packet back to the peer.
+*/
+
+#include "uip.h"
+#include "uipopt.h"
+#include "uip_arch.h"
+
+/*-----------------------------------------------------------------------------------*/
+/* Variable definitions. */
+
+
+/* The IP address of this host. If it is defined to be fixed (by setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set here. Otherwise, the address */
+#if UIP_FIXEDADDR > 0
+#if UIP_IPV6
+const u16_t uip_hostaddr[8] =
+ {UIP_IP6ADDR0, UIP_IP6ADDR1,
+ UIP_IP6ADDR2, UIP_IP6ADDR3,
+ UIP_IP6ADDR4, UIP_IP6ADDR5,
+ UIP_IP6ADDR6, UIP_IP6ADDR7};
+#else /* UIP_IPV6 */
+const u16_t uip_hostaddr[2] =
+ {htons((UIP_IPADDR0 << 8) | UIP_IPADDR1),
+ htons((UIP_IPADDR2 << 8) | UIP_IPADDR3)};
+#endif /* UIP_IPV6 */
+#else
+#if UIP_IPV6
+u16_t uip_hostaddr[8];
+#else /* UIP_IPV6 */
+u16_t uip_hostaddr[2];
+#endif /* UIP_IPV6 */
+#endif /* UIP_FIXEDADDR */
+
+u8_t uip_buf[UIP_BUFSIZE]; /* The packet buffer that contains
+ incoming packets. */
+volatile u8_t *uip_appdata; /* The uip_appdata pointer points to
+ application data. */
+#if UIP_URGDATA > 0
+volatile u8_t *uip_urgdata; /* The uip_urgdata pointer points to
+ urgent data (out-of-band data), if
+ present. */
+volatile u8_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+#if UIP_BUFSIZE > 255
+volatile u16_t uip_len, uip_slen;
+ /* The uip_len is either 8 or 16 bits,
+ depending on the maximum packet
+ size. */
+#else
+volatile u8_t uip_len, uip_slen;
+#endif /* UIP_BUFSIZE > 255 */
+
+volatile u8_t uip_flags; /* The uip_flags variable is used for
+ communication between the TCP/IP stack
+ and the application program. */
+struct uip_conn *uip_conn; /* uip_conn always points to the current
+ connection. */
+
+struct uip_conn uip_conns[UIP_CONNS];
+ /* The uip_conns array holds all TCP
+ connections. */
+u16_t uip_listenports[UIP_LISTENPORTS];
+ /* The uip_listenports list all currently
+ listning ports. */
+#if UIP_UDP
+struct uip_udp_conn *uip_udp_conn;
+struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+
+static u16_t ipid; /* Ths ipid variable is an increasing
+ number that is used for the IP ID
+ field. */
+
+static u8_t iss[4]; /* The iss variable is used for the TCP
+ initial sequence number. */
+
+#if UIP_ACTIVE_OPEN
+/* XXX static */ u16_t lastport; /* Keeps track of the last port used for
+ a new connection. */
+#endif /* UIP_ACTIVE_OPEN */
+
+/* Temporary variables. */
+volatile u8_t uip_acc32[4];
+static u8_t c, opt;
+static u16_t tmpport;
+
+/* Structures and definitions. */
+#define TCP_FIN 0x01
+#define TCP_SYN 0x02
+#define TCP_RST 0x04
+#define TCP_PSH 0x08
+#define TCP_ACK 0x10
+#define TCP_URG 0x20
+#define TCP_CTL 0x3f
+
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ECHO 8
+
+/* Macros. */
+#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define FBUF ((uip_tcpip_hdr *)&uip_reassbuf[0])
+#define ICMPBUF ((uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define UDPBUF ((uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+#if UIP_STATISTICS == 1
+struct uip_stats uip_stat;
+#define UIP_STAT(s) s
+#else
+#define UIP_STAT(s)
+#endif /* UIP_STATISTICS == 1 */
+
+#if UIP_LOGGING == 1
+#include <stdio.h>
+void uip_log(char *msg);
+#define UIP_LOG(m) uip_log(m)
+#else
+#define UIP_LOG(m)
+#endif /* UIP_LOGGING == 1 */
+
+/*-----------------------------------------------------------------------------------*/
+void
+uip_init(void)
+{
+ for(c = 0; c < UIP_LISTENPORTS; ++c) {
+ uip_listenports[c] = 0;
+ }
+ for(c = 0; c < UIP_CONNS; ++c) {
+ uip_conns[c].tcpstateflags = CLOSED;
+ }
+#if UIP_ACTIVE_OPEN
+ lastport = 1024;
+#endif /* UIP_ACTIVE_OPEN */
+
+#if UIP_UDP
+ for(c = 0; c < UIP_UDP_CONNS; ++c) {
+ uip_udp_conns[c].lport = 0;
+ }
+#endif /* UIP_UDP */
+
+#if UIP_IPV6
+ /* IPv6 initialization. */
+#if UIP_FIXEDADDR == 0
+ uip_hostaddr[0] = uip_hostaddr[1] =
+ uip_hostaddr[2] = uip_hostaddr[3] =
+ uip_hostaddr[4] = uip_hostaddr[5] =
+ uip_hostaddr[6] = uip_hostaddr[7] = 0;
+#endif /* UIP_FIXEDADDR */
+
+#else /* UIP_IPV6 */
+
+ /* IPv4 initialization. */
+#if UIP_FIXEDADDR == 0
+ uip_hostaddr[0] = uip_hostaddr[1] = 0;
+#endif /* UIP_FIXEDADDR */
+
+#endif /* UIP_IPV6 */
+}
+/*-----------------------------------------------------------------------------------*/
+#if UIP_ACTIVE_OPEN
+struct uip_conn *
+uip_connect(u16_t *ripaddr, u16_t rport)
+{
+ struct uip_conn *conn;
+
+ /* Find an unused local port. */
+ again:
+ ++lastport;
+
+ if(lastport >= 32000) {
+ lastport = 4096;
+ }
+
+ for(c = 0; c < UIP_CONNS; ++c) {
+ if(uip_conns[c].tcpstateflags != CLOSED &&
+ uip_conns[c].lport == lastport)
+ goto again;
+ }
+
+
+ conn = 0;
+ for(c = 0; c < UIP_CONNS; ++c) {
+ if(uip_conns[c].tcpstateflags == CLOSED) {
+ conn = &uip_conns[c];
+ break;
+ }
+ if(uip_conns[c].tcpstateflags == TIME_WAIT) {
+ if(conn == 0 ||
+ uip_conns[c].timer > uip_conn->timer) {
+ conn = &uip_conns[c];
+ }
+ }
+ }
+
+ if(conn == 0) {
+ return 0;
+ }
+
+ conn->tcpstateflags = SYN_SENT;
+
+ conn->snd_nxt[0] = iss[0];
+ conn->snd_nxt[1] = iss[1];
+ conn->snd_nxt[2] = iss[2];
+ conn->snd_nxt[3] = iss[3];
+
+ conn->len = 1; /* TCP length of the SYN is one. */
+ conn->nrtx = 0;
+ conn->timer = 1; /* Send the SYN next time around. */
+ conn->lport = htons(lastport);
+ conn->rport = htons(rport);
+#if UIP_IPV6
+ conn->ripaddr[0] = ripaddr[0];
+ conn->ripaddr[1] = ripaddr[1];
+ conn->ripaddr[2] = ripaddr[2];
+ conn->ripaddr[3] = ripaddr[3];
+ conn->ripaddr[4] = ripaddr[4];
+ conn->ripaddr[5] = ripaddr[5];
+ conn->ripaddr[6] = ripaddr[6];
+ conn->ripaddr[7] = ripaddr[7];
+#else /* UIP_IPV6 */
+ conn->ripaddr[0] = ripaddr[0];
+ conn->ripaddr[1] = ripaddr[1];
+#endif /* UIP_IPV6 */
+
+ return conn;
+}
+#endif /* UIP_ACTIVE_OPEN */
+/*-----------------------------------------------------------------------------------*/
+#if UIP_UDP
+struct uip_udp_conn *
+uip_udp_new(u16_t *ripaddr, u16_t rport)
+{
+ struct uip_udp_conn *conn;
+
+ /* Find an unused local port. */
+ again:
+ ++lastport;
+
+ if(lastport >= 32000) {
+ lastport = 4096;
+ }
+
+ for(c = 0; c < UIP_UDP_CONNS; ++c) {
+ if(uip_udp_conns[c].lport == lastport)
+ goto again;
+ }
+
+
+ conn = 0;
+ for(c = 0; c < UIP_UDP_CONNS; ++c) {
+ if(uip_udp_conns[c].lport == 0) {
+ conn = &uip_udp_conns[c];
+ break;
+ }
+ }
+
+ if(conn == 0) {
+ return 0;
+ }
+
+ conn->lport = htons(lastport);
+ conn->rport = htons(rport);
+#if UIP_IPV6
+ conn->ripaddr[0] = ripaddr[0];
+ conn->ripaddr[1] = ripaddr[1];
+ conn->ripaddr[2] = ripaddr[2];
+ conn->ripaddr[3] = ripaddr[3];
+ conn->ripaddr[4] = ripaddr[4];
+ conn->ripaddr[5] = ripaddr[5];
+ conn->ripaddr[6] = ripaddr[6];
+ conn->ripaddr[7] = ripaddr[7];
+#else /* UIP_IPV6 */
+ conn->ripaddr[0] = ripaddr[0];
+ conn->ripaddr[1] = ripaddr[1];
+#endif /* UIP_IPV6 */
+
+ return conn;
+}
+#endif /* UIP_UDP */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_listen(u16_t port)
+{
+ for(c = 0; c < UIP_LISTENPORTS; ++c) {
+ if(uip_listenports[c] == 0) {
+ uip_listenports[c] = htons(port);
+ break;
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+#if UIP_IPV6
+/* IPv4 fragment reassembly is not used in IPv6. */
+#define UIP_REASSEMBLY 0
+#else /* UIP_IPV6 */
+#define UIP_REASSEMBLY 0
+#endif /* UIP_IPV6 */
+
+#define UIP_REASS_MAXAGE 10
+
+#if UIP_REASSEMBLY
+#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
+static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
+static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
+static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
+ 0x0f, 0x07, 0x03, 0x01};
+static u16_t uip_reasslen;
+static u8_t uip_reassflags;
+#define UIP_REASS_FLAG_LASTFRAG 0x01
+static u8_t uip_reasstmr;
+
+#define IP_HLEN 20
+#define IP_MF 0x20
+
+static u8_t
+uip_reass(void)
+{
+ u16_t offset, len;
+ u16_t i;
+
+ /* If ip_reasstmr is zero, no packet is present in the buffer, so we
+ write the IP header of the fragment into the reassembly
+ buffer. The timer is updated with the maximum age. */
+ if(uip_reasstmr == 0) {
+ bcopy(&BUF->vhl, uip_reassbuf, IP_HLEN);
+ uip_reasstmr = UIP_REASS_MAXAGE;
+ uip_reassflags = 0;
+ /* Clear the bitmap. */
+ bzero(uip_reassbitmap, sizeof(uip_reassbitmap));
+ }
+
+ /* Check if the incoming fragment matches the one currently present
+ in the reasembly buffer. If so, we proceed with copying the
+ fragment into the buffer. */
+ if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
+ BUF->destipaddr[1] == FBUF->destipaddr[1] &&
+ BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
+ BUF->destipaddr[1] == FBUF->destipaddr[1] &&
+ BUF->ipid == FBUF->ipid) {
+
+ len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
+ offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
+
+ /* If the offset or the offset + fragment length overflows the
+ reassembly buffer, we discard the entire packet. */
+ if(offset > UIP_REASS_BUFSIZE ||
+ offset + len > UIP_REASS_BUFSIZE) {
+ uip_reasstmr = 0;
+ goto nullreturn;
+ }
+
+ /* Copy the fragment into the reassembly buffer, at the right
+ offset. */
+ bcopy(BUF + (BUF->vhl & 0x0f) * 4,
+ &uip_reassbuf[IP_HLEN + offset], len);
+
+ /* Update the bitmap. */
+ if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
+ /* If the two endpoints are in the same byte, we only update
+ that byte. */
+ uip_reassbitmap[offset / (8 * 8)] |=
+ bitmap_bits[(offset / 8 ) & 7] &
+ ~bitmap_bits[((offset + len) / 8 ) & 7];
+ } else {
+ /* If the two endpoints are in different bytes, we update the
+ bytes in the endpoints and fill the stuff inbetween with
+ 0xff. */
+ uip_reassbitmap[offset / (8 * 8)] |=
+ bitmap_bits[(offset / 8 ) & 7];
+ for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
+ uip_reassbitmap[i] = 0xff;
+ }
+ uip_reassbitmap[(offset + len) / (8 * 8)] |=
+ ~bitmap_bits[((offset + len) / 8 ) & 7];
+ }
+
+ /* If this fragment has the More Fragments flag set to zero, we
+ know that this is the last fragment, so we can calculate the
+ size of the entire packet. We also set the
+ IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
+ the final fragment. */
+
+ if((BUF->ipoffset[0] & IP_MF) == 0) {
+ uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
+ uip_reasslen = offset + len;
+ }
+
+ /* Finally, we check if we have a full packet in the buffer. We do
+ this by checking if we have the last fragment and if all bits
+ in the bitmap are set. */
+ if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
+ /* Check all bytes up to and including all but the last byte in
+ the bitmap. */
+ for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
+ if(uip_reassbitmap[i] != 0xff) {
+ goto nullreturn;
+ }
+ }
+ /* Check the last byte in the bitmap. It should contain just the
+ right amount of bits. */
+ if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
+ (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
+ goto nullreturn;
+ }
+
+ /* If we have come this far, we have a full packet in the
+ buffer, so we allocate a pbuf and copy the packet into it. We
+ also reset the timer. */
+ uip_reasstmr = 0;
+ bcopy(FBUF, BUF, uip_reasslen);
+
+ /* Pretend to be a "normal" (i.e., not fragmented) IP packet
+ from now on. */
+ BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
+ BUF->ipchksum = 0;
+ BUF->ipchksum = ~(uip_ipchksum());
+
+
+
+ return uip_reasslen;
+ }
+ }
+
+ nullreturn:
+ return 0;
+}
+#endif /* IP_REASSEMBLY */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_process(u8_t flag)
+{
+ register struct uip_conn *uip_connr = uip_conn;
+ /*#define uip_connr uip_conn*/
+
+ uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
+
+
+ /* Check if we were invoked because of the perodic timer fireing. */
+ if(flag == UIP_TIMER) {
+ /* Increase the initial sequence number. */
+ if(++iss[3] == 0) {
+ if(++iss[2] == 0) {
+ if(++iss[1] == 0) {
+ ++iss[0];
+ }
+ }
+ }
+ uip_len = 0;
+ if(uip_connr->tcpstateflags == TIME_WAIT ||
+ uip_connr->tcpstateflags == FIN_WAIT_2) {
+ ++(uip_connr->timer);
+ if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
+ uip_connr->tcpstateflags = CLOSED;
+ }
+ } else if(uip_connr->tcpstateflags != CLOSED) {
+ /* If the connection has outstanding data, we increase the
+ connection's timer and see if it has reached the RTO value
+ in which case we retransmit. */
+ if(uip_outstanding(uip_connr)) {
+ --(uip_connr->timer);
+ if(uip_connr->timer == 0) {
+ if(uip_connr->nrtx == UIP_MAXRTX ||
+ ((uip_connr->tcpstateflags == SYN_SENT ||
+ uip_connr->tcpstateflags == SYN_RCVD) &&
+ uip_connr->nrtx == UIP_MAXSYNRTX)) {
+ uip_connr->tcpstateflags = CLOSED;
+
+ /* We call UIP_APPCALL() with uip_flags set to
+ UIP_TIMEDOUT to inform the application that the
+ connection has timed out. */
+ uip_flags = UIP_TIMEDOUT;
+ UIP_APPCALL();
+
+ /* We also send a reset packet to the remote host. */
+ BUF->flags = TCP_RST | TCP_ACK;
+ goto tcp_send_nodata;
+ }
+
+ /* Exponential backoff. */
+ uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4? 4: uip_connr->nrtx);
+
+ ++(uip_connr->nrtx);
+
+ /* Ok, so we need to retransmit. We do this differently
+ depending on which state we are in. In ESTABLISHED, we
+ call upon the application so that it may prepare the
+ data for the retransmit. In SYN_RCVD, we resend the
+ SYNACK that we sent earlier and in LAST_ACK we have to
+ retransmit our FINACK. */
+ UIP_STAT(++uip_stat.tcp.rexmit);
+ switch(uip_connr->tcpstateflags & TS_MASK) {
+ case SYN_RCVD:
+ /* In the SYN_RCVD state, we should retransmit our
+ SYNACK. */
+ goto tcp_send_synack;
+
+#if UIP_ACTIVE_OPEN
+ case SYN_SENT:
+ /* In the SYN_SENT state, we retransmit out SYN. */
+ BUF->flags = 0;
+ goto tcp_send_syn;
+#endif /* UIP_ACTIVE_OPEN */
+
+ case ESTABLISHED:
+ /* In the ESTABLISHED state, we call upon the application
+ to do the actual retransmit after which we jump into
+ the code for sending out the packet (the apprexmit
+ label). */
+ uip_len = 0;
+ uip_slen = 0;
+ uip_flags = UIP_REXMIT;
+ UIP_APPCALL();
+ goto apprexmit;
+
+ case FIN_WAIT_1:
+ case CLOSING:
+ case LAST_ACK:
+ /* In all these states we should retransmit a FINACK. */
+ goto tcp_send_finack;
+
+ }
+ }
+ } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
+ /* If there was no need for a retransmission, we poll the
+ application for new data. */
+ uip_len = 0;
+ uip_slen = 0;
+ uip_flags = UIP_POLL;
+ UIP_APPCALL();
+ goto appsend;
+ }
+ }
+ goto drop;
+ }
+#if UIP_UDP
+ if(flag == UIP_UDP_TIMER) {
+ if(uip_udp_conn->lport != 0) {
+ uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
+ uip_len = uip_slen = 0;
+ uip_flags = UIP_POLL;
+ UIP_UDP_APPCALL();
+ goto udp_send;
+ } else {
+ goto drop;
+ }
+ }
+#endif
+
+ /* This is where the input processing starts. */
+ UIP_STAT(++uip_stat.ip.recv);
+
+#if UIP_IPV6
+
+ /* Start of IPv6 input header processing code. */
+
+ /* Check version number in IP header (should be 6) */
+ if((BUF->vtc & 0x60) != 0x60) {
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.vhlerr);
+ UIP_LOG("ip: invalid version.");
+ goto drop;
+ }
+
+ /* Check packet length. It must be at less than or equal to
+ uip_len. If less, the link layer has added a trailer or padding,
+ and we set uip_len accordingly. */
+ tmpport = (((u16_t)BUF->len[0] << 8) | BUF->len[1]);
+ if(tmpport < uip_len) {
+ uip_len = tmpport;
+ } else if(tmpport > uip_len) {
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.lblenerr);
+ UIP_LOG("ip: packet too short.");
+ goto drop;
+ }
+
+ /* Check if the packet is destined for our IP address. */
+ for(c = 0; c < 8; ++c) {
+ if(BUF->destipaddr[c] != uip_hostaddr[c]) {
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_LOG("ip: packet not for us.");
+ goto drop;
+ }
+ }
+
+ if(BUF->nxthdr == UIP_PROTO_TCP) /* Check for TCP packet. If so, jump
+ to the tcp_input label. */
+ goto tcp_input;
+
+ if(BUF->nxthdr != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
+ here. */
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.protoerr);
+ UIP_LOG("ip: neither tcp nor icmp.");
+ goto drop;
+ }
+
+ /* Start of (very simplistic!) ICMPv6 input processing code. */
+ icmp_input:
+ UIP_STAT(++uip_stat.icmp.recv);
+
+ /* ICMP echo (i.e., ping) processing. This is simple, we only change
+ the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
+ checksum before we return the packet. */
+ if(ICMPBUF->type != ICMP_ECHO) {
+ UIP_STAT(++uip_stat.icmp.drop);
+ UIP_STAT(++uip_stat.icmp.typeerr);
+ UIP_LOG("icmp: not icmp echo.");
+ goto drop;
+ }
+
+ ICMPBUF->type = ICMP_ECHO_REPLY;
+
+ if(ICMPBUF->icmpchksum >= htons(0xffff - (ICMP_ECHO << 8))) {
+ ICMPBUF->icmpchksum += htons(ICMP_ECHO << 8) + 1;
+ } else {
+ ICMPBUF->icmpchksum += htons(ICMP_ECHO << 8);
+ }
+
+ /* Swap IP addresses. */
+ for(c = 0; c < 8; ++c) {
+ tmpport = BUF->destipaddr[c];
+ BUF->destipaddr[c] = BUF->srcipaddr[c];
+ BUF->srcipaddr[c] = tmpport;
+ }
+
+ UIP_STAT(++uip_stat.icmp.sent);
+ goto send;
+
+
+ /* End of IPv6 input header processing code. */
+
+#else /* UIP_IPV6 */
+
+
+ /* Start of IPv4 input header processing code. */
+
+ /* Check validity of the IP header. */
+ if(BUF->vhl != 0x45) { /* IP version and header length. */
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.vhlerr);
+ UIP_LOG("ip: invalid version or header length.");
+ goto drop;
+ }
+
+ /* Check the size of the packet. If the size reported to us in
+ uip_len doesn't match the size reported in the IP header, there
+ has been a transmission error and we drop the packet. */
+
+#if UIP_BUFSIZE > 255
+ if(BUF->len[0] != (uip_len >> 8)) { /* IP length, high byte. */
+ uip_len = (uip_len & 0xff) | (BUF->len[0] << 8);
+ }
+ if(BUF->len[1] != (uip_len & 0xff)) { /* IP length, low byte. */
+ uip_len = (uip_len & 0xff00) | BUF->len[1];
+ }
+#else
+ if(BUF->len[0] != 0) { /* IP length, high byte. */
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.hblenerr);
+ UIP_LOG("ip: invalid length, high byte.");
+ goto drop;
+ }
+ if(BUF->len[1] != uip_len) { /* IP length, low byte. */
+ uip_len = BUF->len[1];
+ }
+#endif /* UIP_BUFSIZE > 255 */
+
+ if(BUF->ipoffset[0] & 0x3f) { /* We don't allow IP fragments. */
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.fragerr);
+ UIP_LOG("ip: fragment dropped.");
+ goto drop;
+ }
+
+ /* If we are configured to use ping IP address configuration and
+ hasn't been assigned an IP address yet, we accept all ICMP
+ packets. */
+#if UIP_PINGADDRCONF
+ if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
+ if(BUF->proto == UIP_PROTO_ICMP) {
+ UIP_LOG("ip: possible ping config packet received.");
+ goto icmp_input;
+ } else {
+ UIP_LOG("ip: packet dropped since no address assigned..");
+ goto drop;
+ }
+ }
+#endif /* UIP_PINGADDRCONF */
+
+ /* Check if the packet is destined for our IP address. */
+ if(BUF->destipaddr[0] != uip_hostaddr[0]) {
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_LOG("ip: packet not for us.");
+ goto drop;
+ }
+ if(BUF->destipaddr[1] != uip_hostaddr[1]) {
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_LOG("ip: packet not for us.");
+ goto drop;
+ }
+
+ if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
+ checksum. */
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.chkerr);
+ UIP_LOG("ip: bad checksum.");
+ goto drop;
+ }
+
+ if(BUF->proto == UIP_PROTO_TCP) /* Check for TCP packet. If so, jump
+ to the tcp_input label. */
+ goto tcp_input;
+
+#if UIP_UDP
+ if(BUF->proto == UIP_PROTO_UDP)
+ goto udp_input;
+#endif /* UIP_UDP */
+
+ if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
+ here. */
+ UIP_STAT(++uip_stat.ip.drop);
+ UIP_STAT(++uip_stat.ip.protoerr);
+ UIP_LOG("ip: neither tcp nor icmp.");
+ goto drop;
+ }
+
+ icmp_input:
+ UIP_STAT(++uip_stat.icmp.recv);
+
+ /* ICMP echo (i.e., ping) processing. This is simple, we only change
+ the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
+ checksum before we return the packet. */
+ if(ICMPBUF->type != ICMP_ECHO) {
+ UIP_STAT(++uip_stat.icmp.drop);
+ UIP_STAT(++uip_stat.icmp.typeerr);
+ UIP_LOG("icmp: not icmp echo.");
+ goto drop;
+ }
+
+ /* If we are configured to use ping IP address assignment, we use
+ the destination IP address of this ping packet and assign it to
+ ourself. */
+#if UIP_PINGADDRCONF
+ if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
+ uip_hostaddr[0] = BUF->destipaddr[0];
+ uip_hostaddr[1] = BUF->destipaddr[1];
+ }
+#endif /* UIP_PINGADDRCONF */
+
+ ICMPBUF->type = ICMP_ECHO_REPLY;
+
+ if(ICMPBUF->icmpchksum >= htons(0xffff - (ICMP_ECHO << 8))) {
+ ICMPBUF->icmpchksum += htons(ICMP_ECHO << 8) + 1;
+ } else {
+ ICMPBUF->icmpchksum += htons(ICMP_ECHO << 8);
+ }
+
+ /* Swap IP addresses. */
+ tmpport = BUF->destipaddr[0];
+ BUF->destipaddr[0] = BUF->srcipaddr[0];
+ BUF->srcipaddr[0] = tmpport;
+ tmpport = BUF->destipaddr[1];
+ BUF->destipaddr[1] = BUF->srcipaddr[1];
+ BUF->srcipaddr[1] = tmpport;
+
+ UIP_STAT(++uip_stat.icmp.sent);
+ goto send;
+
+ /* End of IPv4 input header processing code. */
+
+#endif /* UIP_IPV6 */
+
+#if UIP_UDP
+ /* UDP input processing. */
+ udp_input:
+ /* UDP processing is really just a hack. We don't do anything to the
+ UDP/IP headers, but let the UDP application do all the hard
+ work. If the application sets uip_slen, it has a packet to
+ send. */
+#if UIP_UDP_CHECKSUMS
+ if(uip_udpchksum() != 0xffff) {
+ UIP_STAT(++uip_stat.udp.drop);
+ UIP_STAT(++uip_stat.udp.chkerr);
+ UIP_LOG("udp: bad checksum.");
+ goto drop;
+ }
+#endif /* UIP_UDP_CHECKSUMS */
+
+ /* Demultiplex this UDP packet between the UDP "connections". */
+ for(uip_udp_conn = &uip_udp_conns[0];
+ uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
+ ++uip_udp_conn) {
+ if(uip_udp_conn->lport != 0 &&
+ UDPBUF->destport == uip_udp_conn->lport &&
+ (uip_udp_conn->rport == 0 ||
+ UDPBUF->srcport == uip_udp_conn->rport) &&
+#if UIP_IPV6
+ BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
+ BUF->srcipaddr[1] == uip_connr->ripaddr[1] &&
+ BUF->srcipaddr[2] == uip_connr->ripaddr[2] &&
+ BUF->srcipaddr[3] == uip_connr->ripaddr[3] &&
+ BUF->srcipaddr[4] == uip_connr->ripaddr[4] &&
+ BUF->srcipaddr[5] == uip_connr->ripaddr[5] &&
+ BUF->srcipaddr[6] == uip_connr->ripaddr[6] &&
+ BUF->srcipaddr[7] == uip_connr->ripaddr[7]) {
+#else /* UIP_IPV6 */
+ BUF->srcipaddr[0] == uip_udp_conn->ripaddr[0] &&
+ BUF->srcipaddr[1] == uip_udp_conn->ripaddr[1]) {
+#endif /* UIP_IPV6 */
+ goto udp_found;
+ }
+ }
+ goto drop;
+
+ udp_found:
+ uip_len = uip_len - 28;
+ uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
+ uip_flags = UIP_NEWDATA;
+ uip_slen = 0;
+ UIP_UDP_APPCALL();
+ udp_send:
+ if(uip_slen == 0) {
+ goto drop;
+ }
+ uip_len = uip_slen + 28;
+
+#if UIP_BUFSIZE > 255
+ BUF->len[0] = (uip_len >> 8);
+ BUF->len[1] = (uip_len & 0xff);
+#else
+ BUF->len[0] = 0;
+ BUF->len[1] = uip_len;
+#endif /* UIP_BUFSIZE > 255 */
+ BUF->proto = UIP_PROTO_UDP;
+
+ UDPBUF->udplen = htons(uip_slen + 8);
+ UDPBUF->udpchksum = 0;
+#if UIP_UDP_CHECKSUMS
+ /* Calculate UDP checksum. */
+ UDPBUF->udpchksum = ~(uip_udpchksum());
+ if(UDPBUF->udpchksum == 0) {
+ UDPBUF->udpchksum = 0xffff;
+ }
+#endif /* UIP_UDP_CHECKSUMS */
+
+ BUF->srcport = uip_udp_conn->lport;
+ BUF->destport = uip_udp_conn->rport;
+
+#if UIP_IPV6
+ for(c = 0; c < 8; ++c) {
+ BUF->srcipaddr[c] = uip_hostaddr[c];
+ BUF->destipaddr[c] = uip_udp_conn->ripaddr[c];
+ }
+#else /* UIP_IPV6 */
+ BUF->srcipaddr[0] = uip_hostaddr[0];
+ BUF->srcipaddr[1] = uip_hostaddr[1];
+ BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
+ BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
+
+#endif /* UIP_IPV6 */
+
+ uip_appdata = &uip_buf[UIP_LLH_LEN + 40];
+ goto ip_send_nolen;
+#endif /* UIP_UDP */
+
+ /* TCP input processing. */
+ tcp_input:
+ UIP_STAT(++uip_stat.tcp.recv);
+
+ /* Start of TCP input header processing code. */
+
+ if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
+ checksum. */
+ UIP_STAT(++uip_stat.tcp.drop);
+ UIP_STAT(++uip_stat.tcp.chkerr);
+ UIP_LOG("tcp: bad checksum.");
+ goto drop;
+ }
+
+ /* Demultiplex this segment. */
+ /* First check any active connections. */
+ for(uip_connr = &uip_conns[0]; uip_connr < &uip_conns[UIP_CONNS]; ++uip_connr) {
+ if(uip_connr->tcpstateflags != CLOSED &&
+ BUF->destport == uip_connr->lport &&
+ BUF->srcport == uip_connr->rport &&
+#if UIP_IPV6
+ BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
+ BUF->srcipaddr[1] == uip_connr->ripaddr[1] &&
+ BUF->srcipaddr[2] == uip_connr->ripaddr[2] &&
+ BUF->srcipaddr[3] == uip_connr->ripaddr[3] &&
+ BUF->srcipaddr[4] == uip_connr->ripaddr[4] &&
+ BUF->srcipaddr[5] == uip_connr->ripaddr[5] &&
+ BUF->srcipaddr[6] == uip_connr->ripaddr[6] &&
+ BUF->srcipaddr[7] == uip_connr->ripaddr[7]) {
+#else /* UIP_IPV6 */
+ BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
+ BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
+#endif /* UIP_IPV6 */
+ goto found;
+ }
+ }
+
+ /* If we didn't find and active connection that expected the packet,
+ either this packet is an old duplicate, or this is a SYN packet
+ destined for a connection in LISTEN. If the SYN flag isn't set,
+ it is an old packet and we send a RST. */
+ if((BUF->flags & TCP_CTL) != TCP_SYN)
+ goto reset;
+
+ tmpport = BUF->destport;
+ /* Next, check listening connections. */
+ for(c = 0; c < UIP_LISTENPORTS && uip_listenports[c] != 0; ++c) {
+ if(tmpport == uip_listenports[c])
+ goto found_listen;
+ }
+
+ /* No matching connection found, so we send a RST packet. */
+ UIP_STAT(++uip_stat.tcp.synrst);
+ reset:
+
+ /* We do not send resets in response to resets. */
+ if(BUF->flags & TCP_RST)
+ goto drop;
+
+ UIP_STAT(++uip_stat.tcp.rst);
+
+ BUF->flags = TCP_RST | TCP_ACK;
+ uip_len = 40;
+ BUF->tcpoffset = 5 << 4;
+
+ /* Flip the seqno and ackno fields in the TCP header. */
+ c = BUF->seqno[3];
+ BUF->seqno[3] = BUF->ackno[3];
+ BUF->ackno[3] = c;
+
+ c = BUF->seqno[2];
+ BUF->seqno[2] = BUF->ackno[2];
+ BUF->ackno[2] = c;
+
+ c = BUF->seqno[1];
+ BUF->seqno[1] = BUF->ackno[1];
+ BUF->ackno[1] = c;
+
+ c = BUF->seqno[0];
+ BUF->seqno[0] = BUF->ackno[0];
+ BUF->ackno[0] = c;
+
+ /* We also have to increase the sequence number we are
+ acknowledging. If the least significant byte overflowed, we need
+ to propagate the carry to the other bytes as well. */
+ if(++BUF->ackno[3] == 0) {
+ if(++BUF->ackno[2] == 0) {
+ if(++BUF->ackno[1] == 0) {
+ ++BUF->ackno[0];
+ }
+ }
+ }
+
+ /* Swap port numbers. */
+ tmpport = BUF->srcport;
+ BUF->srcport = BUF->destport;
+ BUF->destport = tmpport;
+
+ /* Swap IP addresses. */
+#if UIP_IPV6
+ for(c = 0; c < 8; ++c) {
+ tmpport = BUF->destipaddr[c];
+ BUF->destipaddr[c] = BUF->srcipaddr[c];
+ BUF->srcipaddr[c] = tmpport;
+ }
+#else /* UIP_IPV6 */
+ tmpport = BUF->destipaddr[0];
+ BUF->destipaddr[0] = BUF->srcipaddr[0];
+ BUF->srcipaddr[0] = tmpport;
+ tmpport = BUF->destipaddr[1];
+ BUF->destipaddr[1] = BUF->srcipaddr[1];
+ BUF->srcipaddr[1] = tmpport;
+#endif /* UIP_IPv6 */
+
+ /* And send out the RST packet! */
+ goto tcp_send_noconn;
+
+ /* This label will be jumped to if we matched the incoming packet
+ with a connection in LISTEN. In that case, we should create a new
+ connection and send a SYNACK in return. */
+ found_listen:
+ /* First we check if there are any connections avaliable. Unused
+ connections are kept in the same table as used connections, but
+ unused ones have the tcpstate set to CLOSED. Also, connections in
+ TIME_WAIT are kept track of and we'll use the oldest one if no
+ CLOSED connections are found. Thanks to Eddie C. Dost for a very
+ nice algorithm for the TIME_WAIT search. */
+ uip_connr = 0;
+ for(c = 0; c < UIP_CONNS; ++c) {
+ if(uip_conns[c].tcpstateflags == CLOSED) {
+ uip_connr = &uip_conns[c];
+ break;
+ }
+ if(uip_conns[c].tcpstateflags == TIME_WAIT) {
+ if(uip_connr == 0 ||
+ uip_conns[c].timer > uip_connr->timer) {
+ uip_connr = &uip_conns[c];
+ }
+ }
+ }
+
+ if(uip_connr == 0) {
+ /* All connections are used already, we drop packet and hope that
+ the remote end will retransmit the packet at a time when we
+ have more spare connections. */
+ UIP_STAT(++uip_stat.tcp.syndrop);
+ UIP_LOG("tcp: found no unused connections.");
+ goto drop;
+ }
+ uip_conn = uip_connr;
+
+ /* Fill in the necessary fields for the new connection. */
+ uip_connr->timer = UIP_RTO;
+ uip_connr->nrtx = 0;
+ uip_connr->lport = BUF->destport;
+ uip_connr->rport = BUF->srcport;
+#if UIP_IPV6
+ for(c = 0; c < 8; ++c) {
+ uip_connr->ripaddr[c] = BUF->srcipaddr[c];
+ }
+#else /* UIP_IPV6 */
+ uip_connr->ripaddr[0] = BUF->srcipaddr[0];
+ uip_connr->ripaddr[1] = BUF->srcipaddr[1];
+#endif /* UIP_IPV6 */
+ uip_connr->tcpstateflags = SYN_RCVD;
+
+ uip_connr->snd_nxt[0] = iss[0];
+ uip_connr->snd_nxt[1] = iss[1];
+ uip_connr->snd_nxt[2] = iss[2];
+ uip_connr->snd_nxt[3] = iss[3];
+ uip_connr->len = 1;
+
+ /* rcv_nxt should be the seqno from the incoming packet + 1. */
+ uip_connr->rcv_nxt[3] = BUF->seqno[3];
+ uip_connr->rcv_nxt[2] = BUF->seqno[2];
+ uip_connr->rcv_nxt[1] = BUF->seqno[1];
+ uip_connr->rcv_nxt[0] = BUF->seqno[0];
+ uip_add_rcv_nxt(1);
+
+ /* Parse the TCP MSS option, if present. */
+ if((BUF->tcpoffset & 0xf0) > 0x50) {
+ for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
+ opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
+ if(opt == 0x00) {
+ /* End of options. */
+ break;
+ } else if(opt == 0x01) {
+ ++c;
+ /* NOP option. */
+ } else if(opt == 0x02 &&
+ uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
+ /* An MSS option with the right option length. */
+ tmpport = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+ uip_buf[40 + UIP_LLH_LEN + 3 + c];
+ uip_connr->mss = tmpport > UIP_TCP_MSS? UIP_TCP_MSS: tmpport;
+
+ /* And we are done processing options. */
+ break;
+ } else {
+ /* All other options have a length field, so that we easily
+ can skip past them. */
+ if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
+ /* If the length field is zero, the options are malformed
+ and we don't process them further. */
+ break;
+ }
+ c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
+ }
+ }
+ }
+
+ /* Our response will be a SYNACK. */
+#if UIP_ACTIVE_OPEN
+ tcp_send_synack:
+ BUF->flags = TCP_ACK;
+
+ tcp_send_syn:
+ BUF->flags |= TCP_SYN;
+#else /* UIP_ACTIVE_OPEN */
+ tcp_send_synack:
+ BUF->flags = TCP_SYN | TCP_ACK;
+#endif /* UIP_ACTIVE_OPEN */
+
+ /* We send out the TCP Maximum Segment Size option with our
+ SYNACK. */
+ BUF->optdata[0] = 2;
+ BUF->optdata[1] = 4;
+ BUF->optdata[2] = (UIP_TCP_MSS) / 256;
+ BUF->optdata[3] = (UIP_TCP_MSS) & 255;
+ uip_len = 44;
+ BUF->tcpoffset = 6 << 4;
+ goto tcp_send;
+
+ /* This label will be jumped to if we found an active connection. */
+ found:
+ uip_conn = uip_connr;
+ uip_flags = 0;
+
+ /* We do a very naive form of TCP reset processing; we just accept
+ any RST and kill our connection. We should in fact check if the
+ sequence number of this reset is wihtin our advertised window
+ before we accept the reset. */
+ if(BUF->flags & TCP_RST) {
+ uip_connr->tcpstateflags = CLOSED;
+ UIP_LOG("tcp: got reset, aborting connection.");
+ uip_flags = UIP_ABORT;
+ UIP_APPCALL();
+ goto drop;
+ }
+ /* All segments that are come thus far should have the ACK flag set,
+ otherwise we drop the packet. */
+ if(!(BUF->flags & TCP_ACK)) {
+ UIP_STAT(++uip_stat.tcp.drop);
+ UIP_STAT(++uip_stat.tcp.ackerr);
+ UIP_LOG("tcp: dropped non-ack segment.");
+ goto drop;
+ }
+
+ /* Calculated the length of the data, if the application has sent
+ any data to us. */
+ c = (BUF->tcpoffset >> 4) << 2;
+ /* uip_len will contain the length of the actual TCP data. This is
+ calculated by subtracing the length of the TCP header (in
+ c) and the length of the IP header (20 bytes). */
+ uip_len = uip_len - c - 20;
+
+ /* First, check if the sequence number of the incoming packet is
+ what we're expecting next. If not, we send out an ACK with the
+ correct numbers in. */
+ if(uip_len > 0 &&
+ (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
+ BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
+ BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
+ BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
+ goto tcp_send_ack;
+ }
+
+ /* Next, check if the incoming segment acknowledges any outstanding
+ data. If so, we update the sequence number, reset the length of
+ the outstanding data, calculate RTT estimations, and reset the
+ retransmission timer. */
+ if(uip_outstanding(uip_connr)) {
+ uip_add32(uip_connr->snd_nxt, uip_connr->len);
+ if(BUF->ackno[0] == uip_acc32[0] &&
+ BUF->ackno[1] == uip_acc32[1] &&
+ BUF->ackno[2] == uip_acc32[2] &&
+ BUF->ackno[3] == uip_acc32[3]) {
+ /* Update sequence number. */
+ uip_connr->snd_nxt[0] = uip_acc32[0];
+ uip_connr->snd_nxt[1] = uip_acc32[1];
+ uip_connr->snd_nxt[2] = uip_acc32[2];
+ uip_connr->snd_nxt[3] = uip_acc32[3];
+
+ /* Do RTT estimation, unless we have done retransmissions. */
+ if(uip_connr->nrtx == 0) {
+ signed char m;
+ m = (UIP_RTO << (uip_connr->nrtx > 4? 4: uip_connr->nrtx)) - uip_connr->timer;
+ /* This is taken directly from VJs original code in his paper */
+ m = m - (uip_connr->sa >> 3);
+ uip_connr->sa += m;
+ if(m < 0) {
+ m = -m;
+ }
+ m = m - (uip_connr->sv >> 2);
+ uip_connr->sv += m;
+ uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
+
+ }
+
+ /* Set the acknowledged flag. */
+ uip_flags = UIP_ACKDATA;
+ /* Reset the length of the outstanding data. */
+ uip_connr->len = 0;
+ /* Reset the retransmission timer. */
+ uip_connr->timer = UIP_RTO;
+ }
+ }
+
+ /* Do different things depending on in what state the connection is. */
+ switch(uip_connr->tcpstateflags & TS_MASK) {
+ /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
+ implemented, since we force the application to close when the
+ peer sends a FIN (hence the application goes directly from
+ ESTABLISHED to LAST_ACK). */
+ case SYN_RCVD:
+ /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
+ we are waiting for an ACK that acknowledges the data we sent
+ out the last time. Therefore, we want to have the UIP_ACKDATA
+ flag set. If so, we enter the ESTABLISHED state. */
+ if(uip_flags & UIP_ACKDATA) {
+ uip_connr->tcpstateflags = ESTABLISHED;
+ uip_flags = UIP_CONNECTED;
+ if(uip_len > 0) {
+ uip_flags |= UIP_NEWDATA;
+ uip_add_rcv_nxt(uip_len);
+ }
+ uip_slen = 0;
+ UIP_APPCALL();
+ goto appsend;
+ }
+ goto drop;
+#if UIP_ACTIVE_OPEN
+ case SYN_SENT:
+ /* In SYN_SENT, we wait for a SYNACK that is sent in response to
+ our SYN. The rcv_nxt is set to sequence number in the SYNACK
+ plus one, and we send an ACK. We move into the ESTABLISHED
+ state. */
+ if((uip_flags & UIP_ACKDATA) &&
+ BUF->flags == (TCP_SYN | TCP_ACK)) {
+
+ /* Parse the TCP MSS option, if present. */
+ if((BUF->tcpoffset & 0xf0) > 0x50) {
+ for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
+ opt = uip_buf[40 + UIP_LLH_LEN + c];
+ if(opt == 0x00) {
+ /* End of options. */
+ break;
+ } else if(opt == 0x01) {
+ ++c;
+ /* NOP option. */
+ } else if(opt == 0x02 &&
+ uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
+ /* An MSS option with the right option length. */
+ tmpport = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+ uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
+ uip_connr->mss = tmpport > UIP_TCP_MSS? UIP_TCP_MSS: tmpport;
+
+ /* And we are done processing options. */
+ break;
+ } else {
+ /* All other options have a length field, so that we easily
+ can skip past them. */
+ if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
+ /* If the length field is zero, the options are malformed
+ and we don't process them further. */
+ break;
+ }
+ c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
+ }
+ }
+ }
+ uip_connr->tcpstateflags = ESTABLISHED;
+ uip_connr->rcv_nxt[0] = BUF->seqno[0];
+ uip_connr->rcv_nxt[1] = BUF->seqno[1];
+ uip_connr->rcv_nxt[2] = BUF->seqno[2];
+ uip_connr->rcv_nxt[3] = BUF->seqno[3];
+ uip_add_rcv_nxt(1);
+ uip_flags = UIP_CONNECTED | UIP_NEWDATA;
+ uip_len = 0;
+ uip_slen = 0;
+ UIP_APPCALL();
+ goto appsend;
+ }
+ goto reset;
+#endif /* UIP_ACTIVE_OPEN */
+
+ case ESTABLISHED:
+ /* In the ESTABLISHED state, we call upon the application to feed
+ data into the uip_buf. If the UIP_ACKDATA flag is set, the
+ application should put new data into the buffer, otherwise we are
+ retransmitting an old segment, and the application should put that
+ data into the buffer.
+
+ If the incoming packet is a FIN, we should close the connection on
+ this side as well, and we send out a FIN and enter the LAST_ACK
+ state. We require that there is no outstanding data; otherwise the
+ sequence numbers will be screwed up. */
+
+ if(BUF->flags & TCP_FIN) {
+ if(uip_outstanding(uip_connr)) {
+ goto drop;
+ }
+ uip_add_rcv_nxt(1 + uip_len);
+ uip_flags = UIP_CLOSE;
+ if(uip_len > 0) {
+ uip_flags |= UIP_NEWDATA;
+ }
+ UIP_APPCALL();
+ uip_connr->len = 1;
+ uip_connr->tcpstateflags = LAST_ACK;
+ uip_connr->nrtx = 0;
+ tcp_send_finack:
+ BUF->flags = TCP_FIN | TCP_ACK;
+ goto tcp_send_nodata;
+ }
+
+ /* Check the URG flag. If this is set, the segment carries urgent
+ data that we must pass to the application. */
+ if(BUF->flags & TCP_URG) {
+#if UIP_URGDATA > 0
+ uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
+ if(uip_urglen > uip_len) {
+ /* There is more urgent data in the next segment to come. */
+ uip_urglen = uip_len;
+ }
+ uip_add_rcv_nxt(uip_urglen);
+ uip_len -= uip_urglen;
+ uip_urgdata = uip_appdata;
+ uip_appdata += uip_urglen;
+ } else {
+ uip_urglen = 0;
+#endif /* UIP_URGDATA > 0 */
+ uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
+ uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
+ }
+
+
+ /* If uip_len > 0 we have TCP data in the packet, and we flag this
+ by setting the UIP_NEWDATA flag and update the sequence number
+ we acknowledge. If the application has stopped the dataflow
+ using uip_stop(), we must not accept any data packets from the
+ remote host. */
+ if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
+ uip_flags |= UIP_NEWDATA;
+ uip_add_rcv_nxt(uip_len);
+ }
+
+
+ /* If this packet constitutes an ACK for outstanding data (flagged
+ by the UIP_ACKDATA flag, we should call the application since it
+ might want to send more data. If the incoming packet had data
+ from the peer (as flagged by the UIP_NEWDATA flag), the
+ application must also be notified.
+
+ When the application is called, the global variable uip_len
+ contains the length of the incoming data. The application can
+ access the incoming data through the global pointer
+ uip_appdata, which usually points 40 bytes into the uip_buf
+ array.
+
+ If the application wishes to send any data, this data should be
+ put into the uip_appdata and the length of the data should be
+ put into uip_len. If the application don't have any data to
+ send, uip_len must be set to 0. */
+ if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
+ uip_slen = 0;
+ UIP_APPCALL();
+
+ appsend:
+ if(uip_flags & UIP_ABORT) {
+ uip_slen = 0;
+ uip_connr->tcpstateflags = CLOSED;
+ BUF->flags = TCP_RST | TCP_ACK;
+ goto tcp_send_nodata;
+ }
+
+ if(uip_flags & UIP_CLOSE) {
+ uip_slen = 0;
+ uip_connr->len = 1;
+ uip_connr->tcpstateflags = FIN_WAIT_1;
+ uip_connr->nrtx = 0;
+ BUF->flags = TCP_FIN | TCP_ACK;
+ goto tcp_send_nodata;
+ }
+
+ /* If uip_slen > 0, the application has data to be sent. We
+ cannot send data if the application already has outstanding
+ data. */
+ if(uip_slen > 0 &&
+ !uip_outstanding(uip_connr)) {
+ uip_connr->nrtx = 0;
+ uip_connr->len = uip_slen;
+ } else {
+ uip_slen = 0;
+ }
+ apprexmit:
+ /* If the application has data to be sent, or if the incoming
+ packet had new data in it, we must send out a packet. */
+ if(uip_slen > 0 || (uip_flags & UIP_NEWDATA)) {
+ /* Add the length of the IP and TCP headers. */
+ uip_len = uip_connr->len + UIP_TCPIP_HLEN;
+ /* We always set the ACK flag in response packets. */
+ BUF->flags = TCP_ACK;
+ /* Send the packet. */
+ goto tcp_send_noopts;
+ }
+ }
+ goto drop;
+ case LAST_ACK:
+ /* We can close this connection if the peer has acknowledged our
+ FIN. This is indicated by the UIP_ACKDATA flag. */
+ if(uip_flags & UIP_ACKDATA) {
+ uip_connr->tcpstateflags = CLOSED;
+ uip_flags = UIP_CLOSE;
+ UIP_APPCALL();
+ }
+ break;
+
+ case FIN_WAIT_1:
+ /* The application has closed the connection, but the remote host
+ hasn't closed its end yet. Thus we do nothing but wait for a
+ FIN from the other side. */
+ if(uip_len > 0) {
+ uip_add_rcv_nxt(uip_len);
+ }
+ if(BUF->flags & TCP_FIN) {
+ if(uip_flags & UIP_ACKDATA) {
+ uip_connr->tcpstateflags = TIME_WAIT;
+ uip_connr->timer = 0;
+ uip_connr->len = 0;
+ } else {
+ uip_connr->tcpstateflags = CLOSING;
+ }
+ uip_add_rcv_nxt(1);
+ uip_flags = UIP_CLOSE;
+ UIP_APPCALL();
+ goto tcp_send_ack;
+ } else if(uip_flags & UIP_ACKDATA) {
+ uip_connr->tcpstateflags = FIN_WAIT_2;
+ uip_connr->len = 0;
+ goto drop;
+ }
+ if(uip_len > 0) {
+ goto tcp_send_ack;
+ }
+ goto drop;
+
+ case FIN_WAIT_2:
+ if(uip_len > 0) {
+ uip_add_rcv_nxt(uip_len);
+ }
+ if(BUF->flags & TCP_FIN) {
+ uip_connr->tcpstateflags = TIME_WAIT;
+ uip_connr->timer = 0;
+ uip_add_rcv_nxt(1);
+ uip_flags = UIP_CLOSE;
+ UIP_APPCALL();
+ goto tcp_send_ack;
+ }
+ if(uip_len > 0) {
+ goto tcp_send_ack;
+ }
+ goto drop;
+
+ case TIME_WAIT:
+ goto tcp_send_ack;
+
+ case CLOSING:
+ if(uip_flags & UIP_ACKDATA) {
+ uip_connr->tcpstateflags = TIME_WAIT;
+ uip_connr->timer = 0;
+ }
+ }
+ goto drop;
+
+
+ /* We jump here when we are ready to send the packet, and just want
+ to set the appropriate TCP sequence numbers in the TCP header. */
+ tcp_send_ack:
+ BUF->flags = TCP_ACK;
+ tcp_send_nodata:
+ uip_len = 40;
+ tcp_send_noopts:
+ BUF->tcpoffset = 5 << 4;
+ tcp_send:
+ /* We're done with the input processing. We are now ready to send a
+ reply. Our job is to fill in all the fields of the TCP and IP
+ headers before calculating the checksum and finally send the
+ packet. */
+ BUF->ackno[0] = uip_connr->rcv_nxt[0];
+ BUF->ackno[1] = uip_connr->rcv_nxt[1];
+ BUF->ackno[2] = uip_connr->rcv_nxt[2];
+ BUF->ackno[3] = uip_connr->rcv_nxt[3];
+
+ BUF->seqno[0] = uip_connr->snd_nxt[0];
+ BUF->seqno[1] = uip_connr->snd_nxt[1];
+ BUF->seqno[2] = uip_connr->snd_nxt[2];
+ BUF->seqno[3] = uip_connr->snd_nxt[3];
+
+ BUF->proto = UIP_PROTO_TCP;
+
+ BUF->srcport = uip_connr->lport;
+ BUF->destport = uip_connr->rport;
+
+#if UIP_IPV6
+ for(c = 0; c < 8; ++c) {
+ BUF->srcipaddr[c] = uip_hostaddr[c];
+ BUF->destipaddr[c] = uip_connr->ripaddr[c];
+ }
+#else /* UIP_IPV6 */
+ BUF->srcipaddr[0] = uip_hostaddr[0];
+ BUF->srcipaddr[1] = uip_hostaddr[1];
+ BUF->destipaddr[0] = uip_connr->ripaddr[0];
+ BUF->destipaddr[1] = uip_connr->ripaddr[1];
+
+#endif /* UIP_IPV6 */
+
+ if(uip_connr->tcpstateflags & UIP_STOPPED) {
+ /* If the connection has issued uip_stop(), we advertise a zero
+ window so that the remote host will stop sending data. */
+ BUF->wnd[0] = BUF->wnd[1] = 0;
+ } else {
+#if (UIP_TCP_MSS) > 255
+ BUF->wnd[0] = (uip_connr->mss >> 8);
+#else
+ BUF->wnd[0] = 0;
+#endif /* UIP_MSS */
+ BUF->wnd[1] = (uip_connr->mss & 0xff);
+ }
+
+ tcp_send_noconn:
+
+#if UIP_BUFSIZE > 255
+ BUF->len[0] = (uip_len >> 8);
+ BUF->len[1] = (uip_len & 0xff);
+#else
+ BUF->len[0] = 0;
+ BUF->len[1] = uip_len;
+#endif /* UIP_BUFSIZE > 255 */
+
+ /* Calculate TCP checksum. */
+ BUF->tcpchksum = 0;
+ BUF->tcpchksum = ~(uip_tcpchksum());
+
+ ip_send_nolen:
+
+#if UIP_IPV6
+ BUF->vtc = 0x60;
+ BUF->tcfl = 0x00;
+ BUF->fl = 0x0000;
+ BUF->hoplim = UIP_TTL;
+ BUF->nxthdr = UIP_PROTO_TCP;
+#else /* UIP_IPV6 */
+ BUF->vhl = 0x45;
+ BUF->tos = 0;
+ BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
+ BUF->ttl = UIP_TTL;
+ ++ipid;
+ BUF->ipid[0] = ipid >> 8;
+ BUF->ipid[1] = ipid & 0xff;
+
+ /* Calculate IP checksum. */
+ BUF->ipchksum = 0;
+ BUF->ipchksum = ~(uip_ipchksum());
+#endif /* UIP_IPV6 */
+
+ UIP_STAT(++uip_stat.tcp.sent);
+ send:
+ UIP_STAT(++uip_stat.ip.sent);
+ /* Return and let the caller do the actual transmission. */
+ return;
+ drop:
+ uip_len = 0;
+ return;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/uip/uip.h b/contiki/uip/uip.h
new file mode 100644
index 0000000..4ff91f0
--- /dev/null
+++ b/contiki/uip/uip.h
@@ -0,0 +1,671 @@
+/*
+ * Copyright (c) 2001-2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.h,v 1.1 2003/03/19 14:16:07 adamdunkels Exp $
+ *
+ */
+
+#ifndef __UIP_H__
+#define __UIP_H__
+
+#include "uipopt.h"
+
+#ifndef UIP_IPV6
+#define UIP_IPV6 0
+#endif
+
+/*-----------------------------------------------------------------------------------*/
+/* First, the functions that should be called from the
+ * system. Initialization, the periodic timer and incoming packets are
+ * handled by the following three functions.
+ */
+
+/* uip_init(void):
+ *
+ * Must be called at boot up to configure the uIP data structures.
+ */
+void uip_init(void);
+
+/* uip_periodic(conn):
+ *
+ * Should be called when the periodic timer has fired. Should be
+ * called once per connection (0 - UIP_CONNS).
+ */
+#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \
+ uip_process(UIP_TIMER); } while (0)
+
+/* uip_input(void):
+ *
+ * Is called when the network device driver has received new data.
+ */
+#define uip_input() uip_process(UIP_DATA)
+
+/* uip_sethostaddr(addr):
+ *
+ * Is used to set the IP address.
+ */
+#define uip_sethostaddr(addr) do { uip_hostaddr[0] = addr[0]; \
+ uip_hostaddr[1] = addr[1]; } while(0)
+
+#if UIP_UDP
+/* uip_udp_periodic(conn):
+ */
+#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \
+ uip_process(UIP_UDP_TIMER); } while (0)
+#endif /* UIP_UDP */
+/*-----------------------------------------------------------------------------------*/
+/* Functions that are used by the uIP application program. Opening and
+ * closing connections, sending and receiving data, etc. is all
+ * handled by the functions below.
+*/
+
+/* uip_listen(port):
+ *
+ * Starts listening to the specified port.
+ */
+void uip_listen(u16_t port);
+
+/* uip_connect(ripaddr, port):
+ *
+ * Returns a connection identifier that connects to a port on the
+ * specified host (given in ripaddr). If no connections are avaliable,
+ * the function returns NULL. This function is avaliable only if
+ * support for active open has been configured (#define
+ * UIP_ACTIVE_OPEN 1 in uipopt.h)
+ */
+struct uip_conn *uip_connect(u16_t *ripaddr, u16_t port);
+
+#if UIP_UDP
+/* uip_udp_new(ripaddr, rport):
+ *
+ * Sets up a new UDP "connection" with the specified parameters.
+ */
+struct uip_udp_conn *uip_udp_new(u16_t *ripaddr, u16_t rport);
+
+/* uip_udp_remove(conn):
+ *
+ * Removes the UDP "connection".
+ */
+#define uip_udp_remove(conn) (conn)->lport = 0
+
+/* uip_udp_send(len):
+ *
+ * Sends a UDP datagram of length len. The data must be present in the
+ * uip_buf buffer (pointed to by uip_appdata).
+ */
+#define uip_udp_send(len) uip_slen = (len)
+#endif /* UIP_UDP */
+
+
+/* uip_outstanding(conn):
+ *
+ * Checks whether a connection has outstanding (i.e., unacknowledged)
+ * data.
+ */
+#define uip_outstanding(conn) ((conn)->len)
+
+/* uip_send(data, len):
+ *
+ * Send data on the current connection. The length of the data must
+ * not exceed the maxium segment size (MSS) for the connection.
+ */
+#define uip_send(data, len) do { uip_appdata = (data); uip_slen = (len);} while(0)
+
+/* uip_datalen():
+ *
+ * The length of the data that is currently avaliable (if avaliable)
+ * in the uip_appdata buffer. The test function uip_data() is
+ * used to check if data is avaliable.
+ */
+#define uip_datalen() uip_len
+
+#define uip_urgdatalen() uip_urglen
+
+/* uip_close():
+ *
+ * Close the current connection.
+ */
+#define uip_close() (uip_flags = UIP_CLOSE)
+
+/* uip_abort():
+ *
+ * Abort the current connection.
+ */
+#define uip_abort() (uip_flags = UIP_ABORT)
+
+/* uip_stop():
+ *
+ * Close our receiver's window so that we stop receiving data for the
+ * current connection.
+ */
+#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED)
+
+/* uip_stopped():
+ *
+ * Find out if the current connection has been previously stopped.
+ */
+#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED)
+
+/* uip_restart():
+ *
+ * Open the window again so that we start receiving data for the
+ * current connection.
+ */
+#define uip_restart() do { uip_flags |= UIP_NEWDATA; \
+ uip_conn->tcpstateflags &= ~UIP_STOPPED; \
+ } while(0)
+
+
+/* uIP tests that can be made to determine in what state the current
+ connection is, and what the application function should do. */
+
+/* uip_newdata():
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ */
+#define uip_newdata() (uip_flags & UIP_NEWDATA)
+
+/* uip_acked():
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data. uip_reset_acked() can be used to reset the acked
+ * flag.
+ */
+#define uip_acked() (uip_flags & UIP_ACKDATA)
+#define uip_reset_acked() (uip_flags &= ~UIP_ACKDATA)
+
+/* uip_connected():
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ */
+#define uip_connected() (uip_flags & UIP_CONNECTED)
+
+/* uip_closed():
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may do the necessary clean-ups.
+ */
+#define uip_closed() (uip_flags & UIP_CLOSE)
+
+/* uip_aborted():
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ */
+#define uip_aborted() (uip_flags & UIP_ABORT)
+
+/* uip_timedout():
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ */
+#define uip_timedout() (uip_flags & UIP_TIMEDOUT)
+
+/* uip_rexmit():
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should set the uip_appdata buffer and the uip_len
+ * variable just as it did the last time this data was to be
+ * transmitted.
+ */
+#define uip_rexmit() (uip_flags & UIP_REXMIT)
+
+/* uip_poll():
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ */
+#define uip_poll() (uip_flags & UIP_POLL)
+
+/* uip_mss():
+ *
+ * Gives the current maxium segment size (MSS) of the current
+ * connection.
+ */
+#define uip_mss() (uip_conn->mss)
+
+
+/* uIP convenience and converting functions. */
+
+/* uip_ipaddr(&ipaddr, addr0,addr1,addr2,addr3):
+ *
+ * Packs an IP address into a two element 16-bit array. Such arrays
+ * are used to represent IP addresses in uIP.
+ */
+#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \
+ (addr)[0] = htons(((addr0) << 8) | (addr1)); \
+ (addr)[1] = htons(((addr2) << 8) | (addr3)); \
+ } while(0)
+
+/* htons(), ntohs():
+ *
+ * Macros for converting 16-bit quantities between host and network
+ * byte order.
+ */
+#ifndef htons
+# if BYTE_ORDER == BIG_ENDIAN
+# define htons(n) (n)
+# else /* BYTE_ORDER == BIG_ENDIAN */
+# define htons(n) ((((u16_t)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
+# endif /* BYTE_ORDER == BIG_ENDIAN */
+#endif /* htons */
+
+#define ntohs(n) htons(n)
+
+
+/*-----------------------------------------------------------------------------------*/
+/* The following global variables are used for passing parameters
+ * between uIP, the network device driver and the application. */
+/*-----------------------------------------------------------------------------------*/
+
+/* u8_t uip_buf[UIP_BUFSIZE]:
+ *
+ * The uip_buf array is used to hold incoming and outgoing
+ * packets. The device driver fills this with incoming packets.
+ */
+extern u8_t uip_buf[UIP_BUFSIZE];
+
+/* u8_t *uip_appdata:
+ *
+ * This pointer points to the application data when the application is
+ * called. If the application wishes to send data, this is where the
+ * application should write it. The application can also point this to
+ * another location.
+ */
+extern volatile u8_t *uip_appdata;
+
+#if UIP_URGDATA > 0
+/* u8_t *uip_urgdata:
+ *
+ * This pointer points to any urgent data that has been received. Only
+ * present if compiled with support for urgent data (UIP_URGDATA).
+ */
+extern volatile u8_t *uip_urgdata;
+#endif /* UIP_URGDATA > 0 */
+
+
+/* u[8|16]_t uip_len:
+ *
+ * When the application is called, uip_len contains the length of any
+ * new data that has been received from the remote host. The
+ * application should set this variable to the size of any data that
+ * the application wishes to send. When the network device driver
+ * output function is called, uip_len should contain the length of the
+ * outgoing packet.
+ */
+#if UIP_BUFSIZE > 255
+extern volatile u16_t uip_len, uip_slen;
+#else
+extern volatile u8_t uip_len, uip_slen;
+#endif
+
+#if UIP_URGDATA > 0
+extern volatile u8_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+extern volatile u8_t uip_acc32[4];
+
+/* struct uip_conn:
+ *
+ * The uip_conn structure is used for identifying a connection. All
+ * but one field in the structure are to be considered read-only by an
+ * application. The only exception is the appstate field whos purpose
+ * is to let the application store application-specific state (e.g.,
+ * file pointers) for the connection. The size of this field is
+ * configured in the "uipopt.h" header file.
+ */
+struct uip_conn {
+#if UIP_IPV6
+ u16_t ripaddr[8]; /* The IP address of the remote peer. */
+#else /* UIP_IPV6 */
+ u16_t ripaddr[2]; /* The IP address of the remote peer. */
+#endif /* UIP_IPV6 */
+
+ u16_t lport, rport; /* The local and the remote port. */
+
+ u8_t rcv_nxt[4]; /* The sequence number that we expect to receive
+ next. */
+ u8_t snd_nxt[4]; /* The sequence number that was last sent by
+ us. */
+#if UIP_TCP_MSS > 255
+ u16_t len;
+ u16_t mss; /* Maximum segment size for the connection. */
+#else
+ u8_t len;
+ u8_t mss;
+#endif /* UIP_TCP_MSS */
+ u8_t sa, sv, rto;
+ u8_t tcpstateflags; /* TCP state and flags. */
+ u8_t timer; /* The retransmission timer. */
+ u8_t nrtx; /* Counts the number of retransmissions for a
+ particular segment. */
+
+ u8_t appstate[UIP_APPSTATE_SIZE];
+};
+
+/* struct uip_conn *uip_conn:
+ *
+ * When the application is called, uip_conn will point to the current
+ * conntection, the one that should be processed by the
+ * application. The uip_conns[] array is a list containing all
+ * connections.
+ */
+extern struct uip_conn *uip_conn;
+extern struct uip_conn uip_conns[UIP_CONNS];
+
+#if UIP_UDP
+/* struct uip_udp_conn:
+ *
+ * The uip_udp_conn structure is used for identifying UDP
+ * "connections".
+ */
+struct uip_udp_conn {
+#if UIP_IPV6
+ u16_t ripaddr[8]; /* The IP address of the remote peer. */
+#else /* UIP_IPV6 */
+ u16_t ripaddr[2]; /* The IP address of the remote peer. */
+#endif /* UIP_IPV6 */
+ u16_t lport, rport;
+};
+
+extern struct uip_udp_conn *uip_udp_conn;
+extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+/* struct uip_stats:
+ *
+ * Contains statistics about the TCP/IP stack.
+ */
+struct uip_stats {
+ struct {
+ uip_stats_t drop;
+ uip_stats_t recv;
+ uip_stats_t sent;
+ uip_stats_t vhlerr; /* Number of packets dropped due to wrong IP version
+ or header length. */
+ uip_stats_t hblenerr; /* Number of packets dropped due to wrong IP length,
+ high byte. */
+ uip_stats_t lblenerr; /* Number of packets dropped due to wrong IP length,
+ low byte. */
+ uip_stats_t fragerr; /* Number of packets dropped since they were IP
+ fragments. */
+ uip_stats_t chkerr; /* Number of packets dropped due to IP checksum errors. */
+ uip_stats_t protoerr; /* Number of packets dropped since they were neither
+ ICMP nor TCP. */
+ } ip;
+ struct {
+ uip_stats_t drop;
+ uip_stats_t recv;
+ uip_stats_t sent;
+ uip_stats_t typeerr;
+ } icmp;
+ struct {
+ uip_stats_t drop;
+ uip_stats_t recv;
+ uip_stats_t sent;
+ uip_stats_t chkerr;
+ uip_stats_t ackerr;
+ uip_stats_t rst;
+ uip_stats_t rexmit;
+ uip_stats_t syndrop; /* Number of dropped SYNs due to too few
+ connections was avaliable. */
+ uip_stats_t synrst; /* Number of SYNs for closed ports, triggering a
+ RST. */
+ } tcp;
+};
+
+extern struct uip_stats uip_stat;
+
+
+/*-----------------------------------------------------------------------------------*/
+/* All the stuff below this point is internal to uIP and should not be
+ * used directly by an application or by a device driver.
+ */
+/*-----------------------------------------------------------------------------------*/
+/* u8_t uip_flags:
+ *
+ * When the application is called, uip_flags will contain the flags
+ * that are defined in this file. Please read below for more
+ * infomation.
+ */
+extern volatile u8_t uip_flags;
+
+/* The following flags may be set in the global variable uip_flags
+ before calling the application callback. The UIP_ACKDATA and
+ UIP_NEWDATA flags may both be set at the same time, whereas the
+ others are mutualy exclusive. Note that these flags should *NOT* be
+ accessed directly, but through the uIP functions/macros. */
+
+#define UIP_ACKDATA 1 /* Signifies that the outstanding data was
+ acked and the application should send
+ out new data instead of retransmitting
+ the last data. */
+#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent
+ us new data. */
+#define UIP_REXMIT 4 /* Tells the application to retransmit the
+ data that was last sent. */
+#define UIP_POLL 8 /* Used for polling the application, to
+ check if the application has data that
+ it wants to send. */
+#define UIP_CLOSE 16 /* The remote host has closed the
+ connection, thus the connection has
+ gone away. Or the application signals
+ that it wants to close the
+ connection. */
+#define UIP_ABORT 32 /* The remote host has aborted the
+ connection, thus the connection has
+ gone away. Or the application signals
+ that it wants to abort the
+ connection. */
+#define UIP_CONNECTED 64 /* We have got a connection from a remote
+ host and have set up a new connection
+ for it, or an active connection has
+ been successfully established. */
+
+#define UIP_TIMEDOUT 128 /* The connection has been aborted due to
+ too many retransmissions. */
+
+
+/* uip_process(flag):
+ *
+ * The actual uIP function which does all the work.
+ */
+void uip_process(u8_t flag);
+
+/* The following flags are passed as an argument to the uip_process()
+ function. They are used to distinguish between the two cases where
+ uip_process() is called. It can be called either because we have
+ incoming data that should be processed, or because the periodic
+ timer has fired. */
+
+#define UIP_DATA 1 /* Tells uIP that there is incoming data in
+ the uip_buf buffer. The length of the
+ data is stored in the global variable
+ uip_len. */
+#define UIP_TIMER 2 /* Tells uIP that the periodic timer has
+ fired. */
+#if UIP_UDP
+#define UIP_UDP_TIMER 3
+#endif /* UIP_UDP */
+
+/* The TCP states used in the uip_conn->tcpstateflags. */
+#define CLOSED 0
+#define SYN_RCVD 1
+#define SYN_SENT 2
+#define ESTABLISHED 3
+#define FIN_WAIT_1 4
+#define FIN_WAIT_2 5
+#define CLOSING 6
+#define TIME_WAIT 7
+#define LAST_ACK 8
+#define TS_MASK 15
+
+#define UIP_STOPPED 16
+
+#if UIP_IPV6
+#define UIP_TCPIP_HLEN 60
+#else /* UIP_IPV6 */
+#define UIP_TCPIP_HLEN 40
+#endif /* UIP_IPV6 */
+
+/* The TCP and IP headers. */
+typedef struct {
+ /* IP header. */
+#if UIP_IPV6
+ u8_t vtc,
+ tcfl;
+ u16_t fl;
+ u8_t len[2];
+ u8_t nxthdr, hoplim;
+ u16_t srcipaddr[8],
+ destipaddr[8];
+#else /* UIP_IPV6 */
+ u8_t vhl,
+ tos,
+ len[2],
+ ipid[2],
+ ipoffset[2],
+ ttl,
+ proto;
+ u16_t ipchksum;
+ u16_t srcipaddr[2],
+ destipaddr[2];
+#endif /* UIP_IPV6 */
+
+ /* TCP header. */
+ u16_t srcport,
+ destport;
+ u8_t seqno[4],
+ ackno[4],
+ tcpoffset,
+ flags,
+ wnd[2];
+ u16_t tcpchksum;
+ u8_t urgp[2];
+ u8_t optdata[4];
+} uip_tcpip_hdr;
+
+/* The ICMP and IP headers. */
+typedef struct {
+ /* IP header. */
+#if UIP_IPV6
+ u16_t vtcfl;
+ u16_t fl;
+ u8_t len[2];
+ u8_t nxthdr, hoplim;
+ u16_t srcipaddr[8],
+ destipaddr[8];
+#else /* UIP_IPV6 */
+ u8_t vhl,
+ tos,
+ len[2],
+ ipid[2],
+ ipoffset[2],
+ ttl,
+ proto;
+ u16_t ipchksum;
+ u16_t srcipaddr[2],
+ destipaddr[2];
+#endif /* UIP_IPV6 */
+ /* ICMP (echo) header. */
+ u8_t type, icode;
+ u16_t icmpchksum;
+ u16_t id, seqno;
+} uip_icmpip_hdr;
+
+
+/* The UDP and IP headers. */
+typedef struct {
+ /* IP header. */
+#if UIP_IPV6
+ u8_t vtc,
+ tcfl;
+ u16_t fl;
+ u8_t len[2];
+ u8_t nxthdr, hoplim;
+ u16_t srcipaddr[8],
+ destipaddr[8];
+#else /* UIP_IPV6 */
+ u8_t vhl,
+ tos,
+ len[2],
+ ipid[2],
+ ipoffset[2],
+ ttl,
+ proto;
+ u16_t ipchksum;
+ u16_t srcipaddr[2],
+ destipaddr[2];
+#endif /* UIP_IPV6 */
+
+ /* UDP header. */
+ u16_t srcport,
+ destport;
+ u16_t udplen;
+ u16_t udpchksum;
+} uip_udpip_hdr;
+
+#define UIP_PROTO_ICMP 1
+#define UIP_PROTO_TCP 6
+#define UIP_PROTO_UDP 17
+
+#if UIP_FIXEDADDR
+#if UIP_IPV6
+extern const u16_t uip_hostaddr[8];
+#else /* UIP_IPV6 */
+extern const u16_t uip_hostaddr[2];
+#endif /* UIP_IPV6 */
+#else /* UIP_FIXEDADDR */
+#if UIP_IPV6
+extern u16_t uip_hostaddr[8];
+#else /* UIP_IPV6 */
+extern u16_t uip_hostaddr[2];
+#endif /* UIP_IPV6 */
+#endif /* UIP_FIXEDADDR */
+
+#endif /* __UIP_H__ */
+
+
+
+
+
+
+
diff --git a/contiki/uip/uip_arp.c b/contiki/uip/uip_arp.c
new file mode 100644
index 0000000..e758610
--- /dev/null
+++ b/contiki/uip/uip_arp.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2001-2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arp.c,v 1.1 2003/03/19 14:16:07 adamdunkels Exp $
+ *
+ */
+
+
+#include "uip_arp.h"
+
+struct arp_hdr {
+ struct uip_eth_hdr ethhdr;
+ u16_t hwtype;
+ u16_t protocol;
+ u8_t hwlen;
+ u8_t protolen;
+ u16_t opcode;
+ struct uip_eth_addr shwaddr;
+ u16_t sipaddr[2];
+ struct uip_eth_addr dhwaddr;
+ u16_t dipaddr[2];
+};
+
+struct ethip_hdr {
+ struct uip_eth_hdr ethhdr;
+ /* IP header. */
+ u8_t vhl,
+ tos,
+ len[2],
+ ipid[2],
+ ipoffset[2],
+ ttl,
+ proto;
+ u16_t ipchksum;
+ u16_t srcipaddr[2],
+ destipaddr[2];
+};
+
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+#define ARP_HWTYPE_ETH 1
+
+u16_t uip_arp_draddr[2], uip_arp_netmask[2];
+
+struct arp_entry {
+ u16_t ipaddr[2];
+ struct uip_eth_addr ethaddr;
+ u8_t time;
+};
+
+static const struct uip_eth_addr ethaddr = {{UIP_ETHADDR0,
+ UIP_ETHADDR1,
+ UIP_ETHADDR2,
+ UIP_ETHADDR3,
+ UIP_ETHADDR4,
+ UIP_ETHADDR5}};
+
+static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
+static u16_t ipaddr[2];
+static u8_t i, c;
+
+static u8_t arptime;
+static u8_t tmpage;
+
+#define BUF ((struct arp_hdr *)&uip_buf[0])
+#define IPBUF ((struct ethip_hdr *)&uip_buf[0])
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_init(void)
+{
+ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+ arp_table[i].ipaddr[0] =
+ arp_table[i].ipaddr[1] = 0;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_timer(void)
+{
+ ++arptime;
+ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+ if((arp_table[i].ipaddr[0] | arp_table[i].ipaddr[1]) != 0 &&
+ arptime - arp_table[i].time >= UIP_ARP_MAXAGE) {
+ arp_table[i].ipaddr[0] =
+ arp_table[i].ipaddr[1] = 0;
+ }
+ }
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
+{
+ /* Walk through the ARP mapping table and try to find an entry to
+ update. If none is found, the IP -> MAC address mapping is
+ inserted in the ARP table. */
+ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+
+ /* Only check those entries that are actually in use. */
+ if(arp_table[i].ipaddr[0] != 0 &&
+ arp_table[i].ipaddr[1] != 0) {
+
+ /* Check if the source IP address of the incoming packet matches
+ the IP address in this ARP table entry. */
+ if(ipaddr[0] == arp_table[i].ipaddr[0] &&
+ ipaddr[1] == arp_table[i].ipaddr[1]) {
+
+ /* An old entry found, update this and return. */
+ for(c = 0; c < 6; ++c) {
+ arp_table[i].ethaddr.addr[c] = ethaddr->addr[c];
+ }
+ arp_table[i].time = arptime;
+
+ return;
+ }
+ }
+ }
+
+ /* If we get here, no existing ARP table entry was found, so we
+ create one. */
+
+ /* First, we try to find an unused entry in the ARP table. */
+ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+ if(arp_table[i].ipaddr[0] == 0 &&
+ arp_table[i].ipaddr[1] == 0) {
+ break;
+ }
+ }
+
+ /* If no unused entry is found, we try to find the oldest entry and
+ throw it away. */
+ if(i == UIP_ARPTAB_SIZE) {
+ tmpage = 0;
+ c = 0;
+ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+ if(arptime - arp_table[i].time > tmpage) {
+ tmpage = arptime - arp_table[i].time;
+ c = i;
+ }
+ }
+ i = c;
+ }
+
+ /* Now, i is the ARP table entry which we will fill with the new
+ information. */
+ arp_table[i].ipaddr[0] = ipaddr[0];
+ arp_table[i].ipaddr[1] = ipaddr[1];
+ for(c = 0; c < 6; ++c) {
+ arp_table[i].ethaddr.addr[c] = ethaddr->addr[c];
+ }
+ arp_table[i].time = arptime;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_ipin(void)
+{
+
+ /* Only insert/update an entry if the source IP address of the
+ incoming IP packet comes from a host on the local network. */
+ /* if((IPBUF->srcipaddr[0] & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)) !=
+ (uip_hostaddr[0]
+ & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)))
+ return;
+ if((IPBUF->srcipaddr[1] & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3)) !=
+ (uip_hostaddr[1]
+ & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3)))
+ return;
+ */
+ if((IPBUF->srcipaddr[0] & uip_arp_netmask[0]) !=
+ (uip_hostaddr[0] & uip_arp_netmask[0])) {
+ return;
+ }
+ if((IPBUF->srcipaddr[1] & uip_arp_netmask[1]) !=
+ (uip_hostaddr[1] & uip_arp_netmask[1])) {
+ return;
+ }
+ uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
+
+ return;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_arpin(void)
+{
+
+ if(uip_len < sizeof(struct arp_hdr)) {
+ uip_len = 0;
+ return;
+ }
+
+ uip_len = 0;
+
+ switch(BUF->opcode) {
+ case htons(ARP_REQUEST):
+ /* ARP request. If it asked for our address, we send out a
+ reply. */
+ if(BUF->dipaddr[0] == uip_hostaddr[0] &&
+ BUF->dipaddr[1] == uip_hostaddr[1]) {
+ /* The reply opcode is 2. */
+ BUF->opcode = htons(2);
+
+ for(c = 0; c < 6; ++c) {
+ BUF->dhwaddr.addr[c] = BUF->shwaddr.addr[c];
+ BUF->shwaddr.addr[c] =
+ BUF->ethhdr.src.addr[c] = ethaddr.addr[c];
+ BUF->ethhdr.dest.addr[c] = BUF->dhwaddr.addr[c];
+ }
+
+ BUF->dipaddr[0] = BUF->sipaddr[0];
+ BUF->dipaddr[1] = BUF->sipaddr[1];
+ BUF->sipaddr[0] = uip_hostaddr[0];
+ BUF->sipaddr[1] = uip_hostaddr[1];
+
+ BUF->ethhdr.type = htons(UIP_ETHTYPE_ARP);
+ uip_len = sizeof(struct arp_hdr);
+ }
+ break;
+ case htons(ARP_REPLY):
+ /* ARP reply. We insert or update the ARP table if it was meant
+ for us. */
+ if(BUF->dipaddr[0] == uip_hostaddr[0] &&
+ BUF->dipaddr[1] == uip_hostaddr[1]) {
+
+ uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
+ }
+ break;
+ }
+
+ return;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_out(void)
+{
+ /* Find the destination IP address in the ARP table and construct
+ the Ethernet header. If the destination IP addres isn't on the
+ local network, we use the default router's IP address instead.
+
+ If not ARP table entry is found, we overwrite the original IP
+ packet with an ARP request for the IP address. */
+
+ /* Check if the destination address is on the local network. */
+ /* if((IPBUF->destipaddr[0] & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)) !=
+ (uip_hostaddr[0]
+ & htons((UIP_NETMASK0 << 8) | UIP_NETMASK1)) ||
+ (IPBUF->destipaddr[1] & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3)) !=
+ (uip_hostaddr[1]
+ & htons((UIP_NETMASK2 << 8) | UIP_NETMASK3))) {*/
+ if((IPBUF->destipaddr[0] & uip_arp_netmask[0]) !=
+ (uip_hostaddr[0] & uip_arp_netmask[0]) ||
+ (IPBUF->destipaddr[1] & uip_arp_netmask[1]) !=
+ (uip_hostaddr[1] & uip_arp_netmask[1])) {
+ /* Destination address was not on the local network, so we need to
+ use the default router's IP address instead of the destination
+ address when determining the MAC address. */
+ /* ipaddr[0] = htons((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1);
+ ipaddr[1] = htons((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3);*/
+ ipaddr[0] = uip_arp_draddr[0];
+ ipaddr[1] = uip_arp_draddr[1];
+ } else {
+ /* Else, we use the destination IP address. */
+ ipaddr[0] = IPBUF->destipaddr[0];
+ ipaddr[1] = IPBUF->destipaddr[1];
+ }
+
+ for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+ if(ipaddr[0] == arp_table[i].ipaddr[0] &&
+ ipaddr[1] == arp_table[i].ipaddr[1])
+ break;
+ }
+
+ if(i == UIP_ARPTAB_SIZE) {
+ /* The destination address was not in our ARP table, so we
+ overwrite the IP packet with an ARP request. */
+
+ for(c = 0; c < 6; ++c) {
+ BUF->ethhdr.dest.addr[c] = 0xff; /* Broadcast ARP request. */
+ BUF->ethhdr.src.addr[c] =
+ BUF->shwaddr.addr[c] = ethaddr.addr[c];
+ BUF->dhwaddr.addr[c] = 0;
+ }
+
+ BUF->dipaddr[0] = ipaddr[0];
+ BUF->dipaddr[1] = ipaddr[1];
+ BUF->sipaddr[0] = uip_hostaddr[0];
+ BUF->sipaddr[1] = uip_hostaddr[1];
+ BUF->opcode = htons(ARP_REQUEST); /* ARP request. */
+ BUF->hwtype = htons(ARP_HWTYPE_ETH);
+ BUF->protocol = htons(UIP_ETHTYPE_IP);
+ BUF->hwlen = 6;
+ BUF->protolen = 4;
+ BUF->ethhdr.type = htons(UIP_ETHTYPE_ARP);
+
+ uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
+
+ uip_len = sizeof(struct arp_hdr);
+ return;
+ }
+
+ /* Build an ethernet header. */
+ for(c = 0; c < 6; ++c) {
+ IPBUF->ethhdr.dest.addr[c] = arp_table[i].ethaddr.addr[c];
+ IPBUF->ethhdr.src.addr[c] = ethaddr.addr[c];
+ }
+ IPBUF->ethhdr.type = htons(UIP_ETHTYPE_IP);
+
+ uip_len += sizeof(struct uip_eth_hdr);
+}
+/*-----------------------------------------------------------------------------------*/
+
+
+
+
diff --git a/contiki/uip/uip_arp.h b/contiki/uip/uip_arp.h
new file mode 100644
index 0000000..415877a
--- /dev/null
+++ b/contiki/uip/uip_arp.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2001-2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arp.h,v 1.1 2003/03/19 14:16:07 adamdunkels Exp $
+ *
+ */
+
+#ifndef __UIP_ARP_H__
+#define __UIP_ARP_H__
+
+#include "uip.h"
+
+struct uip_eth_addr {
+ u8_t addr[6];
+};
+
+struct uip_eth_hdr {
+ struct uip_eth_addr dest;
+ struct uip_eth_addr src;
+ u16_t type;
+};
+
+#define UIP_ETHTYPE_ARP 0x0806
+#define UIP_ETHTYPE_IP 0x0800
+#define UIP_ETHTYPE_IP6 0x86dd
+
+
+/* The uip_arp_init() function must be called before any of the other
+ ARP functions. */
+void uip_arp_init(void);
+
+/* The uip_arp_ipin() function should be called whenever an IP packet
+ arrives from the Ethernet. This function refreshes the ARP table or
+ inserts a new mapping if none exists. The function assumes that an
+ IP packet with an Ethernet header is present in the uip_buf buffer
+ and that the length of the packet is in the uip_len variable. */
+void uip_arp_ipin(void);
+
+/* The uip_arp_arpin() should be called when an ARP packet is received
+ by the Ethernet driver. This function also assumes that the
+ Ethernet frame is present in the uip_buf buffer. When the
+ uip_arp_arpin() function returns, the contents of the uip_buf
+ buffer should be sent out on the Ethernet if the uip_len variable
+ is > 0. */
+void uip_arp_arpin(void);
+
+/* The uip_arp_out() function should be called when an IP packet
+ should be sent out on the Ethernet. This function creates an
+ Ethernet header before the IP header in the uip_buf buffer. The
+ Ethernet header will have the correct Ethernet MAC destination
+ address filled in if an ARP table entry for the destination IP
+ address (or the IP address of the default router) is present. If no
+ such table entry is found, the IP packet is overwritten with an ARP
+ request and we rely on TCP to retransmit the packet that was
+ overwritten. In any case, the uip_len variable holds the length of
+ the Ethernet frame that should be transmitted. */
+void uip_arp_out(void);
+
+/* The uip_arp_timer() function should be called every ten seconds. It
+ is responsible for flushing old entries in the ARP table. */
+void uip_arp_timer(void);
+
+
+#define uip_setdraddr(addr) do { uip_arp_draddr[0] = addr[0]; \
+ uip_arp_draddr[1] = addr[1]; } while(0)
+#define uip_setnetmask(addr) do { uip_arp_netmask[0] = addr[0]; \
+ uip_arp_netmask[1] = addr[1]; } while(0)
+
+
+/* Internal variables that are set using the macros uip_setdraddr and
+ uip_setnetmask. */
+extern u16_t uip_arp_draddr[2], uip_arp_netmask[2];
+#endif /* __UIP_ARP_H__ */
diff --git a/contiki/uip/uip_main.c b/contiki/uip/uip_main.c
new file mode 100644
index 0000000..7d8bbc2
--- /dev/null
+++ b/contiki/uip/uip_main.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_main.c,v 1.1 2003/03/19 14:16:07 adamdunkels Exp $
+ *
+ */
+
+
+/* uip_main.c: initialization code and main event loop. */
+
+#define NULL (void *)0
+
+
+
+#include "uip.h"
+#include "uip_arp.h"
+
+#ifdef WITH_TFE
+#include "cs8900a.h"
+#endif /* WITH_TFE */
+
+#include <time.h>
+
+#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+
+static u8_t i, arptimer;
+static u16_t start, current;
+
+static void idle(void);
+static struct dispatcher_proc p =
+ {DISPATCHER_PROC("uIP TCP/IP stack", idle, NULL, NULL)};
+static ek_id_t id;
+
+
+/*-----------------------------------------------------------------------------------*/
+static void
+timer(void)
+{
+ for(i = 0; i < UIP_CONNS; ++i) {
+ uip_periodic(i);
+ if(uip_len > 0) {
+#ifdef WITH_TFE
+ uip_arp_out();
+ cs8900a_send();
+#endif /* WITH_TFE */
+#ifdef WITH_RS232
+ rs232dev_send();
+#endif /* WITH_RS232 */
+ }
+ }
+
+ for(i = 0; i < UIP_UDP_CONNS; i++) {
+ uip_udp_periodic(i);
+ /* If the above function invocation resulted in data that
+ should be sent out on the network, the global variable
+ uip_len is set to a value > 0. */
+ if(uip_len > 0) {
+#ifdef WITH_TFE
+ uip_arp_out();
+ cs8900a_send();
+#endif /* WITH_TFE */
+#ifdef WITH_RS232
+ rs232dev_send();
+#endif /* WITH_RS232 */
+ }
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_main_init(void)
+{
+ u16_t ipaddr[2];
+
+ id = dispatcher_start(&p);
+
+ arptimer = 0;
+ start = clock();
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+idle(void)
+{
+#ifdef WITH_TFE
+ /* Poll Ethernet device to see if there is a frame avaliable. */
+ uip_len = cs8900a_poll();
+ if(uip_len > 0) {
+ /* A frame was avaliable (and is now read into the uip_buf), so
+ we process it. */
+ if(BUF->type == htons(UIP_ETHTYPE_IP)) {
+ uip_arp_ipin();
+ uip_len -= sizeof(struct uip_eth_hdr);
+ uip_input();
+ /* If the above function invocation resulted in data that
+ should be sent out on the network, the global variable
+ uip_len is set to a value > 0. */
+ if(uip_len > 0) {
+ uip_arp_out();
+ cs8900a_send();
+ }
+ } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
+ uip_arp_arpin();
+ /* If the above function invocation resulted in data that
+ should be sent out on the network, the global variable
+ uip_len is set to a value > 0. */
+ if(uip_len > 0) {
+ cs8900a_send();
+ }
+ }
+ }
+#endif /* WITH_TFE */
+
+#ifdef WITH_RS232
+ uip_len = rs232dev_poll();
+ if(uip_len > 0) {
+ uip_process(UIP_DATA);
+ if(uip_len > 0) {
+ rs232dev_send();
+ }
+ }
+#endif /* WITH_RS232 */
+
+ /* Check the clock so see if we should call the periodic uIP
+ processing. */
+ current = clock();
+
+ if((current - start) >= CLK_TCK/2) {
+ timer();
+ start = current;
+ }
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+uip_main_ipaddrconv(char *addrstr, unsigned char *ipaddr)
+{
+ unsigned char tmp;
+ char c;
+ unsigned char i, j;
+
+ tmp = 0;
+
+ for(i = 0; i < 4; ++i) {
+ j = 0;
+ do {
+ c = *addrstr;
+ ++j;
+ if(j > 4) {
+ return 0;
+ }
+ if(c == '.' || c == 0) {
+ *ipaddr = tmp;
+ ++ipaddr;
+ tmp = 0;
+ } else if(c >= '0' || c <= '9') {
+ tmp = (tmp * 10) + (c - '0');
+ } else {
+ return 0;
+ }
+ ++addrstr;
+ } while(c != '.' && c != 0);
+ }
+ return 1;
+}
+
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/uip/uip_main.h b/contiki/uip/uip_main.h
new file mode 100644
index 0000000..96fdcba
--- /dev/null
+++ b/contiki/uip/uip_main.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the Contiki desktop environment for the C64.
+ *
+ * $Id: uip_main.h,v 1.1 2003/03/19 14:16:07 adamdunkels Exp $
+ *
+ */
+#ifndef __UIP_MAIN_H__
+#define __UIP_MAIN_H__
+
+void uip_main_init(void);
+unsigned char uip_main_ipaddrconv(char *addrstr, unsigned char *addr);
+
+#endif /* __UIP_MAIN_H__ */
diff --git a/contiki/uip/uipopt.h b/contiki/uip/uipopt.h
new file mode 100644
index 0000000..ef4de36
--- /dev/null
+++ b/contiki/uip/uipopt.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Dunkels.
+ * 4. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uipopt.h,v 1.1 2003/03/19 14:16:07 adamdunkels Exp $
+ *
+ */
+
+#ifndef __UIPOPT_H__
+#define __UIPOPT_H__
+
+/* This file is used for tweaking various configuration options for
+ uIP. You should make a copy of this file into one of your project's
+ directories instead of editing this example "uipopt.h" file that
+ comes with the uIP distribution. */
+
+/*-----------------------------------------------------------------------------------*/
+/* First, two typedefs that may have to be tweaked for your particular
+ compiler. The uX_t types are unsigned integer types, where the X is
+ the number of bits in the integer type. Most compilers use
+ "unsigned char" and "unsigned short" for those two,
+ respectively. */
+typedef unsigned char u8_t;
+typedef unsigned short u16_t;
+typedef unsigned long u32_t;
+typedef unsigned long uip_stats_t;
+
+#include <string.h>
+#define bcopy(s,d,l) memcpy(d,s,l)
+
+/*-----------------------------------------------------------------------------------*/
+/* The configuration options for a specific node. This includes IP
+ * address, netmask and default router as well as the Ethernet
+ * address. The netmask, default router and Ethernet address are
+ * appliciable only if uIP should be run over Ethernet.
+ *
+ * All of these should be changed to suit your project.
+*/
+#define UIP_URGDATA 0
+#define UIP_PINGADDRCONF 0
+
+#define UIP_UDP 1
+#define UIP_UDP_CHECKSUMS 0
+#define UIP_UDP_CONNS 1
+#define UIP_UDP_APPCALL udp_appcall
+void udp_appcall(void);
+
+#define UIP_FIXEDADDR 0
+/* UIP_IPADDR: The IP address of this uIP node. */
+/*#define UIP_IPADDR0 192
+#define UIP_IPADDR1 168
+#define UIP_IPADDR2 0
+#define UIP_IPADDR3 2*/
+
+/* UIP_NETMASK: The netmask. */
+#define UIP_NETMASK0 255
+#define UIP_NETMASK1 255
+#define UIP_NETMASK2 255
+#define UIP_NETMASK3 0
+
+/* UIP_DRIPADDR: IP address of the default router. */
+#define UIP_DRIPADDR0 192
+#define UIP_DRIPADDR1 168
+#define UIP_DRIPADDR2 1
+#define UIP_DRIPADDR3 1
+
+/* UIP_ETHADDR: The Ethernet address. */
+#define UIP_ETHADDR0 0x00
+#define UIP_ETHADDR1 0x00
+#define UIP_ETHADDR2 0x00
+#define UIP_ETHADDR3 0x64
+#define UIP_ETHADDR4 0x64
+#define UIP_ETHADDR5 0x64
+
+
+/*-----------------------------------------------------------------------------------*/
+/* The following options are used to configure application specific
+ * setting such as how many TCP ports that should be avaliable and if
+ * the uIP should be configured to support active opens.
+ *
+ * These should probably be tweaked to suite your project.
+ */
+
+/* Include the header file for the application program that should be
+ used. If you don't use the example web server, you should change
+ this. */
+#include "dispatcher.h"
+
+/* UIP_ACTIVE_OPEN: Determines if support for opening connections from
+ uIP should be compiled in. If this isn't needed for your
+ application, don't turn it on. (A web server doesn't need this, for
+ instance.) */
+#define UIP_ACTIVE_OPEN 1
+
+/* UIP_CONNS: The maximum number of simultaneously active
+ connections. */
+#define UIP_CONNS 6
+
+/* UIP_LISTENPORTS: The maximum number of simultaneously listening TCP
+ ports. For a web server, 1 is enough here. */
+#define UIP_LISTENPORTS 6
+
+/* UIP_BUFSIZE: The size of the buffer that holds incoming and
+ outgoing packets. */
+#ifdef WITH_ETHERNET
+#define UIP_BUFSIZE 360
+#else /* WITH_ETHERNET */
+#define UIP_BUFSIZE 360
+#endif /* WITH_ETHERNET */
+
+/* UIP_STATISTICS: Determines if statistics support should be compiled
+ in. The statistics is useful for debugging and to show the user. */
+#define UIP_STATISTICS 0
+
+/* UIP_LOGGING: Determines if logging of certain events should be
+ compiled in. Useful mostly for debugging. The function uip_log(char
+ *msg) must be implemented to suit your architecture if logging is
+ turned on. */
+#define UIP_LOGGING 0
+
+/* UIP_LLH_LEN: The link level header length; this is the offset into
+ the uip_buf where the IP header can be found. For Ethernet, this
+ should be set to 14. For SLIP, this should be set to 0. */
+#ifdef WITH_ETHERNET
+#define UIP_LLH_LEN 14
+#else /* WITH_ETHERNET */
+#define UIP_LLH_LEN 0
+#endif /* WITH_ETHERNET */
+
+/*-----------------------------------------------------------------------------------*/
+/* The following configuration options can be tweaked for your
+ * project, but you are probably safe to use the default values. The
+ * options are listed in order of tweakability.
+ */
+
+/* UIP_ARPTAB_SIZE: The size of the ARP table - use a larger value if
+ this uIP node will have many connections from the local network. */
+#define UIP_ARPTAB_SIZE 8
+
+/* The maxium age of ARP table entries measured in 10ths of
+ seconds. An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD
+ default). */
+#define UIP_ARP_MAXAGE 120
+
+/* UIP_RTO: The retransmission timeout counted in timer pulses (i.e.,
+ the speed of the periodic timer, usually one second). */
+#define UIP_RTO 3
+
+/* UIP_MAXRTX: The maximum number of times a segment should be
+ retransmitted before the connection should be aborted. */
+#define UIP_MAXSYNRTX 8
+#define UIP_MAXRTX 8
+
+/* UIP_TCP_MSS: The TCP maximum segment size. This should be set to
+ at most UIP_BUFSIZE - UIP_LLH_LEN - 40. */
+#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - 42)
+
+/* UIP_TTL: The IP TTL (time to live) of IP packets sent by uIP. */
+#define UIP_TTL 255
+
+/* UIP_TIME_WAIT_TIMEOUT: How long a connection should stay in the
+ TIME_WAIT state. Has no real implication, so it should be left
+ untouched. */
+#define UIP_TIME_WAIT_TIMEOUT 120
+/*-----------------------------------------------------------------------------------*/
+/* This is where you configure if your CPU architecture is big or
+ * little endian. Most CPUs today are little endian. The most notable
+ * exception are the Motorolas which are big endian. Tweak the
+ * definition of the BYTE_ORDER macro to configure uIP for your
+ * project.
+ */
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 3412
+#endif /* LITTLE_ENDIAN */
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 1234
+#endif /* BIGE_ENDIAN */
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif /* BYTE_ORDER */
+
+#endif /* __UIPOPT_H__ */