Merge remote-tracking branch 'contiki-atari/master'
diff --git a/contiki-apple2/Makefile b/contiki-apple2/Makefile
new file mode 100644
index 0000000..18d56b4
--- /dev/null
+++ b/contiki-apple2/Makefile
@@ -0,0 +1,67 @@
+# 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: Makefile,v 1.6 2005/04/18 21:49:36 oliverschmidt Exp $
+#
+
+CONTIKI=../contiki
+CONTIKICC65=../contiki-cc65
+
+usage:
+	@echo "Make sure the Contiki sources is in the directory $(CONTIKI)"
+	@echo 'To compile Contiki, use "'$(MAKE)' target" where target'
+	@echo 'is one of the following:'
+	@echo all
+	@echo apple2
+	@echo apple2enh
+	@echo programs
+	@echo programsenh
+	@echo '(Also check the Makefile for more targets to try...)'
+
+all: clean apple2enh programsenh
+
+apple2:
+	$(MAKE) CONTIKI=$(CONTIKI) CONTIKICC65=$(CONTIKICC65) -f Makefile.apple2 SYS=apple2
+
+apple2enh:
+	$(MAKE) CONTIKI=$(CONTIKI) CONTIKICC65=$(CONTIKICC65) -f Makefile.apple2 SYS=apple2enh
+
+programs:
+	$(MAKE) CONTIKI=$(CONTIKI) CONTIKICC65=$(CONTIKICC65) -f Makefile.programs SYS=apple2
+
+programsenh:
+	$(MAKE) CONTIKI=$(CONTIKI) CONTIKICC65=$(CONTIKICC65) -f Makefile.programs SYS=apple2enh
+
+CCDEPFLAGS=
+
+include $(CONTIKICC65)/Makefile.cc65
+
diff --git a/contiki-apple2/Makefile.apple2 b/contiki-apple2/Makefile.apple2
new file mode 100644
index 0000000..293f4d2
--- /dev/null
+++ b/contiki-apple2/Makefile.apple2
@@ -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 desktop environment
+#
+# $Id: Makefile.apple2,v 1.20 2006/05/30 20:51:01 oliverschmidt Exp $
+#
+
+all: contiki
+
+include $(CONTIKI)/Makefile.common
+include $(CONTIKICC65)/Makefile.cc65
+
+AFLAGS:=-t $(SYS) -I lib -I $(CC65_INC)/../asminc
+
+CFLAGS:=$(CFLAGSCC65) --code-name CONTIKI \
+        -DWITH_ASCII -DWITH_UIP -DWITH_LOADER_ARCH -DWITH_ETHERNET
+
+ifeq ($(SYS),apple2)
+
+CTK=ctk.o ctk-conio.o
+
+else # apple2
+
+CTK=ctk.o ctk-mousetext.o ctk-mouse.o
+
+uip.s uip_arch.s uiplib.s tcpip.s: %.s: %.c
+	$(CC) $(CFLAGS) $(OPT) -DUIP_CODE -o $(notdir $@) $<
+
+endif # apple2
+
+contiki:crt0.o main.o ek.o ek-service.o timer.o program-handler.o arg.o \
+	loader-arch.o clock-arch.o bank.o kfs.o import.o $(CTK) $(UIP) \
+	www-dsc.o \
+	email-dsc.o \
+	ftp-dsc.o \
+	directory-dsc.o
+	$(LD) -C $(SYS).cfg -Ln contiki-labels -m contiki.map $^ $(SYS).lib
diff --git a/contiki-apple2/Makefile.programs b/contiki-apple2/Makefile.programs
new file mode 100644
index 0000000..b3df70e
--- /dev/null
+++ b/contiki-apple2/Makefile.programs
@@ -0,0 +1,94 @@
+# Copyright (c) 2003, 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. 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: Makefile.programs,v 1.20 2006/05/30 20:51:01 oliverschmidt Exp $
+#
+
+all: loader-arch-module.o loader-arch-module-dsc.o contiki-labels.o \
+     about.prg about.dsc \
+     calc.prg calc.dsc \
+     config.prg \
+     configedit.prg configedit.dsc \
+     dhcp.prg dhcp.dsc \
+     directory.prg directory.dsc \
+     email.prg email.dsc \
+     ftp.prg ftp.dsc \
+     irc.prg irc.dsc \
+     memstat.prg memstat.dsc \
+     processes.prg processes.dsc \
+     shell.prg shell.dsc \
+     telnet.prg telnet.dsc \
+     welcome.prg \
+     wget.prg wget.dsc \
+     www.prg www.dsc \
+     lancegs.drv lancegs.dsc \
+     uther.drv uther.dsc \
+     plasma.sav plasma.dsc \
+     ssfire.sav ssfire.dsc
+
+ifeq ($(SYS),apple2enh)
+
+all: webserver.prg webserver.dsc \
+     bounce.sav bounce.dsc
+
+endif # apple2enh
+
+include $(CONTIKI)/Makefile.common
+include $(CONTIKICC65)/Makefile.cc65
+
+AFLAGS:=-t $(SYS)
+
+CFLAGS:=$(CFLAGSCC65) \
+        -DWITH_ASCII -DWITH_UIP -DWITH_LOADER_ARCH -DWITH_ETHERNET
+
+configedit.prg: configedit.o ctk-textentry-checkbox.o
+
+dhcp.prg: $(DHCP) lc-asm.o
+
+directory.prg: $(DIRECTORY) cfs.o
+
+email.prg: $(EMAIL) lc-asm.o
+
+ftp.prg: $(FTP) cfs.o
+
+irc.prg: $(IRC) lc-asm.o
+
+shell.prg: $(SHELL_) cfs.o
+
+telnet.prg: $(TELNET)
+
+webserver.prg: $(WEBSERVER) lc-asm.o
+
+wget.prg: $(WGET)
+
+www.prg: $(WWW)
+
+lancegs.drv: lancegs-drv.o lan91c96.o uip_arp.o
+
+uther.drv: uther-drv.o cs8900a.o uther-drv-asm.o uip_arp.o
diff --git a/contiki-apple2/apple2.cfg b/contiki-apple2/apple2.cfg
new file mode 100644
index 0000000..2e8c07d
--- /dev/null
+++ b/contiki-apple2/apple2.cfg
@@ -0,0 +1,36 @@
+MEMORY {
+    ZP:     start = $0080, size = $001A, file = "", define = yes;
+    BUFFER: start = $0800, size = $0400, file = "";
+    HEADER: start = $0000, size = $0004, file = "contiki";
+    RAM:    start = $0C00, size = $8A00, file = "contiki";
+    PIC:    start = $0000, size = $FFFF, file = "contiki";
+    TMP:    start = $0000, size = $FFFF, file = "contiki";
+    LC:     start = $D400, size = $0C00, file = "contiki";
+}
+SEGMENTS {
+    ZEROPAGE: load = ZP,             type = zp;
+    UIPBUF:   load = BUFFER,         type = bss;
+    EXEHDR:   load = HEADER,         type = ro;
+    STARTUP:  load = RAM,            type = ro,  define = yes;
+    CONTIKI:  load = RAM,            type = ro;
+    RODATA:   load = RAM,            type = ro;
+    DATA:     load = RAM,            type = rw;
+    BSS:      load = RAM,            type = bss, define = yes;
+    BOOT:     load = PIC,            type = ro,  define = yes;
+    INIT:     load = TMP, run = RAM, type = ro,  define = yes;
+    CODE:     load = LC,             type = ro,  define = yes;
+}
+FEATURES {
+    CONDES: segment = INIT,
+	    type  = constructor,
+	    label = __CONSTRUCTOR_TABLE__,
+	    count = __CONSTRUCTOR_COUNT__;
+    CONDES: segment = RODATA,
+	    type  = destructor,
+	    label = __DESTRUCTOR_TABLE__,
+	    count = __DESTRUCTOR_COUNT__;
+}
+SYMBOLS {
+    __STACKSIZE__ = $0100;
+    __UIP_SIZE__  = $0000;
+}
diff --git a/contiki-apple2/apple2enh.cfg b/contiki-apple2/apple2enh.cfg
new file mode 100644
index 0000000..68fdc20
--- /dev/null
+++ b/contiki-apple2/apple2enh.cfg
@@ -0,0 +1,41 @@
+MEMORY {
+    ZP:     start = $0080, size = $001A, file = "", define = yes;
+    BUFFER: start = $0800, size = $0400, file = "";
+    HEADER: start = $0000, size = $0004, file = "contiki";
+    RAM:    start = $0C00, size = $8A00, file = "contiki";
+    PIC:    start = $0000, size = $FFFF, file = "contiki";
+    TMP:    start = $0000, size = $FFFF, file = "contiki";
+    LC:     start = $D000, size = $1000, file = "contiki";
+    AUX:    start = $2000, size = $2000, file = "contiki";
+}
+SEGMENTS {
+    ZEROPAGE: load = ZP,             type = zp;
+    UIPBUF:   load = BUFFER,         type = bss;
+    EXEHDR:   load = HEADER,         type = ro;
+    STARTUP:  load = RAM,            type = ro,  define = yes;
+    CONTIKI:  load = RAM,            type = ro;
+    RODATA:   load = RAM,            type = ro;
+    DATA:     load = RAM,            type = rw;
+    BSS:      load = RAM,            type = bss, define = yes;
+    BOOT:     load = PIC,            type = ro,  define = yes;
+    INIT:     load = TMP, run = RAM, type = ro,  define = yes;
+    CODE:     load = LC,             type = ro,  define = yes;
+    UIP:      load = AUX,            type = ro,  define = yes;
+}
+FEATURES {
+    CONDES: segment = INIT,
+	    type  = constructor,
+	    label = __CONSTRUCTOR_TABLE__,
+	    count = __CONSTRUCTOR_COUNT__;
+    CONDES: segment = RODATA,
+	    type  = destructor,
+	    label = __DESTRUCTOR_TABLE__,
+	    count = __DESTRUCTOR_COUNT__;
+    CONDES: segment = RODATA,
+	    type  = interruptor,
+	    label = __INTERRUPTOR_TABLE__,
+	    count = __INTERRUPTOR_COUNT__;
+}
+SYMBOLS {
+    __STACKSIZE__ = $0100;
+}
diff --git a/contiki-apple2/apps/bounce-dsc.c b/contiki-apple2/apps/bounce-dsc.c
new file mode 100644
index 0000000..abc2251
--- /dev/null
+++ b/contiki-apple2/apps/bounce-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: bounce-dsc.c,v 1.1 2006/05/30 20:50:26 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon bounce_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(ssfire_dsc,
+    "Screensaver with a bouncing box",
+    "bounce.sav",
+    bounce_init,
+    &bounce_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char bounceicon_bitmap[3*3*8] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char bounceicon_textmap[9] = {
+  '-', '|', '-',
+  '|', '|', '|',
+  '|', '-', '|'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon bounce_icon =
+  {CTK_ICON("Bounce", bounceicon_bitmap, bounceicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/bounce.c b/contiki-apple2/apps/bounce.c
new file mode 100644
index 0000000..b56d1d1
--- /dev/null
+++ b/contiki-apple2/apps/bounce.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2002-2004, 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. 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: bounce.c,v 1.1 2006/05/30 20:50:26 oliverschmidt Exp $
+ *
+ */
+
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ctk-mouse.h"
+#include "ek.h"
+#include "loader.h"
+
+EK_EVENTHANDLER(bounce_eventhandler, ev, data);
+EK_POLLHANDLER(bounce_pollhandler);
+EK_PROCESS(p, "Bounce screensaver", EK_PRIO_LOWEST,
+	   bounce_eventhandler, bounce_pollhandler, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static char pos[4] = {3, 17, 7, 13};
+static char vec[4] = {-1, 1, -1, 1};
+static char max[4];
+static char rev[2];
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(ssfire_init, arg)
+{
+  arg_free(arg);
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(bounce_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+  
+  if(ev == EK_EVENT_INIT) {
+    ctk_mode_set(CTK_MODE_SCREENSAVER);
+    ctk_mouse_hide();
+    max[0] = max[1] = ctk_draw_width();
+    max[2] = max[3] = ctk_draw_height();
+  } else if(ev == ctk_signal_screensaver_stop ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    ctk_draw_init();
+    ctk_desktop_redraw(NULL);
+    ek_exit();
+    id = EK_ID_NONE;
+    LOADER_UNLOAD();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_POLLHANDLER(bounce_pollhandler)
+{
+  static unsigned char i;
+
+  if(ctk_mode_get() == CTK_MODE_SCREENSAVER) {
+    for(i = 0; i < 4; ++i) {
+      pos[i] += vec[i];
+      if(pos[i] <= 0 || pos[i] >= max[i]) {
+        vec[i] = -vec[i];
+      }
+    }
+    if(pos[0] == pos[1] || pos[2] == pos[3]) {
+      return;
+    }
+    for(i = 0; i < 2; ++i) {
+      rev[i] = pos[i * 2] > pos[i * 2 + 1];
+    }
+    _textframexy(pos[0 + rev[0]],
+		 pos[2 + rev[1]],
+		 pos[1 - rev[0]] - pos[0 + rev[0]],
+		 pos[3 - rev[1]] - pos[2 + rev[1]], _TEXTFRAME_TALL);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/config.c b/contiki-apple2/apps/config.c
new file mode 100644
index 0000000..409da35
--- /dev/null
+++ b/contiki-apple2/apps/config.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2004, 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: config.c,v 1.13 2006/06/28 23:10:44 oliverschmidt Exp $
+ *
+ */
+
+
+#include <string.h>
+#include <unistd.h>
+
+#include "uiplib.h"
+#include "resolv.h"
+#include "uip_arp.h"
+
+#include "program-handler.h"
+#include "kfs.h"
+
+#include "config.h"
+
+
+static config_t config = {0,
+#ifdef __APPLE2__
+			  "SSFire.sav", 5,
+#else /* __APPLE2__ */
+			  "Bounce.sav", 5,
+#endif /* __APPLE2__ */
+			  "Uther.drv", 0,
+			  "",
+			  {0xA8C0, 0x8000}, {0xFFFF, 0x00FF},
+			  {0xA8C0, 0x0100}, {0xA8C0, 0x0100},
+			  0xA2};
+
+/*-----------------------------------------------------------------------------------*/
+static void
+config_load(void)
+{
+  int fd;
+
+  fd = kfs_open("contiki.cfg");
+  if(fd == -1) {
+    return;
+  }
+  kfs_read(fd, &config, sizeof(config));
+  kfs_close(fd);
+}
+/*-----------------------------------------------------------------------------------*/
+static void 
+config_apply(void)
+{
+#ifdef __APPLE2ENH__
+
+  ctk_draw_setbackground(config.bkgnd);
+
+#endif /* __APPLE2ENH__ */
+
+  program_handler_setscreensaver(config.screensaver);
+
+  CTK_SCREENSAVER_SET_TIMEOUT(config.timeout * 60);
+
+  config_setlanslot(config.slot);
+
+  if(*config.driver) {
+    program_handler_load(config.driver, NULL);
+  }
+
+  if(*config.prefix == '/') {
+    config_setprefixok(chdir(config.prefix) == 0);
+  }
+
+#ifdef WITH_UIP
+
+  uip_sethostaddr(config.ipaddr);
+
+#ifdef WITH_ETHERNET
+
+  uip_setnetmask(config.netmask);
+  uip_setdraddr(config.gateway);
+  uip_ethaddr.addr[5] = config.maclsb;
+
+#endif /* WITH_ETHERNET */
+
+  resolv_conf(config.dnsserver);
+
+#endif /* WITH_UIP */
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(config_init, arg)
+{
+  arg_free(arg);
+  config_load();
+  config_apply();
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/config.h b/contiki-apple2/apps/config.h
new file mode 100644
index 0000000..ea7e1b3
--- /dev/null
+++ b/contiki-apple2/apps/config.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2004, 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: config.h,v 1.8 2006/06/28 23:10:44 oliverschmidt Exp $
+ *
+ */
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+typedef struct {
+  unsigned char bkgnd;
+  char screensaver[16];
+  unsigned char timeout;
+  char driver[16];
+  unsigned char slot;
+  char prefix[65];
+  u16_t ipaddr[2];
+  u16_t netmask[2];
+  u16_t gateway[2];
+  u16_t dnsserver[2];
+  unsigned char maclsb;
+} config_t;
+
+extern unsigned char lanslot;
+extern unsigned char prefixok;
+
+#define config_getlanslot()	lanslot
+#define config_setlanslot(slot)	lanslot = (slot)
+
+#define config_getprefixok()	prefixok
+#define config_setprefixok(ok)  prefixok = (ok)
+
+#endif /* __CONFIG_H__ */
diff --git a/contiki-apple2/apps/configedit-dsc.c b/contiki-apple2/apps/configedit-dsc.c
new file mode 100644
index 0000000..cfe7564
--- /dev/null
+++ b/contiki-apple2/apps/configedit-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: configedit-dsc.c,v 1.3 2005/05/06 22:33:51 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon configedit_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(configedit_dsc,
+    "Edit Contiki configuration",
+    "configedit.prg",
+    configedit_init,
+    &configedit_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char tcpipconficon_textmap[9] = {
+  '-', '-', '-',
+  'C', 'F', 'G',
+  'E', 'D', 'T'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon configedit_icon =
+  {CTK_ICON("Configuration", tcpipconficon_bitmap, tcpipconficon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/configedit-dsc.h b/contiki-apple2/apps/configedit-dsc.h
new file mode 100644
index 0000000..0b33f4a
--- /dev/null
+++ b/contiki-apple2/apps/configedit-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: configedit-dsc.h,v 1.1 2004/12/26 14:13:34 oliverschmidt Exp $
+ *
+ */
+#ifndef __CONFIGEDIT_DSC_H__
+#define __CONFIGEDIT_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(configedit_dsc);
+
+#endif /* __CONFIGEDIT_DSC_H__ */
diff --git a/contiki-apple2/apps/configedit.c b/contiki-apple2/apps/configedit.c
new file mode 100644
index 0000000..e3aa78b
--- /dev/null
+++ b/contiki-apple2/apps/configedit.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 2004, 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: configedit.c,v 1.12 2006/06/28 23:10:45 oliverschmidt Exp $
+ *
+ */
+
+
+#include <string.h>
+
+#include "uiplib.h"
+#include "resolv.h"
+#include "uip_arp.h"
+#include "ctk.h"
+
+#include "program-handler.h"
+#include "packet-service.h"
+#include "kfs.h"
+#include "cfs.h"
+
+#include "ctk-textentry-checkbox.h"
+
+#include "config.h"
+
+
+static config_t config;
+static struct ctk_window window;
+
+#ifdef __APPLE2ENH__
+
+static struct ctk_label backgroundlabel =
+  {CTK_LABEL(0, 1, 11, 1, "Background")};
+static char bkgnd[2];
+static struct ctk_textentry backgroundtextentry =
+  {CTK_TEXTENTRY_INPUT(12, 1, 1, 1, bkgnd, 1, ctk_textentry_checkbox_input)};
+static struct ctk_label backgrounddescr =
+  {CTK_LABEL(16, 1, 12, 1, "('x' or ' ')")};
+
+#endif /* __APPLE2ENH__ */
+
+static struct ctk_label screensaverlabel =
+  {CTK_LABEL(0, 3, 11, 1, "Screensaver")};
+static char screensaver[16];
+static struct ctk_textentry screensavertextentry =
+  {CTK_TEXTENTRY(12, 3, 15, 1, screensaver, 15)};
+
+static struct ctk_label timeoutlabel =
+  {CTK_LABEL(0, 4, 11, 1, "Timeout")};
+static char timeout[2];
+static struct ctk_textentry timeouttextentry =
+  {CTK_TEXTENTRY(12, 4, 1, 1, timeout, 1)};
+static struct ctk_label timeoutdescr =
+  {CTK_LABEL(16, 4, 12, 1, "(in Minutes)")};
+
+static struct ctk_label driverlabel =
+  {CTK_LABEL(0, 6, 11, 1, "LAN driver")};
+static char driver[16];
+static struct ctk_textentry drivertextentry =
+  {CTK_TEXTENTRY(12, 6, 15, 1, driver, 15)};
+
+static struct ctk_label slotlabel =
+  {CTK_LABEL(0, 7, 11, 1, "LAN slot")};
+static char slot[2];
+static struct ctk_textentry slottextentry =
+  {CTK_TEXTENTRY(12, 7, 1, 1, slot, 1)};
+static struct ctk_label slotdescr =
+  {CTK_LABEL(16, 7, 12, 1, "('1' to '7')")};
+
+static struct ctk_label prefixlabel =
+  {CTK_LABEL(0, 9, 11, 1, "DOS Prefix")};
+static char prefix[65];
+static struct ctk_textentry prefixtextentry =
+  {CTK_TEXTENTRY(12, 9, 15, 1, prefix, 65)};
+
+static struct ctk_label ipaddrlabel =
+  {CTK_LABEL(0, 11, 10, 1, "IP address")};
+static char ipaddr[16];
+static struct ctk_textentry ipaddrtextentry =
+  {CTK_TEXTENTRY(12, 11, 15, 1, ipaddr, 15)};
+
+#ifdef WITH_ETHERNET
+
+static struct ctk_label netmasklabel =
+  {CTK_LABEL(0, 12, 11, 1, "Netmask")};
+static char netmask[16];
+static struct ctk_textentry netmasktextentry =
+  {CTK_TEXTENTRY(12, 12, 15, 1, netmask, 15)};
+
+static struct ctk_label gatewaylabel =
+  {CTK_LABEL(0, 13, 11, 1, "Gateway")};
+static char gateway[16];
+static struct ctk_textentry gatewaytextentry =
+  {CTK_TEXTENTRY(12, 13, 15, 1, gateway, 15)};
+
+static struct ctk_label dnsserverlabel =
+  {CTK_LABEL(0, 14, 11, 1, "DNS server")};
+static char dnsserver[16];
+static struct ctk_textentry dnsservertextentry =
+  {CTK_TEXTENTRY(12, 14, 15, 1, dnsserver, 15)};
+
+static struct ctk_label maclsblabel =
+  {CTK_LABEL(0, 16, 11, 1, "MAC address")};
+static char maclsb[4];
+static struct ctk_textentry maclsbtextentry =
+  {CTK_TEXTENTRY(12, 16, 3, 1, maclsb, 3)};
+static struct ctk_label maclsbdescr =
+  {CTK_LABEL(18, 16, 10, 1, "(LSB only)")};
+
+#else /* WITH_ETHERNET */
+
+static struct ctk_label dnsserverlabel =
+  {CTK_LABEL(0, 12, 11, 1, "DNS server")};
+static char dnsserver[16];
+static struct ctk_textentry dnsservertextentry =
+  {CTK_TEXTENTRY(12, 12, 15, 1, dnsserver, 15)};
+
+#endif /* WITH_ETHERNET */
+
+static struct ctk_button okbutton =
+  {CTK_BUTTON(0, 18, 12, "Save & close")};
+static struct ctk_button cancelbutton =
+  {CTK_BUTTON(22, 18, 6, "Cancel")};
+
+
+static struct ctk_window errordialog;
+
+static struct ctk_label errormsg =
+  {CTK_LABEL(0, 1, 19, 1, "Error saving config")};
+static struct ctk_button errorokbutton =
+  {CTK_BUTTON(7, 3, 2, "Ok")};
+
+
+EK_EVENTHANDLER(config_eventhandler, ev, data);
+EK_PROCESS(p, "Configuration", EK_PRIO_NORMAL,
+	   config_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+static ek_id_t driverid = EK_ID_NONE;
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(config_init, arg)
+{
+  arg_free(arg);
+    
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static char *
+makebyte(u8_t byte, char *str)
+{
+  if(byte >= 100) {
+    *str++ = (byte / 100 ) % 10 + '0';
+  }
+  if(byte >= 10) {
+    *str++ = (byte / 10) % 10 + '0';
+  }
+  *str++ = (byte % 10) + '0';
+
+  return str;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+makeaddr(u16_t *addr, char *str)
+{
+  str = makebyte(HTONS(addr[0]) >> 8, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[0]) & 0xff, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[1]) >> 8, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[1]) & 0xff, str);
+  *str++ = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static int
+makedriver(const char *name, char *str)
+{
+  char *pattern = PACKET_SERVICE_NAME ": ";
+
+  while(*pattern) {
+    if(*name++ != *pattern++) {
+      return 0;
+    }
+  }
+
+  while(*name) {
+    *str++ = *name++;
+  }
+  strcpy(str, ".drv");
+
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+makestrings(void)
+{
+  u16_t addr[2], *addrptr;
+  struct ek_proc *p;
+
+#ifdef __APPLE2ENH__
+
+  if(ctk_draw_getbackground()) {
+    *bkgnd = 'x';
+  }
+
+#endif /* __APPLE2ENH__ */
+
+  strncpy(screensaver, program_handler_getscreensaver(), sizeof(screensaver));
+
+  *timeout = (CTK_SCREENSAVER_TIMEOUT() / 60) % 10 + '0';
+
+  for(p = EK_PROCS(); p != NULL; p = p->next) {
+    if(makedriver(p->name, driver)) {
+      driverid = p->id;
+      break;
+    }
+  }
+
+  if(config_getlanslot() != 0) {
+    *slot = config_getlanslot() + '0';
+  }
+
+  if(config_getprefixok()) {
+    getcwd(prefix, sizeof(prefix));
+  }
+
+#ifdef WITH_UIP
+
+  uip_gethostaddr(addr);
+  makeaddr(addr, ipaddr);
+  
+#ifdef WITH_ETHERNET
+
+  uip_getnetmask(addr);
+  makeaddr(addr, netmask);
+  
+  uip_getdraddr(addr);
+  makeaddr(addr, gateway);
+
+  makebyte(uip_ethaddr.addr[5], maclsb);
+
+#endif /* WITH_ETHERNET */
+
+  addrptr = resolv_getserver();
+  if(addrptr != NULL) {
+    makeaddr(addrptr, dnsserver);
+  }
+  
+#endif /* WITH_UIP */
+}
+/*-----------------------------------------------------------------------------------*/
+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
+makeconfig(void)
+{
+  u16_t addr[2];
+  char *cptr;
+  u8_t tmp;
+
+#ifdef __APPLE2ENH__
+
+  config.bkgnd = (*bkgnd == 'x');
+
+#endif /* __APPLE2ENH__ */
+
+  nullterminate(screensaver);
+  strcpy(config.screensaver, screensaver);
+
+  if(*timeout >= '1' && *timeout <= '9') {
+    config.timeout = *timeout - '0';
+  }
+
+  nullterminate(driver);
+  strcpy(config.driver, driver);
+
+  if(*slot >= '1' && *slot <= '7') {
+    config.slot = *slot - '0';
+  } else {
+    config.slot = 0;
+  }
+
+  nullterminate(prefix);
+  strcpy(config.prefix, prefix);
+
+#ifdef WITH_UIP
+
+  nullterminate(ipaddr);
+  if(uiplib_ipaddrconv(ipaddr, (unsigned char *)addr)) {
+    config.ipaddr[0] = addr[0];
+    config.ipaddr[1] = addr[1];
+  }
+  
+#ifdef WITH_ETHERNET
+
+  nullterminate(netmask);
+  if(uiplib_ipaddrconv(netmask, (unsigned char *)addr)) {
+    config.netmask[0] = addr[0];
+    config.netmask[1] = addr[1];
+  }
+
+  nullterminate(gateway);
+  if(uiplib_ipaddrconv(gateway, (unsigned char *)addr)) {
+    config.gateway[0] = addr[0];
+    config.gateway[1] = addr[1];
+  }
+
+  tmp = 0;
+  for(cptr = maclsb; *cptr >= '0' && *cptr <= '9'; ++cptr) {
+    tmp = (tmp * 10) + (*cptr - '0');
+  }
+  if(tmp != 0) {
+    config.maclsb = tmp;
+  }
+
+#endif /* WITH_ETHERNET */
+  
+  nullterminate(dnsserver);
+  if(uiplib_ipaddrconv(dnsserver, (unsigned char *)addr)) {
+    config.dnsserver[0] = addr[0];
+    config.dnsserver[1] = addr[1];
+  }
+
+#endif /* WITH_UIP */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+config_apply(void)
+{
+#ifdef __APPLE2ENH__
+
+  ctk_draw_setbackground(config.bkgnd);
+
+#endif /* __APPLE2ENH__ */
+
+  program_handler_setscreensaver(config.screensaver);
+
+  CTK_SCREENSAVER_SET_TIMEOUT(config.timeout * 60);
+
+  if(driverid != EK_ID_NONE) {
+    ek_post(driverid, EK_EVENT_REQUEST_EXIT, NULL);
+  }
+
+  config_setlanslot(config.slot);
+
+  if(*config.driver) {
+    program_handler_load(config.driver, NULL);
+  }
+
+  if(*config.prefix == '/') {
+    config_setprefixok(chdir(config.prefix) == 0);
+  }
+
+#ifdef WITH_UIP
+
+  uip_sethostaddr(config.ipaddr);
+
+#ifdef WITH_ETHERNET
+
+  uip_setnetmask(config.netmask);
+  uip_setdraddr(config.gateway);
+  uip_ethaddr.addr[5] = config.maclsb;
+
+#endif /* WITH_ETHERNET */
+
+  resolv_conf(config.dnsserver);
+
+#endif /* WITH_UIP */
+}
+/*-----------------------------------------------------------------------------------*/
+static int
+config_save(void)
+{
+  int fd, written = 0;
+
+  fd = cfs_open(strcat(kfs_getdir(), "contiki.cfg"), CFS_WRITE);
+  if(fd != -1) {
+    written = cfs_write(fd, &config, sizeof(config));
+    cfs_close(fd);
+  }
+  return written == sizeof(config);
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(config_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+  
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&window, 30, 19, "Config editor");
+#ifdef __APPLE2ENH__
+    CTK_WIDGET_ADD(&window, &backgroundlabel);
+    CTK_WIDGET_ADD(&window, &backgroundtextentry);
+    CTK_WIDGET_ADD(&window, &backgrounddescr);
+#endif /* __APPLE2ENH__ */
+    CTK_WIDGET_ADD(&window, &screensaverlabel);
+    CTK_WIDGET_ADD(&window, &screensavertextentry);
+    CTK_WIDGET_ADD(&window, &timeoutlabel);
+    CTK_WIDGET_ADD(&window, &timeouttextentry);
+    CTK_WIDGET_ADD(&window, &timeoutdescr);
+    CTK_WIDGET_ADD(&window, &driverlabel);
+    CTK_WIDGET_ADD(&window, &drivertextentry);
+    CTK_WIDGET_ADD(&window, &slotlabel);
+    CTK_WIDGET_ADD(&window, &slottextentry);
+    CTK_WIDGET_ADD(&window, &slotdescr);
+    CTK_WIDGET_ADD(&window, &prefixlabel);
+    CTK_WIDGET_ADD(&window, &prefixtextentry);
+    CTK_WIDGET_ADD(&window, &ipaddrlabel);
+    CTK_WIDGET_ADD(&window, &ipaddrtextentry);
+#ifdef WITH_ETHERNET
+    CTK_WIDGET_ADD(&window, &netmasklabel);
+    CTK_WIDGET_ADD(&window, &netmasktextentry);
+    CTK_WIDGET_ADD(&window, &gatewaylabel);
+    CTK_WIDGET_ADD(&window, &gatewaytextentry);
+#endif /* WITH_ETHERNET */
+    CTK_WIDGET_ADD(&window, &dnsserverlabel);
+    CTK_WIDGET_ADD(&window, &dnsservertextentry);
+#ifdef WITH_ETHERNET
+    CTK_WIDGET_ADD(&window, &maclsblabel);
+    CTK_WIDGET_ADD(&window, &maclsbtextentry);
+    CTK_WIDGET_ADD(&window, &maclsbdescr);
+#endif /* WITH_ETHERNET */
+    CTK_WIDGET_ADD(&window, &okbutton);
+    CTK_WIDGET_ADD(&window, &cancelbutton);
+#ifdef __APPLE2ENH__
+    CTK_WIDGET_FOCUS(&window, &backgroundtextentry);
+#else /* __APPLE2ENH__ */
+    CTK_WIDGET_FOCUS(&window, &screensavertextentry);
+#endif /* __APPLE2ENH__ */
+
+    ctk_dialog_new(&errordialog, 19, 5);
+    CTK_WIDGET_ADD(&errordialog, &errormsg);
+    CTK_WIDGET_ADD(&errordialog, &errorokbutton);
+    CTK_WIDGET_FOCUS(&errordialog, &errorokbutton);
+
+    /* Fill the configuration strings with values from the current
+       configuration */
+    makestrings();
+    ctk_window_open(&window);
+  } else if(ev == ctk_signal_button_activate) {   
+    if(data == (ek_data_t)&okbutton) {
+
+      /* Fill the configuration with values from the current
+         configuration strings */
+      makeconfig();
+      config_apply();
+      if(config_save()) {
+	goto quit;
+      }
+      ctk_dialog_open(&errordialog);
+    } else if(data == (ek_data_t)&errorokbutton) {
+      ctk_dialog_close();
+      goto quit;
+    } else if(data == (ek_data_t)&cancelbutton) {
+      goto quit;
+    }
+
+  } else if(ev == ctk_signal_window_close ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    goto quit;
+  }
+  return;
+
+quit:
+  ctk_window_close(&window);
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/plasma-dsc.c b/contiki-apple2/apps/plasma-dsc.c
new file mode 100644
index 0000000..bd8940b
--- /dev/null
+++ b/contiki-apple2/apps/plasma-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: plasma-dsc.c,v 1.1 2005/05/12 21:12:43 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon plasma_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(plasma_dsc,
+    "Screensaver with a plasma",
+    "plasma.sav",
+    plasma_init,
+    &plasma_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char plasmaicon_bitmap[3*3*8] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char plasmaicon_textmap[9] = {
+  '.', ' ', '.',
+  ' ', 'O', ' ',
+  '.', ' ', '.'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon plasma_icon =
+  {CTK_ICON("Plasma", plasmaicon_bitmap, plasmaicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/plasma.c b/contiki-apple2/apps/plasma.c
new file mode 100644
index 0000000..1936363
--- /dev/null
+++ b/contiki-apple2/apps/plasma.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2002-2004, 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. 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: plasma.c,v 1.1 2005/05/12 21:12:43 oliverschmidt Exp $
+ *
+ */
+
+#include <stdlib.h>
+
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ctk-mouse.h"
+#include "ek.h"
+#include "loader.h"
+
+static unsigned char sinetab1[256] = {
+  128, 131, 134, 137, 140, 143, 146, 149, 
+  152, 156, 159, 162, 165, 168, 171, 174, 
+  176, 179, 182, 185, 188, 191, 193, 196, 
+  199, 201, 204, 206, 209, 211, 213, 216, 
+  218, 220, 222, 224, 226, 228, 230, 232, 
+  234, 236, 237, 239, 240, 242, 243, 245, 
+  246, 247, 248, 249, 250, 251, 252, 252, 
+  253, 254, 254, 255, 255, 255, 255, 255, 
+  255, 255, 255, 255, 255, 255, 254, 254, 
+  253, 252, 252, 251, 250, 249, 248, 247, 
+  246, 245, 243, 242, 240, 239, 237, 236, 
+  234, 232, 230, 228, 226, 224, 222, 220, 
+  218, 216, 213, 211, 209, 206, 204, 201, 
+  199, 196, 193, 191, 188, 185, 182, 179, 
+  176, 174, 171, 168, 165, 162, 159, 156, 
+  152, 149, 146, 143, 140, 137, 134, 131, 
+  128, 124, 121, 118, 115, 112, 109, 106, 
+  103,  99,  96,  93,  90,  87,  84,  81, 
+   79,  76,  73,  70,  67,  64,  62,  59, 
+   56,  54,  51,  49,  46,  44,  42,  39, 
+   37,  35,  33,  31,  29,  27,  25,  23, 
+   21,  19,  18,  16,  15,  13,  12,  10, 
+    9,   8,   7,   6,   5,   4,   3,   3, 
+    2,   1,   1,   0,   0,   0,   0,   0, 
+    0,   0,   0,   0,   0,   0,   1,   1, 
+    2,   3,   3,   4,   5,   6,   7,   8, 
+    9,  10,  12,  13,  15,  16,  18,  19, 
+   21,  23,  25,  27,  29,  31,  33,  35, 
+   37,  39,  42,  44,  46,  49,  51,  54, 
+   56,  59,  62,  64,  67,  70,  73,  76, 
+   78,  81,  84,  87,  90,  93,  96,  99, 
+  103, 106, 109, 112, 115, 118, 121, 124, 
+};
+
+static unsigned char sinetab2[256];
+static unsigned char sinetab3[256];
+
+static unsigned char colortab[256];
+
+static unsigned char colors[16] =
+  {
+    0x00, 0x22, 0x55, 0x33,
+    0xBB, 0xAA, 0xDD, 0xFF,
+    0xDD, 0xAA, 0xBB, 0x99,
+    0x11, 0x88, 0x00, 0x00
+  };
+
+#define XSIZE 25
+#define YSIZE 24
+
+#define XADD01 0xfe
+#define YADD01 0x05
+
+#define XADD1 0x04
+#define YADD1 0x02
+#define XADD2 0xfc
+#define YADD2 0xf9
+
+#define XADD 0x03
+#define YADD 0xfe
+
+#define MOVADD 0xfb
+
+static unsigned char xplasma[XSIZE], yplasma[YSIZE];
+static unsigned char xcnt, ycnt;
+static unsigned char xcnt01, xcnt02, xcnt1, xcnt2;
+static unsigned char ycnt01, ycnt02, ycnt1, ycnt2;
+
+static unsigned char xadd02 = 0x01;
+static unsigned char yadd02 = 0xfb;
+
+static unsigned char movcnt;
+
+/*static DISPATCHER_SIGHANDLER(sighandler, s, data);
+static void idle(void);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Plasma screensaver", idle,
+		   sighandler,
+		   NULL)};
+		   static ek_id_t id;*/
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_POLLHANDLER(pollhandler);
+EK_PROCESS(p, "Plasma screensaver", EK_PRIO_LOWEST,
+	   eventhandler, pollhandler, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*-----------------------------------------------------------------------------------*/
+static void
+quit(void)
+{
+  *(char *)0xC051 = 0;
+
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+scrninit(void)
+{
+  static int i;
+  
+  /* Make sine tables */
+  for(i = 0; i < 256; ++i) {
+    sinetab2[(unsigned char)i] = sinetab1[(unsigned char)i] / 2;
+    sinetab3[(unsigned char)i] = sinetab1[(unsigned char)i] / 4;    
+  }
+    
+  /* Make color table */
+  for(i = 0; i < 256; ++i) {
+    colortab[(unsigned char)i] = colors[(unsigned char)i / 16];
+  }
+    
+  *(char *)0xC056 = 0;
+  *(char *)0xC054 = 0;
+  *(char *)0xC052 = 0;
+  *(char *)0xC050 = 0;
+
+  for(ycnt = 0; ycnt < 24; ++ycnt) {
+    gotoy(ycnt);
+    for(xcnt = 0; xcnt < 40; ++xcnt) {
+      (*(unsigned char **)0x28)[xcnt] = 0x00;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_POLLHANDLER(pollhandler)
+{
+  static unsigned char i, x, y, xofs;
+  
+  if(ctk_mode_get() == CTK_MODE_SCREENSAVER) {
+
+    xcnt1 = xcnt01;
+    xcnt2 = xcnt02;
+    
+    for(i = 0; i < XSIZE; ++i) {
+      xplasma[i] = sinetab1[xcnt1] + sinetab2[xcnt2];
+      xcnt1 += XADD1;
+      xcnt2 += XADD2;
+    }
+
+    ycnt1 = ycnt01;
+    ycnt2 = ycnt02;
+    
+    for(i = 0; i < YSIZE; ++i) {
+      yplasma[i] = sinetab1[ycnt1] + sinetab3[ycnt2];
+      ycnt1 += YADD1;
+      ycnt2 += YADD2;
+    }
+
+    xcnt01 += XADD01;
+    xcnt02 += xadd02;
+    ycnt01 += YADD01;
+    ycnt02 += yadd02;
+
+    
+    yadd02 = sinetab3[ycnt] / 4;
+    xadd02 = sinetab3[xcnt] / 4;
+
+    ycnt += YADD;
+    xcnt += XADD;
+
+    movcnt += MOVADD;
+    xofs = sinetab1[movcnt]/16;
+
+    for(y = 0; y < YSIZE; ++y) {
+      gotoy(y);
+      for(x = 0; x < XSIZE; ++x) {
+	(*(unsigned char **)0x28)[x + xofs] = colortab[(xplasma[x] + yplasma[y]) & 0xff];
+      }
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/*static
+  DISPATCHER_SIGHANDLER(sighandler, s, data)*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    ctk_mode_set(CTK_MODE_SCREENSAVER);
+    ctk_mouse_hide();
+   
+    scrninit();
+
+  } else if(ev == ctk_signal_screensaver_stop ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    ctk_draw_init();
+    ctk_desktop_redraw(NULL);
+    /*    ctk_mode_set(CTK_MODE_NORMAL);*/
+    quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(plasma_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+ 
diff --git a/contiki-apple2/apps/ssfire-dsc.c b/contiki-apple2/apps/ssfire-dsc.c
new file mode 100644
index 0000000..0fe625d
--- /dev/null
+++ b/contiki-apple2/apps/ssfire-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: ssfire-dsc.c,v 1.1 2005/05/12 21:12:43 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon ssfire_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(ssfire_dsc,
+    "Screensaver with two fires",
+    "ssfire.sav",
+    ssfire_init,
+    &ssfire_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char ssfireicon_bitmap[3*3*8] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char ssfireicon_textmap[9] = {
+  '.', ' ', '.',
+  'o', ' ', 'o',
+  'O', ' ', 'O'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon ssfire_icon =
+  {CTK_ICON("Fire", ssfireicon_bitmap, ssfireicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/ssfire.c b/contiki-apple2/apps/ssfire.c
new file mode 100644
index 0000000..574a652
--- /dev/null
+++ b/contiki-apple2/apps/ssfire.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2002-2004, 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. 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: ssfire.c,v 1.1 2005/05/12 21:12:43 oliverschmidt Exp $
+ *
+ */
+
+#include <stdlib.h>
+
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ctk-mouse.h"
+#include "ek.h"
+#include "loader.h"
+
+
+/*static DISPATCHER_SIGHANDLER(ssfire_sighandler, s, data);
+static void ssfire_idle(void);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Fire screensaver", ssfire_idle,
+		   ssfire_sighandler,
+		   NULL)};
+		   static ek_id_t id;*/
+
+EK_EVENTHANDLER(ssfire_eventhandler, ev, data);
+EK_POLLHANDLER(ssfire_pollhandler);
+EK_PROCESS(p, "Fire screensaver", EK_PRIO_LOWEST,
+	   ssfire_eventhandler, ssfire_pollhandler, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static unsigned char flames[8*17];
+
+static const unsigned char flamecolors[16] =
+  {0x00, 0x00, 0x00, 0x11, 0x99, 0xDD, 0xFF, 0xFF,
+   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+   
+static unsigned char *flameptr;
+static unsigned char x, y;
+
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(ssfire_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+fire_quit(void)
+{
+  *(char *)0xC051 = 0;
+
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+fire_init(void)
+{
+  *(char *)0xC056 = 0;
+  *(char *)0xC054 = 0;
+  *(char *)0xC052 = 0;
+  *(char *)0xC050 = 0;
+
+  for(y = 0; y < 24; ++y) {
+    gotoy(y);
+    for(x = 0; x < 40; ++x) {
+      (*(unsigned char **)0x28)[x] = 0x00;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(ssfire_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+  
+  if(ev == EK_EVENT_INIT) {
+    ctk_mode_set(CTK_MODE_SCREENSAVER);
+    ctk_mouse_hide();
+    fire_init();
+  } else if(ev == ctk_signal_screensaver_stop ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    fire_quit();
+    ctk_draw_init();
+    ctk_desktop_redraw(NULL);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+static void
+fire_burn(void)
+{
+  /* Calculate new flames. */
+  asm("ldy #$00");
+loop1:
+  asm("lda %v+7,y", flames);
+  asm("clc");
+  asm("adc %v+8,y", flames);
+  asm("adc %v+9,y", flames);
+  asm("adc %v+16,y", flames);
+  asm("lsr");
+  asm("lsr");
+  asm("sta %v,y", flames);
+  asm("iny");
+  asm("cpy #(8*15)");
+  asm("bne %g", loop1);
+
+  /* Fill last line with pseudo-random data. */
+  asm("ldy #$05");
+loop2:
+  asm("jsr %v", rand);
+  asm("and #$0F");
+  asm("sta %v+8*15+1,y", flames);
+  asm("dey");
+  asm("bpl %g", loop2);
+}
+#pragma optimize(pop)
+/*-----------------------------------------------------------------------------------*/
+EK_POLLHANDLER(ssfire_pollhandler)
+{
+  if(ctk_mode_get() == CTK_MODE_SCREENSAVER) {
+
+    fire_burn();
+  
+    /* Display flames on screen. */  
+    flameptr = flames;
+    for(y = 9; y < 24; ++y) {
+      gotoy(y);
+      for(x = 0; x < 8; ++x) {
+	(*(unsigned char **)0x28)[x   ] =
+	(*(unsigned char **)0x28)[x+32] = flamecolors[flameptr[x]];
+      }
+      flameptr += 8;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+
diff --git a/contiki-apple2/apps/welcome.c b/contiki-apple2/apps/welcome.c
new file mode 100644
index 0000000..10acca3
--- /dev/null
+++ b/contiki-apple2/apps/welcome.c
@@ -0,0 +1,123 @@
+/*
+ * 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. 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: welcome.c,v 1.3 2006/05/30 21:02:32 oliverschmidt Exp $
+ *
+ */
+
+#include "contiki.h"
+#include <string.h>
+
+
+static struct ctk_window welcomedialog;
+static struct ctk_label welcomelabel1 =
+  {CTK_LABEL(2, 1, 30, 1, "Welcome to " CONTIKI_VERSION_STRING " !")};
+static struct ctk_label welcomelabel2 =
+  {CTK_LABEL(2, 4, 30, 1, "Esc        - open menus")};
+static struct ctk_label welcomelabel3 =
+  {CTK_LABEL(2, 6, 30, 1, "Ctrl-W     - cycle windows")};
+static struct ctk_label welcomelabel4 =
+  {CTK_LABEL(2, 8, 30, 1, "Ctrl-A     - select up")};
+static struct ctk_label welcomelabel5 =
+  {CTK_LABEL(2, 10, 30, 1, "Tab        - select down")};
+static struct ctk_label welcomelabel6 =
+  {CTK_LABEL(2, 12, 30, 1, "Return     - activate selected")};
+#ifdef __APPLE2__
+static struct ctk_label welcomelabel7 =
+  {CTK_LABEL(2, 14, 30, 1, "Ctrl-D     - delete character")};
+static struct ctk_label welcomelabel8 =
+  {CTK_LABEL(2, 16, 30, 1, "Ctrl-Reset - quit Contiki")};
+static struct ctk_label welcomeclose =
+  {CTK_BUTTON(13, 19, 5, "Close")};
+#else /* __APPLE2__ */
+static struct ctk_label welcomelabel7 =
+  {CTK_LABEL(2, 14, 30, 1, "Ctrl-Reset - quit Contiki")};
+static struct ctk_label welcomeclose =
+  {CTK_BUTTON(13, 17, 5, "Close")};
+#endif /* __APPLE2__ */
+
+
+EK_EVENTHANDLER(welcome_eventhandler, ev, data);
+
+EK_PROCESS(p, "Welcome", EK_PRIO_NORMAL, welcome_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(welcome_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+welcome_quit(void)
+{
+  ctk_dialog_close();
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+/*static DISPATCHER_SIGHANDLER(welcome_sighandler, s, data)*/
+EK_EVENTHANDLER(welcome_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+#ifdef __APPLE2__
+    ctk_dialog_new(&welcomedialog, 34, 21);
+#else /* __APPLE2__ */
+    ctk_dialog_new(&welcomedialog, 34, 19);
+#endif /* __APPLE2__ */
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel1);
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel2);
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel3);
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel4);
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel5);
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel6);
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel7);
+#ifdef __APPLE2__
+    CTK_WIDGET_ADD(&welcomedialog, &welcomelabel8);
+#endif /* __APPLE2__ */
+    CTK_WIDGET_ADD(&welcomedialog, &welcomeclose);
+    CTK_WIDGET_FOCUS(&welcomedialog, &welcomeclose);
+    
+    ctk_dialog_open(&welcomedialog);
+    
+  } else if(ev == EK_EVENT_REQUEST_EXIT ||
+	    ev == ctk_signal_button_activate) {
+    welcome_quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/wget-dsc.c b/contiki-apple2/apps/wget-dsc.c
new file mode 100644
index 0000000..59f58cb
--- /dev/null
+++ b/contiki-apple2/apps/wget-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: wget-dsc.c,v 1.2 2005/04/19 22:01:22 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon wget_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(wget_dsc,
+    "Downloads files or disks from the web",
+    "wget.prg",
+    wget_init,
+    &wget_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char wgeticon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char wgeticon_textmap[9] = {
+  'w', 'e', 'b',
+  'p', 'r', 'g',
+  'd', 's', 'k'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon wget_icon =
+  {CTK_ICON("Web downloader", wgeticon_bitmap, wgeticon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/apps/wget-dsc.h b/contiki-apple2/apps/wget-dsc.h
new file mode 100644
index 0000000..1d217b8
--- /dev/null
+++ b/contiki-apple2/apps/wget-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: wget-dsc.h,v 1.1 2005/03/29 23:12:31 oliverschmidt Exp $
+ *
+ */
+#ifndef __WGET_DSC_H__
+#define __WGET_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(wget_dsc);
+
+#endif /* __WGET_DSC_H__ */
diff --git a/contiki-apple2/apps/wget.c b/contiki-apple2/apps/wget.c
new file mode 100644
index 0000000..ec74e8a
--- /dev/null
+++ b/contiki-apple2/apps/wget.c
@@ -0,0 +1,461 @@
+/*
+ * 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. 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: wget.c,v 1.3 2005/04/24 13:37:06 oliverschmidt Exp $
+ *
+ */
+
+
+#include "ctk.h"
+#include "ek.h"
+#include "webclient.h"
+#include "resolv.h"
+#include "uiplib.h"
+#include "loader.h"
+#include "cfs.h"
+
+#include "contiki.h"
+
+#include "program-handler.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <dio.h>
+
+
+static struct ctk_window window;
+
+static struct ctk_label urllabel =
+  {CTK_LABEL(0, 1, 4, 1, "URL:")};
+static char url[80];
+static char urledit[80];
+struct ctk_textentry urltextentry =
+  {CTK_TEXTENTRY(5, 1, 30, 1, urledit, 78)};
+
+static struct ctk_label savefilenamelabel =
+  {CTK_LABEL(0, 3, 14, 1, "Save filename:")};
+static char savefilename[40];
+static struct ctk_textentry savefilenametextentry =
+  {CTK_TEXTENTRY(15, 3, 20, 1, savefilename, 38)};
+
+static struct ctk_button filebutton =
+  {CTK_BUTTON(0, 5, 16, "Download to file")};
+
+static struct ctk_button dskbutton =
+  {CTK_BUTTON(19, 5, 16, "Download to disk")};
+
+static struct ctk_label statustext =
+  {CTK_LABEL(0, 7, 37, 1, "")};
+static char statusmsg[40];
+
+static struct ctk_window dskdialog;
+static struct ctk_label overwritelabel =
+  {CTK_LABEL(0, 1, 36, 1, "This will overwrite the entire disk!")};
+static struct ctk_label makesurelabel1 =
+  {CTK_LABEL(7, 3, 22, 1, "Make sure you have the")};
+static struct ctk_label makesurelabel2 =
+  {CTK_LABEL(4, 4, 28, 1, "right disk in slot 6 drive 1")};
+static struct ctk_button overwritebutton =
+  {CTK_BUTTON(2, 6, 14, "Overwrite disk")};
+static struct ctk_button cancelbutton =
+  {CTK_BUTTON(26, 6, 6, "Cancel")};
+
+EK_EVENTHANDLER(wget_eventhandler, ev, data);
+EK_PROCESS(p, "Web downloader", EK_PRIO_NORMAL,
+	   wget_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/* State */
+
+#define DLOAD_NONE 0
+#define DLOAD_FILE 1
+#define DLOAD_DSK  2
+static u8_t dload_state;
+static unsigned long dload_bytes;
+
+static int savefile;
+static void* savedsk;
+
+static char buffer[16][256];
+static u16_t bufferptr;
+static u8_t relsector;
+static u16_t absblock;
+
+/*-----------------------------------------------------------------------------------*/
+/* wget_init();
+ *
+ * Initializes and starts the web browser. Called either at startup or
+ * to open the browser window.
+ */
+LOADER_INIT_FUNC(wget_init, arg)
+{
+  if(arg != NULL) {
+    strncpy(url, arg, sizeof(url));
+    strncpy(urledit, arg, sizeof(urledit));
+  } else {
+#ifdef WGET_CONF_URL
+    strncpy(url, WGET_CONF_URL, sizeof(url));
+    strncpy(urledit, WGET_CONF_URL, sizeof(urledit));
+#endif /* WGET_CONF_URL  */
+  }
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+show_statustext(char *text)
+{
+  ctk_label_set_text(&statustext, text);
+  CTK_WIDGET_REDRAW(&statustext);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+dload_close(char *text)
+{
+  show_statustext(text);
+  if(dload_state == DLOAD_FILE) {
+    cfs_close(savefile);
+  } else if(dload_state == DLOAD_DSK) {
+    dio_close(savedsk);
+  }
+  dload_state = DLOAD_NONE;
+  webclient_close();
+}
+/*-----------------------------------------------------------------------------------*/
+/* 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
+start_get(void)
+{
+  u16_t addr[2];
+  unsigned char i;
+  static char host[32];
+  char *file;
+  register char *urlptr;
+
+  /* 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 = "/";
+  }
+      
+  /* First check if the host is an IP address. */
+  if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) {    
+    
+    /* 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...");
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(wget_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    /* Create the main window. */
+    ctk_window_new(&window, 37, 8, "Web downloader");
+
+    CTK_WIDGET_ADD(&window, &urllabel);
+    CTK_WIDGET_ADD(&window, &urltextentry);
+    CTK_WIDGET_ADD(&window, &savefilenamelabel);
+    CTK_WIDGET_ADD(&window, &savefilenametextentry);
+    CTK_WIDGET_ADD(&window, &filebutton);
+    CTK_WIDGET_ADD(&window, &dskbutton);
+    CTK_WIDGET_ADD(&window, &statustext);
+
+    CTK_WIDGET_FOCUS(&window, &urltextentry);
+
+    dload_state = DLOAD_NONE;
+      
+    memset(savefilename, 0, sizeof(savefilename));
+    memset(url, 0, sizeof(url));
+
+    ctk_dialog_new(&dskdialog, 36, 8);
+    CTK_WIDGET_ADD(&dskdialog, &overwritelabel);
+    CTK_WIDGET_ADD(&dskdialog, &makesurelabel1);
+    CTK_WIDGET_ADD(&dskdialog, &makesurelabel2);
+    CTK_WIDGET_ADD(&dskdialog, &overwritebutton);
+    CTK_WIDGET_ADD(&dskdialog, &cancelbutton);
+    
+    CTK_WIDGET_FOCUS(&dskdialog, &cancelbutton);
+
+    ctk_window_open(&window);
+  } else if(ev == tcpip_event) {
+    webclient_appcall(data);
+  } else if(ev == ctk_signal_button_activate) {
+    if(data == (void *)&filebutton) {
+      dload_close("");
+      savefile = cfs_open(savefilename, CFS_WRITE);
+      if(savefile == -1) {
+	sprintf(statusmsg, "Open error with '%s'", savefilename);
+	show_statustext(statusmsg);
+      } else {
+	strncpy(url, urledit, sizeof(url));
+	start_get();
+	dload_bytes = 0;
+	dload_state = DLOAD_FILE;
+      }
+    } else if(data == (void *)&dskbutton) {
+      ctk_dialog_open(&dskdialog);
+    } else if(data == (void *)&cancelbutton) {
+      ctk_dialog_close();
+    } else if(data == (void *)&overwritebutton) {
+      ctk_dialog_close();
+      dload_close("");
+      savedsk = dio_open(/*slot*/6 * 2 + /*drive*/1 - 1);
+      if(savedsk == NULL) {
+	sprintf(statusmsg, "Access error with slot 6 drive 1");
+	show_statustext(statusmsg);
+      } else {
+	strncpy(url, urledit, sizeof(url));
+	start_get();
+	dload_bytes = 0;
+	dload_state = DLOAD_DSK;
+	bufferptr = 0;
+	relsector = 0;
+	absblock = 0;
+      }
+    }
+  } else if(ev == ctk_signal_hyperlink_activate) {
+    if(dload_state == DLOAD_NONE) {
+      /*      open_link(w->widget.hyperlink.url);*/
+      strncpy(urledit,
+	      ((struct ctk_widget *)data)->widget.hyperlink.url, sizeof(urledit));
+      CTK_WIDGET_REDRAW(&urltextentry);
+      CTK_WIDGET_FOCUS(&window, &urltextentry);
+    }
+  } else if(ev == resolv_event_found) {
+    /* Either found a hostname, or not. */
+    if((char *)data != NULL &&
+       resolv_lookup((char *)data) != NULL) {
+      start_get();
+    } else {
+      show_statustext("Host not found.");
+    }
+  } else if(ev == ctk_signal_window_close) {
+    dload_close("");
+    ek_exit();
+    id = EK_ID_NONE;
+    LOADER_UNLOAD();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/* 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)
+{
+  dload_close("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)
+{
+  if(dload_state == DLOAD_NONE) {
+    return;
+  }
+  show_statustext("Done.");
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_closed():
+ *
+ * Callback function. Called from the webclient when the HTTP
+ * connection is connected.
+ */
+void
+webclient_connected(void)
+{    
+  show_statustext("Request sent...");
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char
+write_buffer(void)
+{
+  u8_t sector;
+
+  for(sector = 0; sector < 16; sector += 2) {
+    if(dio_write(savedsk, absblock++, buffer[sector]) != 0) {
+      return 0;
+    }
+  }
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char
+handle_dsk_data(char *data, u16_t len)
+{
+  static u8_t skew[16] = {0x0, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8,
+			  0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xF};
+  u16_t bufferlen;
+
+  while(len > 0) {
+    bufferlen = sizeof(buffer[0]) - bufferptr;
+    if(len < bufferlen) {
+      bufferlen = len;
+    }
+    
+    memcpy(&buffer[skew[relsector]][bufferptr], data, bufferlen);
+
+    data += bufferlen;
+    bufferptr += bufferlen;
+    len -= bufferlen;
+    
+    if(bufferptr == sizeof(buffer[0])) {
+      bufferptr = 0;
+      if(++relsector == 16) {
+	relsector = 0;
+	if(write_buffer() == 0) {
+	  return 0;
+	}
+      }
+    }
+  }
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_datahandler():   
+ *
+ * Callback function. Called from the webclient module when HTTP data
+ * has arrived.
+ */
+void
+webclient_datahandler(char *data, u16_t len)
+{
+  int ret;
+  
+  if(len > 0) {
+    dload_bytes += len;    
+    sprintf(statusmsg, "Downloading (%lu bytes)", dload_bytes);
+    show_statustext(statusmsg);
+    if(dload_state == DLOAD_DSK) {
+      if(handle_dsk_data(data, len) == 0) {
+	dload_close("Write error with slot 6 drive 1");
+      }
+    } else if(dload_state == DLOAD_FILE) {      
+      ret = cfs_write(savefile, data, len);       
+      if(ret != len) {
+	sprintf(statusmsg, "Wrote only %d bytes", ret);
+	dload_close(statusmsg);
+      }
+    }
+  }
+  
+  if(data == NULL) {
+    sprintf(statusmsg, "Finished downloading %lu bytes", dload_bytes);
+    dload_close(statusmsg);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/conf/cc-conf.h b/contiki-apple2/conf/cc-conf.h
new file mode 100644
index 0000000..a358a3f
--- /dev/null
+++ b/contiki-apple2/conf/cc-conf.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003, 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 OS
+ *
+ * $Id: cc-conf.h,v 1.1 2003/04/10 07:25:27 adamdunkels Exp $
+ *
+ */
+#ifndef __CC_CONF_H__
+#define __CC_CONF_H__
+
+#define CC_CONF_REGISTER_ARGS          1
+#define CC_CONF_FUNCTION_POINTER_ARGS  1
+
+#define CC_CONF_FASTCALL               fastcall
+
+#endif /* __CC_CONF_H__ */
+
diff --git a/contiki-apple2/conf/clock-conf.h b/contiki-apple2/conf/clock-conf.h
new file mode 100644
index 0000000..8417343
--- /dev/null
+++ b/contiki-apple2/conf/clock-conf.h
@@ -0,0 +1,8 @@
+#ifndef __CLOCK_CONF_H__
+#define __CLOCK_CONF_H__
+
+typedef unsigned short clock_time_t;
+
+#define CLOCK_CONF_SECOND 2
+
+#endif /* __CLOCK_CONF_H__ */
diff --git a/contiki-apple2/conf/ctk-conf.h b/contiki-apple2/conf/ctk-conf.h
new file mode 100644
index 0000000..8c304f0
--- /dev/null
+++ b/contiki-apple2/conf/ctk-conf.h
@@ -0,0 +1,104 @@
+/*
+ * 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.13 2006/05/07 23:08:42 oliverschmidt 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_ESC
+
+/* Defines which key that is to be used for switching the frontmost
+   window.  */
+#define CTK_CONF_WINDOWSWITCH_KEY     0x17	/* Ctrl-W */
+
+/* Defines which key that is to be used for switching to the prevoius
+   widget.  */
+#define CTK_CONF_WIDGETUP_KEY         0x01	/* Ctrl-A */
+
+/* Defines which key that is to be used for switching to the next
+   widget.  */
+#define CTK_CONF_WIDGETDOWN_KEY       '\t'	/* Tab or Ctrl-I */
+
+/* Toggles mouse support (must have support functions in the
+architecture specific files to work). */
+#ifdef __APPLE2__
+#define CTK_CONF_MOUSE_SUPPORT        0 /* 1342 bytes */
+#else /* __APPLE2__ */
+#define CTK_CONF_MOUSE_SUPPORT        1 /* 1342 bytes */
+#endif /* __APPLE2__ */
+
+/* Toggles support for icons. */
+#define CTK_CONF_ICONS                1 /* 107 bytes */
+
+/* Toggles support for icon bitmaps. */
+#define CTK_CONF_ICON_BITMAPS         0
+
+/* Toggles support for icon textmaps. */
+#define CTK_CONF_ICON_TEXTMAPS        1
+
+/* Toggles support for movable windows. */
+#ifdef __APPLE2__
+#define CTK_CONF_WINDOWMOVE           0 /* 333 bytes */
+#else /* __APPLE2__ */
+#define CTK_CONF_WINDOWMOVE           1 /* 333 bytes */
+#endif /* __APPLE2__ */
+
+/* Toggles support for closable windows. */
+#define CTK_CONF_WINDOWCLOSE          1 /* 14 bytes */
+
+/* Toggles support for menus. */
+#define CTK_CONF_MENUS                1 /* 1384 bytes */
+
+/* Defines the default width of a menu. */
+#define CTK_CONF_MENUWIDTH            16
+/* The maximum number of menu items in each menu. */
+#ifdef __APPLE2__
+#define CTK_CONF_MAXMENUITEMS         5
+#else /* __APPLE2__ */
+#define CTK_CONF_MAXMENUITEMS         6
+#endif /* __APPLE2__ */
+
+/* Toggles support for screen savers. */
+#define CTK_CONF_SCREENSAVER          1
+
+#endif /* __CTK_CONF_H__ */
diff --git a/contiki-apple2/conf/ctk-conio-conf.h b/contiki-apple2/conf/ctk-conio-conf.h
new file mode 100644
index 0000000..3a646d5
--- /dev/null
+++ b/contiki-apple2/conf/ctk-conio-conf.h
@@ -0,0 +1,175 @@
+/*
+ * 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-conio-conf.h,v 1.1 2005/02/17 22:36:19 oliverschmidt Exp $
+ *
+ */
+
+#ifndef __CTK_CONIO_CONF_H__
+#define __CTK_CONIO_CONF_H__
+
+#if 0
+/* Light gray inverted color scheme: */
+#define BORDERCOLOR         COLOR_WHITE
+#define SCREENCOLOR         COLOR_WHITE
+#define BACKGROUNDCOLOR     COLOR_WHITE
+
+#define WINDOWCOLOR_FOCUS   COLOR_BLACK
+#define WINDOWCOLOR         COLOR_GRAY2
+
+#define DIALOGCOLOR         COLOR_RED
+
+#define WIDGETCOLOR_HLINK   COLOR_BLUE
+#define WIDGETCOLOR_FWIN    COLOR_BLACK
+#define WIDGETCOLOR         COLOR_GRAY1
+#define WIDGETCOLOR_DIALOG  COLOR_RED
+#define WIDGETCOLOR_FOCUS   COLOR_BLACK
+
+#define MENUCOLOR           COLOR_BLACK
+#define OPENMENUCOLOR       COLOR_BLACK
+#define ACTIVEMENUITEMCOLOR COLOR_BLACK
+#endif /* 0 */
+
+#if 0
+/* Blue color scheme: */
+#define BORDERCOLOR         COLOR_LIGHTBLUE
+#define SCREENCOLOR         COLOR_BLUE
+#define BACKGROUNDCOLOR     COLOR_BLUE
+
+#define WINDOWCOLOR_FOCUS   COLOR_LIGHTBLUE
+#define WINDOWCOLOR         COLOR_GRAY1
+
+#define DIALOGCOLOR         COLOR_WHITE
+
+#define WIDGETCOLOR_HLINK   COLOR_CYAN
+#define WIDGETCOLOR_FWIN    COLOR_LIGHTBLUE
+#define WIDGETCOLOR         COLOR_GRAY1
+#define WIDGETCOLOR_DIALOG  COLOR_WHITE
+#define WIDGETCOLOR_FOCUS   COLOR_YELLOW
+
+#define MENUCOLOR           COLOR_WHITE
+#define OPENMENUCOLOR       COLOR_LIGHTBLUE
+#define ACTIVEMENUITEMCOLOR COLOR_YELLOW
+#endif /* 0 */
+
+#if 1
+/* Black and white monocrome color scheme: */
+#define BORDERCOLOR         COLOR_BLACK
+#define SCREENCOLOR         COLOR_BLACK
+#define BACKGROUNDCOLOR     COLOR_BLACK
+
+#define WINDOWCOLOR_FOCUS   COLOR_WHITE
+#define WINDOWCOLOR         COLOR_WHITE
+
+#define DIALOGCOLOR         COLOR_WHITE
+
+#define WIDGETCOLOR_HLINK   COLOR_WHITE
+#define WIDGETCOLOR_FWIN    COLOR_WHITE
+#define WIDGETCOLOR         COLOR_WHITE
+#define WIDGETCOLOR_DIALOG  COLOR_WHITE
+#define WIDGETCOLOR_FOCUS   COLOR_WHITE
+
+#define MENUCOLOR           COLOR_WHITE
+#define OPENMENUCOLOR       COLOR_WHITE
+#define ACTIVEMENUITEMCOLOR COLOR_WHITE
+#endif /* 0 */
+
+#if 0
+/* Blue monocrome color scheme: */
+#define BORDERCOLOR         COLOR_BLUE
+#define SCREENCOLOR         COLOR_BLUE
+#define BACKGROUNDCOLOR     COLOR_BLUE
+
+#define WINDOWCOLOR_FOCUS   COLOR_LIGHTBLUE
+#define WINDOWCOLOR         COLOR_LIGHTBLUE
+
+#define DIALOGCOLOR         COLOR_LIGHTBLUE
+
+#define WIDGETCOLOR_HLINK   COLOR_LIGHTBLUE
+#define WIDGETCOLOR_FWIN    COLOR_LIGHTBLUE
+#define WIDGETCOLOR         COLOR_LIGHTBLUE
+#define WIDGETCOLOR_DIALOG  COLOR_LIGHTBLUE
+#define WIDGETCOLOR_FOCUS   COLOR_LIGHTBLUE
+
+#define MENUCOLOR           COLOR_LIGHTBLUE
+#define OPENMENUCOLOR       COLOR_LIGHTBLUE
+#define ACTIVEMENUITEMCOLOR COLOR_LIGHTBLUE
+#endif /* 0 */
+
+#if 0
+/* Gray color scheme: */
+#define BORDERCOLOR         COLOR_GRAY1
+#define SCREENCOLOR         COLOR_GRAY1
+#define BACKGROUNDCOLOR     COLOR_GRAY1
+
+#define WINDOWCOLOR_FOCUS   COLOR_GRAY3
+#define WINDOWCOLOR         COLOR_GRAY2
+
+#define DIALOGCOLOR         COLOR_WHITE
+
+#define WIDGETCOLOR_HLINK   COLOR_LIGHTBLUE
+#define WIDGETCOLOR_FWIN    COLOR_GRAY3
+#define WIDGETCOLOR         COLOR_GRAY2
+#define WIDGETCOLOR_DIALOG  COLOR_WHITE
+#define WIDGETCOLOR_FOCUS   COLOR_YELLOW
+
+#define MENUCOLOR           COLOR_GRAY3
+#define OPENMENUCOLOR       COLOR_WHITE
+#define ACTIVEMENUITEMCOLOR COLOR_YELLOW
+#endif /* 0 */
+
+#if 0
+/* Red color scheme: */
+#define BORDERCOLOR         COLOR_BLACK
+#define SCREENCOLOR         COLOR_BLACK
+#define BACKGROUNDCOLOR     COLOR_BLACK
+
+#define WINDOWCOLOR_FOCUS   COLOR_LIGHTRED
+#define WINDOWCOLOR         COLOR_RED
+
+#define DIALOGCOLOR         COLOR_WHITE
+
+#define WIDGETCOLOR_HLINK   COLOR_LIGHTBLUE
+#define WIDGETCOLOR_FWIN    COLOR_YELLOW
+#define WIDGETCOLOR         COLOR_LIGHTRED
+#define WIDGETCOLOR_DIALOG  COLOR_WHITE
+#define WIDGETCOLOR_FOCUS   COLOR_YELLOW
+
+#define MENUCOLOR           COLOR_LIGHTRED
+#define OPENMENUCOLOR       COLOR_WHITE
+#define ACTIVEMENUITEMCOLOR COLOR_YELLOW
+#endif /* 0 */
+
+
+#endif /* __CTK_CONIO_CONF_H__ */
diff --git a/contiki-apple2/conf/ctk-mouse-conf.h b/contiki-apple2/conf/ctk-mouse-conf.h
new file mode 100644
index 0000000..f9a3285
--- /dev/null
+++ b/contiki-apple2/conf/ctk-mouse-conf.h
@@ -0,0 +1,46 @@
+/*
+ * 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" GUI toolkit for cc65
+ *
+ * $Id: ctk-mouse-conf.h,v 1.1 2006/04/09 16:13:31 oliverschmidt Exp $
+ *
+ */
+
+#ifndef __CTK_MOUSE_CONF_H__
+#define __CTK_MOUSE_CONF_H__
+
+#define MOUSE_CONF_DRIVER  "a2e.stdmou.mou"
+#define MOUSE_CONF_XTOC(x) ((x) * 2 / 7)
+#define MOUSE_CONF_YTOC(y) ((y) / 8)
+
+#endif /* __CTK_MOUSE_CONF_H__ */
diff --git a/contiki-apple2/conf/ek-conf.h b/contiki-apple2/conf/ek-conf.h
new file mode 100644
index 0000000..354d7d9
--- /dev/null
+++ b/contiki-apple2/conf/ek-conf.h
@@ -0,0 +1,54 @@
+/*
+ * 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.5 2005/04/16 14:10:31 oliverschmidt Exp $
+ *
+ */
+
+
+#ifndef __EK_CONF_H__
+#define __EK_CONF_H__
+
+#include <time.h>
+
+typedef void *ek_data_t;
+
+typedef unsigned char ek_event_t;
+typedef unsigned char ek_num_events_t;
+typedef unsigned char ek_id_t;
+
+#define EK_CONF_MAXPROCS 32
+#define EK_CONF_NUMEVENTS 16
+
+#endif /* __EK_CONF_H__ */
diff --git a/contiki-apple2/conf/email-conf.h b/contiki-apple2/conf/email-conf.h
new file mode 100644
index 0000000..e2d2d2c
--- /dev/null
+++ b/contiki-apple2/conf/email-conf.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: email-conf.h,v 1.2 2005/05/04 23:49:37 oliverschmidt Exp $
+ */
+#ifndef __EMAIL_CONF_H__
+#define __EMAIL_CONF_H__
+
+#ifdef __APPLE2__
+#define EMAIL_CONF_WIDTH 37
+#else /* __APPLE2__ */
+#define EMAIL_CONF_WIDTH 48
+#endif /* __APPLE2__ */
+#define EMAIL_CONF_HEIGHT 16
+
+#endif /* __EMAIL_CONF_H__ */
diff --git a/contiki-apple2/conf/irc-conf.h b/contiki-apple2/conf/irc-conf.h
new file mode 100644
index 0000000..d050bbc
--- /dev/null
+++ b/contiki-apple2/conf/irc-conf.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: irc-conf.h,v 1.1 2004/12/26 14:13:34 oliverschmidt Exp $
+ */
+#ifndef __IRC_CONF_H__
+#define __IRC_CONF_H__
+
+#ifdef __APPLE2__
+#define IRC_CONF_WIDTH 38
+#else /* __APPLE2__ */
+#define IRC_CONF_WIDTH 78
+#endif /* __APPLE2__ */
+#define IRC_CONF_HEIGHT 20
+
+#define IRC_CONF_SYSTEM_STRING "apple2"
+
+#endif /* __IRC_CONF_H__ */
diff --git a/contiki-apple2/conf/log-conf.h b/contiki-apple2/conf/log-conf.h
new file mode 100644
index 0000000..9ff4810
--- /dev/null
+++ b/contiki-apple2/conf/log-conf.h
@@ -0,0 +1,6 @@
+#ifndef __LOG_CONF_H__
+#define __LOG_CONF_H__
+
+#define LOG_CONF_ENABLED 0
+
+#endif /* __LOG_CONF__H__ */
diff --git a/contiki-apple2/conf/program-handler-conf.h b/contiki-apple2/conf/program-handler-conf.h
new file mode 100644
index 0000000..e2bc71d
--- /dev/null
+++ b/contiki-apple2/conf/program-handler-conf.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: program-handler-conf.h,v 1.6 2006/05/14 23:34:13 oliverschmidt Exp $
+ */
+#ifndef __PROGRAM_HANDLER_CONF_H__
+#define __PROGRAM_HANDLER_CONF_H__
+
+#ifdef __APPLE2__
+#define PROGRAM_HANDLER_CONF_MAX_NUMDSCS 5
+#define PROGRAM_HANDLER_CONF_QUIT_MENU   0
+#else /* __APPLE2__ */
+#define PROGRAM_HANDLER_CONF_MAX_NUMDSCS 6
+#define PROGRAM_HANDLER_CONF_QUIT_MENU   1
+#endif /* __APPLE2__ */
+
+#endif /* __PROGRAM_HANDLER_CONF_H__ */
diff --git a/contiki-apple2/conf/shell-gui-conf.h b/contiki-apple2/conf/shell-gui-conf.h
new file mode 100644
index 0000000..eaf02e6
--- /dev/null
+++ b/contiki-apple2/conf/shell-gui-conf.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: shell-gui-conf.h,v 1.1 2005/05/04 22:12:05 oliverschmidt Exp $
+ */
+#ifndef __SHELL_GUI_CONF_H__
+#define __SHELL_GUI_CONF_H__
+
+#define SHELL_GUI_CONF_XSIZE 38
+#define SHELL_GUI_CONF_YSIZE 12
+
+#endif /* __SHELL_GUI_CONF_H__ */
diff --git a/contiki-apple2/conf/uip-conf.h b/contiki-apple2/conf/uip-conf.h
new file mode 100644
index 0000000..b4e379b
--- /dev/null
+++ b/contiki-apple2/conf/uip-conf.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2003, 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 Destop OS
+ *
+ * $Id: uip-conf.h,v 1.4 2006/05/17 15:55:29 oliverschmidt Exp $
+ *
+ */
+#ifndef __UIP_CONF_H__
+
+#define UIP_CONF_MAX_CONNECTIONS 10
+#define UIP_CONF_MAX_LISTENPORTS 10
+#define UIP_CONF_BUFFER_SIZE     1024 - 2
+#define UIP_CONF_RECEIVE_WINDOW  UIP_TCP_MSS
+#define UIP_CONF_BYTE_ORDER      LITTLE_ENDIAN
+#define UIP_CONF_EXTERNAL_BUFFER
+
+#ifdef UIP_CODE
+
+#pragma codeseg("UIP");
+
+#include "ek-conf.h"
+
+#undef  EK_PROCESS_INIT
+#define EK_PROCESS_INIT(name, arg)					\
+  void _tcpip_init(void *arg)
+
+#undef  EK_EVENTHANDLER
+#define EK_EVENTHANDLER(name, ev, data)					\
+  void _tcpip_eventhandler(ek_event_t ev, ek_data_t data)
+
+#undef  EK_POLLHANDLER
+#define EK_POLLHANDLER(name)						\
+  void _tcpip_pollhandler(void)
+
+#undef  EK_PROCESS
+#define EK_PROCESS(name, strname, prio, eventh, pollh, stateptr)	\
+  void tcpip_eventhandler(ek_event_t ev, ek_data_t data);		\
+  void tcpip_pollhandler(void);						\
+  static struct ek_proc name = {NULL, EK_ID_NONE, strname, prio, tcpip_eventhandler, tcpip_pollhandler, stateptr}
+
+#define htons                _htons
+#define uiplib_ipaddrconv    _uiplib_ipaddrconv
+#define tcp_markconn         _tcp_markconn
+#define tcp_listen           _tcp_listen
+#define tcp_unlisten         _tcp_unlisten
+#define tcp_connect          _tcp_connect
+#define udp_new              _udp_new
+#define tcpip_set_forwarding _tcpip_set_forwarding
+#define tcpip_input          _tcpip_input
+#define tcpip_output         _tcpip_output
+#define tcpip_poll_tcp       _tcpip_poll_tcp
+#define tcpip_poll_udp       _tcpip_poll_udp
+
+#define ek_post_synch        _ek_post_synch
+void _ek_post_synch(ek_id_t id, ek_event_t ev, ek_data_t data);
+
+#endif /* UIP_CODE */
+
+#endif /* __UIP_CONF_H__ */
diff --git a/contiki-apple2/conf/www-conf.h b/contiki-apple2/conf/www-conf.h
new file mode 100644
index 0000000..1c3a761
--- /dev/null
+++ b/contiki-apple2/conf/www-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 Contiki desktop environment
+ *
+ * $Id: www-conf.h,v 1.8 2005/05/23 22:39:56 oliverschmidt Exp $
+ *
+ */
+#ifndef __WWW_CONF_H__
+#define __WWW_CONF_H__
+
+#define WWW_CONF_HOMEPAGE "http://www.sics.se/~adam/contiki/"
+
+/* The size of the HTML viewing area. */
+#ifdef __APPLE2__
+#define WWW_CONF_WEBPAGE_WIDTH 38
+#else /* __APPLE2__ */
+#define WWW_CONF_WEBPAGE_WIDTH 78
+#endif /* __APPLE2__ */
+#define WWW_CONF_WEBPAGE_HEIGHT 16
+
+/* The size of the "Back" history. */
+#define WWW_CONF_HISTORY_SIZE 4
+
+/* Defines the maximum length of an URL */
+#define WWW_CONF_MAX_URLLEN 78
+
+/* The maxiumum number of widgets (i.e., hyperlinks, form elements) on
+   a page. */
+#define WWW_CONF_MAX_NUMPAGEWIDGETS 26
+
+/* Turns <center> support on or off; must be on for forms to work. */
+#define WWW_CONF_RENDERSTATE 1
+
+/* Toggles support for HTML forms. */
+#define WWW_CONF_FORMS       1
+
+/* Maximum lengths for various HTML form parameters. */
+#define WWW_CONF_MAX_FORMACTIONLEN  30
+#define WWW_CONF_MAX_FORMNAMELEN    20
+#define WWW_CONF_MAX_INPUTNAMELEN   20
+
+#define WWW_CONF_MAX_INPUTVALUELEN  (WWW_CONF_WEBPAGE_WIDTH - 1)
+
+#endif /* __WWW_CONF_H__ */
diff --git a/contiki-apple2/contiki.icon b/contiki-apple2/contiki.icon
new file mode 100644
index 0000000..56a5c8e
--- /dev/null
+++ b/contiki-apple2/contiki.icon
Binary files differ
diff --git a/contiki-apple2/ctk/ctk-arch.h b/contiki-apple2/ctk/ctk-arch.h
new file mode 100644
index 0000000..02d08e7
--- /dev/null
+++ b/contiki-apple2/ctk/ctk-arch.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 "ctk" console GUI toolkit for cc65
+ *
+ * $Id: ctk-arch.h,v 1.9 2005/04/17 22:40:11 oliverschmidt Exp $
+ *
+ */
+#ifndef __CTK_ARCH_H__
+#define __CTK_ARCH_H__
+
+#include "ctk-conio.h"
+
+#ifndef CH_CURS_UP
+#define CH_CURS_UP  	0x0B	/* Ctrl-K */
+#endif /* CH_CURS_UP */
+
+#ifndef CH_CURS_DOWN
+#define CH_CURS_DOWN	0x0A	/* Ctrl-J */
+#endif /* CH_CURS_DOWN */
+
+#ifndef CH_DEL
+#define CH_DEL		0x04	/* Ctrl-D */
+#endif /* CH_DEL */
+
+#ifdef __APPLE2ENH__
+
+extern unsigned char ctk_draw_background;
+
+#define ctk_draw_getbackground()      ctk_draw_background
+#define ctk_draw_setbackground(bkgnd) ctk_draw_background = (bkgnd)
+
+#endif /* __APPLE2ENH__ */
+
+#endif /* __CTK_ARCH_H__ */
diff --git a/contiki-apple2/ctk/ctk-mousetext.c b/contiki-apple2/ctk/ctk-mousetext.c
new file mode 100644
index 0000000..0a3a925
--- /dev/null
+++ b/contiki-apple2/ctk/ctk-mousetext.c
@@ -0,0 +1,421 @@
+/*
+ * 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. 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-mousetext.c,v 1.22 2006/05/29 20:57:32 oliverschmidt Exp $
+ *
+ */
+
+#include <conio.h>
+
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "uip.h"
+#include "config.h"
+
+#include "ctk-conio-conf.h"
+#include <string.h>
+#include <ctype.h>
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+unsigned char ctk_draw_windowborder_height = 1;
+unsigned char ctk_draw_windowborder_width = 1;
+unsigned char ctk_draw_windowtitle_height = 1;
+
+unsigned char ctk_draw_background;
+
+/*-----------------------------------------------------------------------------------*/
+static void
+cputsn(char *str, unsigned char len)
+{
+  char c;
+
+  while(len > 0) {
+    --len;
+    c = *str;
+    if(c == 0) {
+      break;
+    }
+    cputc(c);
+    ++str;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_init(void)
+{
+  ctk_draw_clear(0, 24);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_widget(struct ctk_widget *w,
+	    unsigned char x, unsigned char y,
+	    unsigned char clipx,
+	    unsigned char clipy,
+	    unsigned char focus)
+{
+  unsigned char xpos, ypos, xscroll;
+  unsigned char i, j;
+  char c, *text;
+  unsigned char len, wfocus;
+
+  wfocus = 0;
+  if(focus & CTK_FOCUS_WINDOW) {    
+    if(focus & CTK_FOCUS_WIDGET) {
+      wfocus = 1;
+    }
+  } else if(focus & CTK_FOCUS_DIALOG) {
+    if(focus & CTK_FOCUS_WIDGET) {
+      wfocus = 1;
+    }
+  }
+  
+  xpos = x + w->x;
+  ypos = y + w->y;
+    
+  switch(w->type) {
+  case CTK_WIDGET_SEPARATOR:
+    chlinexy(xpos, ypos, w->w);
+    break;
+  case CTK_WIDGET_LABEL:
+    text = w->widget.label.text;
+    for(i = 0; i < w->h; ++i) {
+      gotoxy(xpos, ypos);
+      cputsn(text, w->w);
+      if(w->w - (wherex() - xpos) > 0) {
+	cclear(w->w - (wherex() - xpos));
+      }
+      ++ypos;
+      text += w->w;
+    }
+    break;
+  case CTK_WIDGET_BUTTON:
+    revers(wfocus != 0);
+    cputcxy(xpos, ypos, '[');
+    cputsn(w->widget.button.text, w->w);
+    cputc(']');
+    revers(0);
+    break;
+  case CTK_WIDGET_HYPERLINK:
+    revers(wfocus == 0);
+    gotoxy(xpos, ypos);
+    cputsn(w->widget.button.text, w->w);
+    revers(0);
+    break;
+  case CTK_WIDGET_TEXTENTRY:
+    text = w->widget.textentry.text;
+    xscroll = 0;
+    if(w->widget.textentry.xpos >= w->w - 1) {
+      xscroll = w->widget.textentry.xpos - w->w + 1;
+    }
+    for(j = 0; j < w->h; ++j) {
+      if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
+	 w->widget.textentry.ypos == j) {
+	revers(0);
+	cputcxy(xpos, ypos, '>');
+	c = 1;
+	for(i = 0; i < w->w; ++i) {
+	  if(c != 0) {
+	    c = text[i + xscroll];
+	  }
+	  revers(i == w->widget.textentry.xpos - xscroll);
+	  if(c == 0) {
+	    cputc(' ');
+	  } else {
+	    cputc(c);
+	  }
+	}
+	revers(0);
+	cputc('<');
+      } else {
+	revers(wfocus != 0 && j == w->widget.textentry.ypos);
+	cvlinexy(xpos, ypos, 1);
+	gotoxy(xpos + 1, ypos);          
+	cputsn(text, w->w);
+	i = wherex();
+	if(i - xpos - 1 < w->w) {
+	  cclear(w->w - (i - xpos) + 1);
+	}
+	cvline(1);
+      }
+      ++ypos;
+      text += w->widget.textentry.len + 1;
+    }
+    revers(0);
+    break;
+#if CTK_CONF_ICONS
+  case CTK_WIDGET_ICON:
+    revers(wfocus != 0);
+#if CTK_CONF_ICON_TEXTMAPS
+    if(w->widget.icon.textmap != NULL) {
+      for(i = 0; i < 3; ++i) {
+	gotoxy(xpos, ypos);
+	cputc(w->widget.icon.textmap[0 + 3 * i]);
+	cputc(w->widget.icon.textmap[1 + 3 * i]);
+	cputc(w->widget.icon.textmap[2 + 3 * i]);
+	++ypos;
+      }
+    }
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+    len = strlen(w->widget.icon.title);
+    if(xpos + len >= 80) {
+      xpos = 80 - len;
+    }
+
+    gotoxy(xpos, ypos);
+    cputs(w->widget.icon.title);
+    revers(0);
+    break;
+#endif /* CTK_CONF_ICONS */
+
+  default:
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_widget(struct ctk_widget *w,
+		unsigned char focus,
+		unsigned char clipy1,
+		unsigned char clipy2)
+{
+  struct ctk_window *win = w->window;
+  unsigned char posx, posy;
+
+  posx = win->x + 1;
+  posy = win->y + 2;
+
+  if(w == win->focused) {
+    focus |= CTK_FOCUS_WIDGET;
+  }
+  
+  draw_widget(w, posx, posy, posx + win->w, posy + win->h, focus);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear_window(struct ctk_window *window,
+		      unsigned char focus,
+		      unsigned char clipy1,
+		      unsigned char clipy2)
+{
+  unsigned char i;
+  unsigned char h;
+  
+  h = window->y + 2 + window->h;
+
+  /* Clear window contents. */
+  for(i = window->y + 2; i < h; ++i) {
+    cclearxy(window->x + 1, i, window->w);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_window_contents(struct ctk_window *window, unsigned char focus,
+		     unsigned char x1, unsigned char x2,
+		     unsigned char y1, unsigned char y2)
+{
+  struct ctk_widget *w;
+  unsigned char wfocus;
+  
+  /* Draw inactive widgets. */
+  for(w = window->inactive; w != NULL; w = w->next) {
+    draw_widget(w, x1, y1, x2, y2, focus);
+  }
+  
+  /* Draw active widgets. */
+  for(w = window->active; w != NULL; w = w->next) {  
+    wfocus = focus;
+    if(w == window->focused) {
+      wfocus |= CTK_FOCUS_WIDGET;
+    }
+
+   draw_widget(w, x1, y1, x2, y2, wfocus);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+#pragma codeseg(push, "CODE");
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_window(struct ctk_window *window, unsigned char focus,
+		unsigned char clipy1, unsigned char clipy2,
+		unsigned char draw_borders)
+{
+  unsigned char x, y;
+  unsigned char x1, y1, x2, y2;
+
+  x = window->x;
+  y = window->y + 1;
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + window->w;
+  y2 = y1 + window->h;
+
+  if(draw_borders) {
+
+    /* Draw window frame. */  
+    _textframexy(x, y, window->w + 2, window->h + 2, _TEXTFRAME_TALL);
+  }
+
+  draw_window_contents(window, focus, x1, x2, y1, y2);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_dialog(struct ctk_window *dialog)
+{
+  unsigned char x, y;
+  unsigned char i;
+  unsigned char x1, y1, x2, y2;
+  
+  x = dialog->x;
+  y = dialog->y + 1;
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + dialog->w;
+  y2 = y1 + dialog->h;
+
+  /* Draw dialog frame. */
+  _textframexy(x, y, dialog->w + 2, dialog->h + 2, _TEXTFRAME_WIDE);
+  
+  /* Clear dialog contents. */
+  for(i = y1; i < y2; ++i) {
+    cclearxy(x1, i, dialog->w);
+  }
+
+  draw_window_contents(dialog, CTK_FOCUS_DIALOG, x1, x2, y1, y2);
+}
+/*-----------------------------------------------------------------------------------*/
+#pragma codeseg(pop);
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear(unsigned char y1, unsigned char y2)
+{
+  char c1, c2;
+  unsigned char i;
+
+  if(ctk_draw_background) {
+    c1 = 'V';
+    c2 = 'W';
+  } else {
+    c1 = ' ' | 0x80;
+    c2 = ' ' | 0x80;
+  }
+
+  for(i = 1; i < 24; ++i) {
+    gotoy(i);
+    *(char *)0xC055 = 0;
+    memset(*(char **)0x28, c1, 40);
+    *(char *)0xC054 = 0;
+    memset(*(char **)0x28, c2, 40);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_menu(struct ctk_menu *m, unsigned char open)
+{
+  unsigned char x, x2, y;
+
+  if(open) {
+    x = x2 = wherex();
+    if(x2 + CTK_CONF_MENUWIDTH > 80) {
+      x2 = 80 - CTK_CONF_MENUWIDTH;
+    }
+
+    for(y = 0; y < m->nitems; ++y) {
+      if(y == m->active) {
+	revers(0);
+      } else {
+	revers(1);
+      }
+      gotoxy(x2, y + 1);
+      if(m->items[y].title[0] == '-') {
+	chline(CTK_CONF_MENUWIDTH);
+      } else {
+	cputs(m->items[y].title);
+      }
+      if(x2 + CTK_CONF_MENUWIDTH > wherex()) {
+	cclear(x2 + CTK_CONF_MENUWIDTH - wherex());
+      }
+    }
+
+    gotoxy(x, 0);
+    revers(0);
+  }
+
+  cputs(m->title);
+  cputc(' ');
+  revers(1);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_menus(struct ctk_menus *menus)
+{
+  struct ctk_menu *m;
+
+  /* Draw menus */
+  gotoxy(0, 0);
+  revers(1);
+  cputc(' ');
+  for(m = menus->menus->next; m != NULL; m = m->next) {
+    draw_menu(m, m == menus->open);
+  }
+
+  /* Draw desktopmenu */
+  if(wherex() + strlen(menus->desktopmenu->title) + 1 >= 80) {
+    gotoxy(80 - strlen(menus->desktopmenu->title) - 1, 0);
+  } else {
+    cclear(80 - wherex() -
+	   strlen(menus->desktopmenu->title) - 1);
+  }
+  draw_menu(menus->desktopmenu, menus->desktopmenu == menus->open);
+
+  revers(0);
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_height(void)
+{
+  return 24;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_width(void)
+{
+  return 80;
+}
+/*-----------------------------------------------------------------------------------*/
+int
+ctk_arch_isprint(char c)
+{
+  return isprint(c);
+}
diff --git a/contiki-apple2/lib/bank.S b/contiki-apple2/lib/bank.S
new file mode 100644
index 0000000..9d3d866
--- /dev/null
+++ b/contiki-apple2/lib/bank.S
@@ -0,0 +1,138 @@
+;
+; Bank switching code for Contiki (Apple2 version)
+;
+
+	.segment	"CONTIKI"
+
+	.export		VTABZ
+
+VTABZ:
+	; Switch in ROM and call VTABZ
+	bit	$C082
+	jsr	$FC24
+
+	; Switch in LC bank 2 for R/O and return
+	bit	$C080
+	rts
+
+.ifdef  __APPLE2ENH__
+
+	.code
+
+main2aux:
+	; Switch in $2000-$3FFF from aux memory
+	bit	$C055		; Page2
+	bit	$C057		; HiRes
+	rts
+	
+aux2main:
+	; Switch in $2000-$3FFF from main memory
+	bit	$C056		; LoRes
+	bit	$C054		; Page1
+	rts
+
+	.export		_tcpip_init
+	.import		__tcpip_init
+
+_tcpip_init:
+	jsr	main2aux
+	jsr	__tcpip_init
+	jmp	aux2main
+	
+	.export		_tcpip_eventhandler
+	.import		__tcpip_eventhandler
+
+_tcpip_eventhandler:
+	jsr	main2aux
+	jsr	__tcpip_eventhandler
+	jmp	aux2main
+	
+	.export		_tcpip_pollhandler
+	.import		__tcpip_pollhandler
+
+_tcpip_pollhandler:
+	jsr	main2aux
+	jsr	__tcpip_pollhandler
+	jmp	aux2main
+	
+	.export		_htons
+	.import		__htons
+
+_htons:
+	jsr	main2aux
+	jsr	__htons
+	jmp	aux2main
+	
+	.export		_uiplib_ipaddrconv
+	.import		__uiplib_ipaddrconv
+
+_uiplib_ipaddrconv:
+	jsr	main2aux
+	jsr	__uiplib_ipaddrconv
+	jmp	aux2main
+	
+	.export		_tcp_markconn
+	.import		__tcp_markconn
+
+_tcp_markconn:
+	jsr	main2aux
+	jsr	__tcp_markconn
+	jmp	aux2main
+
+	.export		_tcp_listen
+	.import		__tcp_listen
+
+_tcp_listen:
+	jsr	main2aux
+	jsr	__tcp_listen
+	jmp	aux2main
+
+	.export		_tcp_unlisten
+	.import		__tcp_unlisten
+
+_tcp_unlisten:
+	jsr	main2aux
+	jsr	__tcp_unlisten
+	jmp	aux2main
+
+	.export		_tcp_connect
+	.import		__tcp_connect
+
+_tcp_connect:
+	jsr	main2aux
+	jsr	__tcp_connect
+	jmp	aux2main
+
+	.export		_udp_new
+	.import		__udp_new
+
+_udp_new:
+	jsr	main2aux
+	jsr	__udp_new
+	jmp	aux2main
+
+	.export		_tcpip_input
+	.import		__tcpip_input
+
+_tcpip_input:
+	jsr	main2aux
+	jsr	__tcpip_input
+	jmp	aux2main
+
+	.export		_tcpip_poll_udp
+	.import		__tcpip_poll_udp
+
+_tcpip_poll_udp:
+	jsr	main2aux
+	jsr	__tcpip_poll_udp
+	jmp	aux2main
+	
+	.export		__ek_post_synch
+	.import		_ek_post_synch
+
+__ek_post_synch:
+	jsr	aux2main
+	jsr	_ek_post_synch
+	jmp	main2aux
+
+.endif
diff --git a/contiki-apple2/lib/cfs.c b/contiki-apple2/lib/cfs.c
new file mode 100644
index 0000000..be57120
--- /dev/null
+++ b/contiki-apple2/lib/cfs.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cfs.c,v 1.4 2006/04/09 23:28:10 oliverschmidt Exp $
+ */
+
+
+#include <string.h>
+
+#include "contiki.h"
+#include "kfs.h"
+
+#include "cfs.h"
+
+
+/*---------------------------------------------------------------------------*/
+int
+cfs_opendir(struct cfs_dir *dirp, const char *name)
+{
+  if(strcmp(name, "/") == 0) {
+    name = kfs_getdir();
+  }
+
+  dirp->dir = opendir(name);
+  if(dirp->dir == NULL) {
+    return -1;
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+int
+cfs_readdir(struct cfs_dir *dirp, struct cfs_dirent *direntp)
+{
+  struct dirent *dirent = readdir(dirp->dir);
+  if(dirent == NULL) {
+    return -1;
+  }
+
+  strcpy(direntp->name, dirent->d_name);
+  direntp->size = 0;
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+int
+cfs_closedir(struct cfs_dir *dirp)
+{
+  return closedir(dirp->dir);
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki-apple2/lib/cfs.h b/contiki-apple2/lib/cfs.h
new file mode 100644
index 0000000..bae94c5
--- /dev/null
+++ b/contiki-apple2/lib/cfs.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cfs.h,v 1.4 2006/04/09 23:28:10 oliverschmidt Exp $
+ */
+#ifndef __CFS_H__
+#define __CFS_H__
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#define CFS_READ  (O_RDONLY)
+#define CFS_WRITE (O_WRONLY | O_CREAT | O_TRUNC)
+
+#define cfs_open  open
+#define cfs_close close
+#define cfs_read  read
+#define cfs_write write
+
+struct cfs_dir {
+  DIR *dir;
+};
+
+struct cfs_dirent {
+  char name[16];
+  unsigned int size;
+};
+
+int cfs_opendir(struct cfs_dir *dirp, const char *name);
+int cfs_readdir(struct cfs_dir *dirp, struct cfs_dirent *direntp);
+int cfs_closedir(struct cfs_dir *dirp);
+
+#endif /* __CFS_H__ */
diff --git a/contiki-apple2/lib/clock-arch.S b/contiki-apple2/lib/clock-arch.S
new file mode 100644
index 0000000..5d9c39d
--- /dev/null
+++ b/contiki-apple2/lib/clock-arch.S
@@ -0,0 +1,34 @@
+;
+; Clock tick code for Contiki (Apple2 version)
+;
+
+        .constructor    inittick
+	.export		_tick
+
+	.segment	"INIT"
+
+inittick:
+	; Switch in ROM
+	bit	$C082
+
+	; Check for IIgs
+	sec
+	jsr     $FE1F
+	bcs     done
+
+	; Check for fast speed
+	bit	$C036
+	bpl	done
+
+	; Adjust tick (5/14 = 1.0MHz/2.8MHz)
+	lda	#5
+	sta	_tick
+
+	; Switch in LC bank 2 for R/O
+done:	bit	$C080
+
+	rts
+
+        .data
+
+_tick:	.byte	14
diff --git a/contiki-apple2/lib/clock-arch.h b/contiki-apple2/lib/clock-arch.h
new file mode 100644
index 0000000..78a9270
--- /dev/null
+++ b/contiki-apple2/lib/clock-arch.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: clock-arch.h,v 1.1 2005/05/16 21:20:53 oliverschmidt Exp $
+ */
+#ifndef __CLOCK_ARCH_H__
+#define __CLOCK_ARCH_H__
+
+extern unsigned char tick;
+
+#endif /* __CLOCK_ARCH_H__ */
diff --git a/contiki-apple2/lib/crt0.S b/contiki-apple2/lib/crt0.S
new file mode 100644
index 0000000..acf5533
--- /dev/null
+++ b/contiki-apple2/lib/crt0.S
@@ -0,0 +1,559 @@
+;
+; Startup code for Contiki (Apple2 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+	.export		_exit
+	.import	   	zerobss, initlib, callmain, donelib
+.ifdef  __APPLE2ENH__
+	.import		_uip_buf, callirq
+.endif
+	.import	       	__STARTUP_RUN__			; Linker generated
+	.import	       	__BSS_RUN__, __BSS_SIZE__	; Linker generated
+	.import	       	__INIT_RUN__, __INIT_SIZE__	; Linker generated
+	.import	       	__CODE_RUN__, __CODE_SIZE__	; Linker generated
+	.import	       	__BOOT_SIZE__, __UIP_SIZE__	; Linker generated
+	.importzp	sp
+	.linecont	+
+
+; ------------------------------------------------------------------------
+; The executable header
+
+.segment	"EXEHDR"
+
+	.word  	__STARTUP_RUN__				; Start address
+	.word  	__BSS_RUN__   + __BOOT_SIZE__ +		\
+		__INIT_SIZE__ + __CODE_SIZE__ +		\
+		__UIP_SIZE__ - __STARTUP_RUN__		; Size
+
+; ------------------------------------------------------------------------
+; Place the startup code in a special segment
+
+.segment       	"STARTUP"
+
+; Forward control to the code in the "BOOT" segment
+
+	jmp	__BSS_RUN__
+
+.ifdef  __APPLE2ENH__
+
+; ProDOS TechRefMan, chapter 6.2:
+; "Each installed routine must begin with a CLD instruction."
+
+irq:	cld
+
+; Switch in LC bank 2 for R/O
+
+	bit	$C080
+
+; Call interruptors
+
+	jsr     callirq
+	
+; Switch in LC bank 1 for R/W
+
+	bit	$C08B
+	bit	$C08B
+
+; Check for success
+
+	bcc	:+
+
+; ProDOS TechRefMan, chapter 6.2:
+; "When the routine that can process the interrupt is called, it
+;  should ... return (via an RTS) with the carry flag clear."
+
+	clc
+	rts
+
+; ProDOS TechRefMan, chapter 6.2:
+; "When a routine that cannot process the interrupt is called,
+;  it should return (via an RTS) with the cary flag set ..."
+
+:       sec
+	rts
+
+.endif
+
+; Avoid re-entrance of donelib. This is also the _exit entry
+
+_exit:	ldx	#$02
+:	lda	rvsave,x
+	sta	$03F2,x
+	dex
+	bpl	:-
+
+; Switch in LC bank 2 for R/O
+
+	bit	$C080
+
+; Call module destructors
+
+	jsr	donelib
+
+.ifdef  __APPLE2ENH__
+	
+; Switch in $2000-$3FFF from aux memory
+
+	lda	$C018		; 80Store ?
+	pha
+	sta	$C001		; 80Store On
+	
+	bit	$C055		; Page2
+	bit	$C057		; HiRes
+
+; Call the cleanup code in the "UIP" segment
+
+	jsr	cleanup
+
+; Switch in $2000-$3FFF from main memory
+
+	bit	$C056		; LoRes
+	bit	$C054		; Page1
+	
+	pla
+	bmi	:+
+	sta	$C000		; 80Store Off
+
+.endif
+
+; Switch in ROM
+
+:	bit	$C082
+
+; Back to DOS
+
+	jmp	$03D0
+
+.ifdef  __APPLE2ENH__
+; ------------------------------------------------------------------------
+; There's space left in the "UIP" segment so we move all cleanup code here
+
+.segment	"UIP"
+
+.proc	cleanup
+
+; Deallocate interrupt vector table entry
+
+	dec     intrpt		; Adjust parameter count
+	jsr     $BF00
+	.byte   $41		; Dealloc interrupt
+	.addr   intrpt
+
+; Save last used device number
+
+	lda	$BF30		; DEVNUM
+	sta	devnum
+
+; Read ProDOS dispatcher from /RAM
+
+	jsr     $BF00
+	.byte   $C8		; Open file
+	.addr   open
+	
+	lda	o_ref
+	sta	r_ref
+	sta	c_ref
+
+	jsr     $BF00
+	.byte   $CA		; Read file
+	.addr   read
+
+	jsr     $BF00
+	.byte   $CC		; Close file
+	.addr   close
+	
+; Destroy /RAM files
+
+	jsr     $BF00
+	.byte   $C1		; Destroy file
+	.addr   destr
+
+	dec	n_ext		; CONTIKI.2 -> CONTIKI.1
+
+	jsr     $BF00
+	.byte   $C1		; Destroy file
+	.addr   destr
+
+; Restore last used device number
+
+	lda	devnum
+	sta	$BF30		; DEVNUM
+
+; Switch in LC bank 2 for W/O
+
+	bit	$C081
+	bit	$C081
+
+; Set source start
+
+	lda	#<__BSS_RUN__
+	ldx	#>__BSS_RUN__
+	sta	$3C
+	stx	$3D
+
+; Set source end
+
+	lda	#<(__BSS_RUN__ + $0300)
+	ldx	#>(__BSS_RUN__ + $0300)
+	sta	$3E
+	stx	$3F
+
+; Set destination
+
+	lda	#<$D100
+	ldx	#>$D100
+	sta	$42
+	stx	$43
+
+; Reset index and call MOVE to copy ProDOS dispatcher into LC
+
+	ldy	#$00
+	jmp	$FE2C
+
+open:	.byte	$03		; Parameter count
+	.addr	name		; Pathname
+	.addr	_uip_buf	; IO buffer
+o_ref:	.byte	$00		; Reference number
+
+read:	.byte	$04		; Parameter count
+r_ref:	.byte	$00		; Reference number
+	.addr	__BSS_RUN__	; Data buffer
+	.word	$0300		; Requested count
+	.word	$0000		; Transfered count
+
+close:	.byte	$01		; Parameter count
+c_ref:	.byte	$00		; Reference number
+
+destr:	.byte	$01		; Parameter count
+	.addr	name		; Pathname
+
+name:	.byte	.strlen("/RAM/CONTIKI.2")
+	.byte	"/RAM/CONTIKI."
+n_ext:	.byte	'2'
+
+devnum:	.res	1
+
+.endproc
+.endif
+
+; ------------------------------------------------------------------------
+; The linker doesn't understand that the "BOOT" segment overlays the "BSS"
+; segment so the automatic fixup of references to the "BOOT" segment does
+; not work. Therefore references to this segment have to be expressed as
+; offsets to __BSS_RUN__.
+
+.segment	"BOOT"
+
+.ifdef  __APPLE2ENH__
+
+; Save potential command line arguments from being overwritten by
+; a slot-based realtime clock being called by ProDOS on file I/O
+
+	ldx	#$7F
+:	lda	$0200,x
+	sta	$0100,x
+	dex
+	bpl	:-
+
+; ProDOS TechRefMan, chapter 5.2.2.1:
+; "... you may protect those areas of auxiliary memory. If you save a
+;  dummy 8K file as the first entry in /RAM, it will always be saved
+;  at $2000 to $3FFF."
+;
+; Read /RAM directory
+
+	jsr     $BF00
+	.byte   $C8		; Open file
+	.addr   open
+	
+	lda	o_ref
+	sta	r_ref
+	sta	c_ref
+
+	jsr     $BF00
+	.byte   $CA		; Read file
+	.addr   read
+
+	jsr     $BF00
+	.byte   $CC		; Close file
+	.addr   close
+	
+; ProDOS TechRefMan, chapter B.2.5:
+; "FileCount := ThisBlock[$25] + (256 * ThisBlock[$26]);"
+;
+; Make sure /RAM is empty
+
+	lda	END + $25
+	ora	END + $26
+	beq	:++
+	
+	ldx	#.strlen("Fatal error: /RAM not empty !")
+:	lda	error,x
+	jsr	$FDED		; COUT
+	dex
+	bpl     :-
+	
+	jsr	$FD0C		; RDKEY
+	jmp	$03D0		; DOSWARM
+
+; Switch to 80 column mode here to show some progress
+
+:	lda	#$0D
+	jsr	$C300
+	
+; Relocate the "UIP" segment by writing it to /RAM as the first file
+
+	lda	#.strlen("/RAM/CONTIKI.1")
+	sta	name
+	jsr	ramfile
+	
+; Switch in LC bank 2 for R/O
+
+	bit	$C080
+
+; Copy ProDOS dispatcher out of LC
+
+	ldx	#$00
+l_mod	= __BSS_RUN__ + *
+:	lda	$D100,x
+s_mod	= __BSS_RUN__ + *
+	sta	UIP,x
+	inx
+	bne	:-
+	inc	l_mod+2
+	inc	s_mod+2
+	lda	l_mod+2
+	cmp	#>$D400
+	bne	:-
+
+; Write ProDOS dispatcher to /RAM
+
+	lda	#>$0300
+	sta	w_cnt+1
+	inc	n_ext		; CONTIKI.1 -> CONTIKI.2
+	jsr	ramfile
+	
+; Restore potential command line arguments
+
+	ldx	#$7F
+:	lda	$0100,x
+	sta	$0200,x
+	dex
+	bpl	:-
+
+; Allocate interrupt vector table entry
+
+	jsr     $BF00
+	.byte   $40		; Alloc interrupt
+	.addr   intrpt
+
+.endif
+
+; Setup the stack at HIMEM
+
+	lda    	$73
+	ldx	$73+1
+	sta	sp
+	stx	sp+1
+
+; Save the original RESET vector
+
+	ldx	#$02
+:	lda	$03F2,x
+	sta	rvsave,x
+	dex
+	bpl	:-
+
+; ProDOS TechRefMan, chapter 5.3.5:
+; "Your system program should place in the RESET vector the address of a
+;  routine that ... closes the files."
+
+	lda	#<_exit
+	sta	$03F2
+	lda	#>_exit
+	sta	$03F3
+	eor	#$A5
+	sta	$03F4
+		
+; Switch in LC bank 2 for W/O
+
+	bit	$C081
+	bit	$C081
+
+; Set source start
+
+	lda	#<(__BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__)
+	ldx	#>(__BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__)
+	sta	$3C
+	stx	$3D
+
+; Set source end
+
+	lda	#<(__BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__ + __CODE_SIZE__)
+	ldx	#>(__BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__ + __CODE_SIZE__)
+	sta	$3E
+	stx	$3F
+
+; Set destination
+
+	lda	#<__CODE_RUN__
+	ldx	#>__CODE_RUN__
+	sta	$42
+	stx	$43
+
+; Reset index and call MOVE to relocate the "CODE" segment
+
+	ldy	#$00
+	jsr	$FE2C
+
+; Set source start
+
+	lda	#<(__BSS_RUN__ + __BOOT_SIZE__)
+	ldx	#>(__BSS_RUN__ + __BOOT_SIZE__)
+	sta	$3C
+	stx	$3D
+
+; Set source end
+
+	lda	#<(__BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__)
+	ldx	#>(__BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__)
+	sta	$3E
+	stx	$3F
+
+; Set destination
+
+	lda	#<__INIT_RUN__
+	ldx	#>__INIT_RUN__
+	sta	$42
+	stx	$43
+
+; Reset index and call MOVE to relocate the "INIT" segment
+
+	ldy	#$00
+	jsr	$FE2C
+
+; Switch in LC bank 2 for R/O
+
+	bit	$C080
+
+; Forward control to code in the "INIT" segment
+
+	jmp	init
+	
+.ifdef  __APPLE2ENH__
+
+; Create a temporary file in /RAM
+
+ramfile	= __BSS_RUN__ + *
+	jsr     $BF00
+	.byte   $C0		; Create file
+	.addr   create
+
+	jsr     $BF00
+	.byte   $C8		; Open file
+	.addr   open
+	
+	lda	o_ref
+	sta	w_ref
+	sta	c_ref
+
+	jsr     $BF00
+	.byte   $CB		; Write file
+	.addr   write
+
+	jsr     $BF00
+	.byte   $CC		; Close file
+	.addr   close
+	
+	rts
+
+UIP	= __BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__ + __CODE_SIZE__
+END	= __BSS_RUN__ + __BOOT_SIZE__ + __INIT_SIZE__ + __CODE_SIZE__ + __UIP_SIZE__
+
+create	= __BSS_RUN__ + *
+	.byte	$07		; Parameter count
+	.addr	name		; Pathname
+	.byte	%11000011	; Access:	Standard full access
+	.byte	$00		; File type:	Typeless file
+	.word	$0000		; Aux type:	N/A
+	.byte	$01		; Storage type:	Standard seedling file
+	.word	$0000		; Create date:	Current date
+	.word	$0000		; Create time:	Current time
+
+open	= __BSS_RUN__ + *
+	.byte	$03		; Parameter count
+	.addr	name		; Pathname
+	.addr	_uip_buf	; IO buffer
+o_ref	= __BSS_RUN__ + *
+	.byte	$00		; Reference number
+
+read	= __BSS_RUN__ + *
+	.byte	$04		; Parameter count
+r_ref	= __BSS_RUN__ + *
+	.byte	$00		; Reference number
+	.addr	END		; Data buffer
+	.word	$0200		; Requested count
+	.word	$0000		; Transfered count
+
+write	= __BSS_RUN__ + *
+	.byte	$04		; Parameter count
+w_ref	= __BSS_RUN__ + *
+	.byte	$00		; Reference number
+	.addr	UIP		; Data buffer
+w_cnt	= __BSS_RUN__ + *
+	.word	$2000		; Requested count
+	.word	$0000		; Transfered count
+
+close	= __BSS_RUN__ + *
+	.byte	$01		; Parameter count
+c_ref	= __BSS_RUN__ + *
+	.byte	$00		; Reference number
+
+name	= __BSS_RUN__ + *
+	.byte	.strlen("/RAM")
+	.byte	"/RAM/CONTIKI."
+n_ext	= __BSS_RUN__ + *
+	.byte	'1'
+
+error	= __BSS_RUN__ + *
+	.byte	$8D,     '!'|$80, ' '|$80, 'y'|$80, 't'|$80, 'p'|$80
+	.byte	'm'|$80, 'e'|$80, ' '|$80, 't'|$80, 'o'|$80, 'n'|$80
+	.byte	' '|$80, 'M'|$80, 'A'|$80, 'R'|$80, '\'|$80, ' '|$80
+	.byte	':'|$80, 'r'|$80, 'o'|$80, 'r'|$80, 'r'|$80, 'e'|$80
+	.byte	' '|$80, 'l'|$80, 'a'|$80, 't'|$80, 'a'|$80, 'F'|$80
+
+.endif
+
+; ------------------------------------------------------------------------
+; The "INIT" segment will be overwritten by the heap
+
+.segment	"INIT"
+
+; Clear the BSS data (and thus overwrite the "BOOT" segment)
+
+init:	jsr	zerobss
+
+; Call module constructors
+
+	jsr	initlib
+
+; Push arguments and call main()
+
+	jmp	callmain
+
+; ------------------------------------------------------------------------
+; Data
+
+.data
+
+rvsave:	.res	3
+
+.ifdef  __APPLE2ENH__
+
+intrpt: .byte   $02		; Parameter count
+	.byte   $00		; Interrupt number
+	.addr   irq		; Interrupt handler
+
+.endif
\ No newline at end of file
diff --git a/contiki-apple2/lib/import.S b/contiki-apple2/lib/import.S
new file mode 100644
index 0000000..4ab774c
--- /dev/null
+++ b/contiki-apple2/lib/import.S
@@ -0,0 +1,11 @@
+;
+; Forced importing code for Contiki (Apple2 version)
+;
+; These symbols are necessary for (at least some) apps, but are
+; initialized by constructors which are currently not supported
+; for apps. Therefore we include these symbols into the Contiki
+; kernel to make them thus available to the apps indirectly via
+; the contiki-labels mechanism.
+
+	.forceimport	__dos_type
+	.forceimport	__cwd
diff --git a/contiki-apple2/lib/kfs.S b/contiki-apple2/lib/kfs.S
new file mode 100644
index 0000000..414170e
--- /dev/null
+++ b/contiki-apple2/lib/kfs.S
@@ -0,0 +1,178 @@
+;
+; Contiki kernel file system (Apple2 version)
+;
+; int __fastcall__ kfs_open(const char* name);
+; int __fastcall__ kfs_read(int fd, void* buf, unsigned count);
+; int __fastcall__ kfs_close(int fd);
+; char* kfs_getdir(void);
+;
+
+	.constructor	init_kfs
+        .destructor     done_kfs
+	.export		_kfs_open, _kfs_read, _kfs_close, _kfs_getdir
+	.import		_uip_buf, popax
+	.importzp 	ptr1
+
+PATHNAME	:= $0280
+MLI		:= $BF00
+
+GET_PREFIX_CALL	= $C7
+OPEN_CALL	= $C8
+READ_CALL	= $CA
+CLOSE_CALL	= $CC
+
+; ------------------------------------------------------------------------
+
+	.bss
+
+PREFIX:		.res	1
+
+; ------------------------------------------------------------------------
+
+	.data
+
+OPEN_PARAM:
+		.byte	$03		;PARAM_COUNT
+		.addr	PATHNAME	;PATHNAME
+		.addr	_uip_buf	;IO_BUFFER
+OPEN_FD:	.byte	$00		;REF_NUM
+
+READ_PARAM:
+		.byte	$04		;PARAM_COUNT
+READ_FD:	.byte	$00		;REF_NUM
+READ_BUFFER:	.addr	$0000		;DATA_BUFFER
+READ_COUNT_IN:	.word	$0000		;REQUEST_COUNT
+READ_COUNT_OUT:	.word	$0000		;TRANS_COUNT
+
+CLOSE_PARAM:
+		.byte	$01		;PARAM_COUNT
+CLOSE_FD:	.byte	$00		;REF_NUM
+
+; ------------------------------------------------------------------------
+
+	.segment	"INIT"
+
+init_kfs:
+        ; Check for full pathname
+	lda	PATHNAME+1
+	cmp	#'/'
+	beq	prefix
+
+	; Save name incl. length
+	ldx	PATHNAME
+:	lda	PATHNAME,x
+	sta	_uip_buf,x
+	dex
+	bpl	:-
+
+	jsr	MLI
+	.byte	GET_PREFIX_CALL
+	.addr	GET_PREFIX_PARAM
+
+	; Append name to prefix
+	lda	PATHNAME
+	clc
+	adc	_uip_buf
+	sta	PATHNAME
+	tax
+	ldy	_uip_buf
+:	lda	_uip_buf,y
+	sta	PATHNAME,x
+	dex
+	dey
+	bne	:-
+
+prefix:	lda	PATHNAME
+	sec
+	sbc	#.strlen("CONTIKI")
+	sta	PREFIX
+	rts
+
+GET_PREFIX_PARAM:
+		.byte	$01		; PARAM_COUNT
+		.addr	PATHNAME	; DATA_BUFFER
+
+; ------------------------------------------------------------------------
+
+	.segment	"CONTIKI"
+
+_kfs_open:
+	; Append name to prefix
+	sta	ptr1
+	stx	ptr1+1
+	ldy	#$00
+	ldx	PREFIX
+:	lda	(ptr1),y
+	beq	:+
+	sta	PATHNAME+1,x
+	iny
+	inx
+	bne	:-	; bra
+:	stx	PATHNAME
+
+	jsr	MLI
+	.byte	OPEN_CALL
+	.addr	OPEN_PARAM
+	bcs	ERROR
+
+	; Return fd
+	lda	OPEN_FD
+	ldx	#$00
+	rts
+
+_kfs_read:
+	; Store count
+	sta	READ_COUNT_IN
+	stx	READ_COUNT_IN+1
+
+	; Pop and store buf
+	jsr	popax
+	sta	READ_BUFFER
+	stx	READ_BUFFER+1
+
+	; Pop and store fd
+	jsr     popax
+	sta	READ_FD
+
+	jsr	MLI
+	.byte	READ_CALL
+	.addr	READ_PARAM
+	bcs	ERROR
+
+	; Return bytes transfered
+	lda	READ_COUNT_OUT
+	ldx	READ_COUNT_OUT+1
+	rts
+
+done_kfs:
+	lda	#$00
+
+_kfs_close:
+	; Store	fd
+	sta	CLOSE_FD
+
+	jsr	MLI
+	.byte	CLOSE_CALL
+	.addr	CLOSE_PARAM
+	bcs	ERROR
+
+	; Return 0
+	tax
+	rts
+
+_kfs_getdir:
+	; Append '\0' to prefix
+	lda	#$00
+	ldx	PREFIX
+	sta	PATHNAME+1,x
+
+	; Return prefix
+	lda	#<(PATHNAME+1)
+	ldx	#>(PATHNAME+1)
+	rts
+
+ERROR:
+	; Return -1
+	lda     #$FF
+        tax
+        rts
diff --git a/contiki-apple2/lib/kfs.h b/contiki-apple2/lib/kfs.h
new file mode 100644
index 0000000..a305103
--- /dev/null
+++ b/contiki-apple2/lib/kfs.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: kfs.h,v 1.2 2005/04/14 21:01:07 oliverschmidt Exp $
+ */
+#ifndef __KFS_H__
+#define __KFS_H__
+
+int __fastcall__ kfs_open(const char* name);
+int __fastcall__ kfs_read(int fd, void* buf, unsigned count);
+int __fastcall__ kfs_close(int fd);
+char* kfs_getdir(void);
+
+#endif /* __KFS_H__ */
diff --git a/contiki-apple2/loader/loader-arch.c b/contiki-apple2/loader/loader-arch.c
new file mode 100644
index 0000000..8ab73d8
--- /dev/null
+++ b/contiki-apple2/loader/loader-arch.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: loader-arch.c,v 1.3 2005/05/07 14:25:47 oliverschmidt Exp $
+ *
+ */
+
+#include <modload.h>
+
+#include "loader.h"
+#include "kfs.h"
+
+struct mod_ctrl ctrl = {
+  kfs_read
+};
+
+struct loader_arch_hdr {
+  char arch[8];
+  char version[8];
+
+  char initfunc[1];
+};
+
+/*-----------------------------------------------------------------------------------*/
+/* load(name)
+ *
+ * Loads a program from disk and executes it. Code originally written by
+ * Ullrich von Bassewitz.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+load(const char *name)
+{
+  unsigned char res;
+  
+  /* Now open the file */
+  ctrl.callerdata = kfs_open(name);
+  if(ctrl.callerdata < 0) {
+    /* Could not open the file, display an error and return */
+    /* ### */
+    return LOADER_ERR_OPEN;
+  }
+
+  /* Load the module */
+  res = mod_load(&ctrl);
+  
+  /* Close the input file */
+  kfs_close(ctrl.callerdata);
+  
+  /* Check the return code */
+  if(res != MLOAD_OK) {
+    /* Wrong module, out of memory or whatever. Print an error
+     * message and return.
+     */
+    /* ### */
+    return res;
+  }
+  
+  /* We've successfully loaded the module. */
+  
+  return LOADER_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+loader_arch_load(const char *name, char *arg)
+{
+  unsigned char r;
+  struct loader_arch_hdr *hdr;
+  
+  r = load(name);
+  if(r != MLOAD_OK) {
+    return r;
+  }
+  hdr = (struct loader_arch_hdr *)ctrl.module;
+  
+  /* Check the program header and see that version and architecture
+     matches. */
+  
+  /* Call the init function. */
+
+  ((void (*)(char *))hdr->initfunc)(arg);
+
+  return LOADER_OK;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/main.c b/contiki-apple2/main.c
new file mode 100644
index 0000000..0332ee3
--- /dev/null
+++ b/contiki-apple2/main.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2004, 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: main.c,v 1.18 2006/06/28 23:10:43 oliverschmidt Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ek.h"
+
+#include "program-handler.h"
+
+#include "uip.h"
+#include "uip_arp.h"
+
+#include "resolv.h"
+
+#include "www-dsc.h"
+#include "email-dsc.h"
+#include "ftp-dsc.h"
+#include "directory-dsc.h"
+
+#include "clock.h"
+#include "clock-arch.h"
+
+#if CTK_CONF_MOUSE_SUPPORT
+#define TICK_COUNT 2800
+#else
+#define TICK_COUNT 4200
+#endif
+
+unsigned char lanslot;
+unsigned char prefixok;
+
+#pragma bssseg(push, "UIPBUF");
+u8_t uip_buf[UIP_BUFSIZE + 2];
+#pragma bssseg(pop);
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+uip_fw_forward(void)
+{
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_fw_periodic(void)
+{
+  return;
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  switch(ev) {
+  case EK_EVENT_INIT:
+    program_handler_load("config.prg", NULL);
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_PROCESS(init, "Init", EK_PRIO_LOWEST,
+	   eventhandler, NULL, NULL);
+/*-----------------------------------------------------------------------------------*/
+clock_time_t
+clock_time(void)
+{
+  static clock_time_t count, clock;
+
+  count += tick;
+
+  if(count == TICK_COUNT) {
+    count = 0;
+    ++clock;
+  }
+
+  return clock;
+}
+/*-----------------------------------------------------------------------------------*/
+#define STACK_SIZE 0
+#if STACK_SIZE
+#include <conio.h>
+#include <stdlib.h>
+void
+stack_size(void)
+{
+  static unsigned char *c;
+  static unsigned int s;
+  c = (unsigned char *)(0xBF00 - STACK_SIZE);
+  while(*c++ == 0xA2) {
+  }
+  s = (unsigned char *)0xBF00 - c;
+  clrscr();
+  cputc('0' + s / 100 % 10);
+  cputc('0' + s / 10  % 10);
+  cputc('0' + s       % 10);
+  cgetc();
+}
+#endif /* STACK_SIZE */
+/*-----------------------------------------------------------------------------------*/
+void
+#ifdef __APPLE2__
+main(void)
+#else /* __APPLE2__ */
+main(int argc, char *argv[])
+#endif /* __APPLE2__ */
+{
+
+#if STACK_SIZE
+  memset((void *)(0xBF00 - STACK_SIZE),
+         0xA2, STACK_SIZE - (0xBF00 - *(unsigned int *)0x80) - 10);
+  atexit(stack_size);
+#endif /* STACK_SIZE */
+
+  ek_init();
+  ek_start(&init);
+
+  tcpip_init(NULL);
+  resolv_init(NULL);
+  
+  ctk_init();
+  
+  program_handler_init();
+
+  program_handler_add(&www_dsc,       "Web browser", 1);
+  program_handler_add(&email_dsc,     "E-mail",      1);
+  program_handler_add(&ftp_dsc,       "FTP client",  1);
+  program_handler_add(&directory_dsc, "Directory",   1);
+
+  while(1) {
+    if(ek_run() == 0) {
+
+#ifdef __APPLE2__
+
+      program_handler_load("welcome.prg", NULL);
+
+#else /* __APPLE2__ */
+
+      static char *startup;
+      static char *slash;
+
+      if(argc == 1) {
+        startup = "welcome.prg";
+      } else {
+	startup = argv[1];
+	while(slash = strchr(startup, '/')) {
+	  startup = slash + 1;
+	}
+      }
+      program_handler_load(startup, NULL);
+
+#endif /* __APPLE2__ */
+
+      break;
+    }
+  }
+  while(1) {
+    ek_run();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/readme.txt b/contiki-apple2/readme.txt
new file mode 100644
index 0000000..88a7e11
--- /dev/null
+++ b/contiki-apple2/readme.txt
@@ -0,0 +1,186 @@
+
+Contiki on the Apple ][ (Oliver Schmidt)
+========================================
+
+
+Contiki for the Apple ][ comes in two variants:
+
+1. 'Contiki40' runs in 40 column text mode and requires at least an Apple ][+
+   with Language Card resulting in 64kB memory.
+
+2. 'Contiki80' runs in 80 column text mode and requires at least an enhanced
+   Apple //e with Extended 80 Column Board resulting in 128kB memory.
+   
+The remainder of this text describes Contiki80.
+
+
+Installation
+------------
+
+1. Get the 'cc65 complete cross development package' from 06/01/2006 or later:
+   http://www.cc65.org
+
+
+2. Build the two targets apple2enh and programsenh.
+
+
+3. Get the 'a2tools' by Terry Kyriacopoulos:
+   ftp://ftp.apple.asimov.net/pub/apple_II/unsorted/a2tools.zip
+
+
+4. Get the 'Apple][ ProDOS 8 system program for loading binary programs':
+   ftp://ftp.musoftware.de/pub/uz/cc65/contrib/loader-1.2.zip
+
+
+5. Use the 'a2tools' to copy these files into a DOS 3.3 disk image:
+
+   a2tools in b      dos33.dsk CONTIKI.SYSTEM loader~1.sys
+   a2tools in -r b   dos33.dsk CONTIKI        contiki
+   a2tools in b.0000 dos33.dsk A2E.STDMOU.MOU a2estd~1.mou
+   a2tools in b.0000 dos33.dsk ABOUT.PRG      about.prg
+   a2tools in b.0000 dos33.dsk ABOUT.DSC      about.dsc
+   a2tools in b.0000 dos33.dsk CALC.PRG       calc.prg
+   a2tools in b.0000 dos33.dsk CALC.DSC       calc.dsc
+   a2tools in b.0000 dos33.dsk CONFIG.PRG     config.prg
+   a2tools in b.0000 dos33.dsk CONFIGEDIT.PRG config~1.prg
+   a2tools in b.0000 dos33.dsk CONFIGEDIT.DSC config~1.dsc
+   a2tools in b.0000 dos33.dsk DHCP.PRG       dhcp.prg
+   a2tools in b.0000 dos33.dsk DHCP.DSC       dhcp.dsc
+   a2tools in b.0000 dos33.dsk DIRECTORY.PRG  direct~1.prg
+   a2tools in b.0000 dos33.dsk DIRECTORY.DSC  direct~1.dsc
+   a2tools in b.0000 dos33.dsk EMAIL.PRG      email.prg
+   a2tools in b.0000 dos33.dsk EMAIL.DSC      email.dsc
+   a2tools in b.0000 dos33.dsk FTP.PRG        ftp.prg
+   a2tools in b.0000 dos33.dsk FTP.DSC        ftp.dsc
+   a2tools in b.0000 dos33.dsk IRC.PRG        irc.prg
+   a2tools in b.0000 dos33.dsk IRC.DSC        irc.dsc
+   a2tools in b.0000 dos33.dsk MEMSTAT.PRG    memstat.prg
+   a2tools in b.0000 dos33.dsk MEMSTAT.DSC    memstat.dsc
+   a2tools in b.0000 dos33.dsk PROCESSES.PRG  proces~1.prg
+   a2tools in b.0000 dos33.dsk PROCESSES.DSC  proces~1.dsc
+   a2tools in b.0000 dos33.dsk SHELL.PRG      shell.prg
+   a2tools in b.0000 dos33.dsk SHELL.DSC      shell.dsc
+   a2tools in b.0000 dos33.dsk TELNET.PRG     telnet.prg
+   a2tools in b.0000 dos33.dsk TELNET.DSC     telnet.dsc
+   a2tools in b.0000 dos33.dsk WEBSERVER.PRG  webser~1.prg
+   a2tools in b.0000 dos33.dsk WEBSERVER.DSC  webser~1.dsc
+   a2tools in b.0000 dos33.dsk WELCOME.PRG    welcome.prg
+   a2tools in b.0000 dos33.dsk WGET.PRG       wget.prg
+   a2tools in b.0000 dos33.dsk WGET.DSC       wget.dsc
+   a2tools in b.0000 dos33.dsk WWW.PRG        www.prg
+   a2tools in b.0000 dos33.dsk WWW.DSC        www.dsc
+   a2tools in b.0000 dos33.dsk LANCEGS.DRV    lancegs.drv
+   a2tools in b.0000 dos33.dsk LANCEGS.DSC    lancegs.dsc
+   a2tools in b.0000 dos33.dsk UTHER.DRV      uther.drv
+   a2tools in b.0000 dos33.dsk UTHER.DSC      uther.dsc
+   a2tools in b.0000 dos33.dsk BOUNCE.SAV     bounce.sav
+   a2tools in b.0000 dos33.dsk BOUNCE.DSC     bounce.dsc
+   a2tools in b.0000 dos33.dsk PLASMA.SAV     plasma.sav
+   a2tools in b.0000 dos33.dsk PLASMA.DSC     plasma.dsc
+   a2tools in b.0000 dos33.dsk SSFIRE.SAV     ssfire.sav
+   a2tools in b.0000 dos33.dsk SSFIRE.DSC     ssfire.dsc
+
+
+6. Use any ProDOS 8 file utility program capable of reading DOS 3.3 files to
+   copy the files from the DOS 3.3 disk to a ProDOS 8 disk.
+
+
+7. Use BASIC.SYSTEM to convert the loader from a BIN to a SYS file:
+
+   BLOAD  CONTIKI.SYSTEM
+   DELETE CONTIKI.SYSTEM
+   CREATE CONTIKI.SYSTEM,TSYS
+   BSAVE  CONTIKI.SYSTEM,TSYS,A$2000,L465
+
+
+Usage
+-----
+
+Select CONTIKI.SYSTEM from the ProDOS 8 dispatcher or use BASIC.SYSTEM:
+
+   - CONTIKI.SYSTEM
+
+1. CONTIKI.SYSTEM supports the ProDOS 8 startup file protocol. The startup file
+   will be initially launched instead of WELCOME.PRG.
+
+   The startup file support allows to open *.PRG files from the GS/OS finder:
+   
+   a) Give your Contiki disk the volume name /CONTIKI
+   b) Copy contiki.icon to /CONTIKI/ICONS/CONTIKI.ICON
+   c) Set the filetype of CONTIKI.ICON to $CA aka ICN
+   d) Set the filetype of the *.PRG files to $FE aka REL
+   
+2. Contiki includes mouse support for the AppleMouse II Card, the Apple //c and
+   the Apple IIgs. All slots are searched for mouse firmware but if non is found
+   the mouse support is silently turned off.
+   
+   IIgs ROM 3 users: Make sure to have set 'Slot 4' in the 'Control Panel' to
+                     'Mouse Port' although this isn't necessary for GS/OS.
+
+
+Implementation Notes
+--------------------
+
+1. File I/O
+
+   Contiki loads programs, drivers and screensavers from disk using ProDOS 8.
+   The ProDOS 8 file I/O library in the cc65 C-library is to large to be used
+   to load WWW.PRG into a 64k Apple ][. Fortunately WWW.PRG itself does no file
+   I/O but delegates that to WGET.PRG which is a lot smaller than WWW.PRG. so
+   the solution is to have two different file I/O libaries.
+   
+   The first one is as small as possible and is only capable of reading one file
+   at a time and only from the directory CONTIKI resides in. It is part of the
+   Contiki kernel and thus called 'KernelFileSystem' (kfs). ProDOS 8 needs a 1kB
+   I/O buffer aligned to a page boundary for every opoen file. The one and only
+   I/O buffer necessary for fks is placed at $0800-$0BFF and serves as buffer
+   for incoming/outgoing IP data as well.
+   
+   The other one which is called 'ContikiFileSystem' (cfs) is mapped to the
+   existing cc65 C-library and linked into the programs (like WGET.PRG).
+   
+2. Memory Layout
+
+   The Contiki memory layout is based on the standard cc65 layout which means
+   that the binary is loaded to the lowest available address ($0C00 here) and
+   contains the CODE, RODATA and DATA segments. The BSS segment is located
+   directly above those and set to zero programatically. The cc65 stack (not
+   to be confused with the 6502 stack at $0100-$01FF) starts at the highest
+   available address and grows downwards. The heap is located between the BSS
+   and the stack.
+   
+   But to satisfy the memory requirements of the larger Contiki programs
+   several modifications were necessary:
+   
+   Generally it's very hard to make use of memory mapping for an event driven
+   system like Contiki but the Apple //e allows to map only 8kB of Aux memory
+   to the address space $2000-$3FFF to facilitate double hires graphics. This
+   feature is accompanied by ProDOS 8 which allows to keep /RAM generally active
+   while doing double hires graphics by saving a 8kB file as first file to /RAM
+   and thus preserving $2000-$3FFF of Aux memory. Contiki makes use of all this
+   double hires support while just staying in text mode and using the 8kB as
+   additional memory.
+
+   The additional 8kB are used to store the code of the uIP TCP/IP stack. They
+   are mapped in both on calls from the Contiki event kernel to the TCP/IP stack
+   process (poll and event handler) and calls to the uIP API from programs. Most
+   of the time the 8kB are just kept mapped in when the uIP code calls other
+   code. This is possible because the only memory not reachable from the uIP
+   code are the corresponding 8kB of Main memory - and the Contiki kernel
+   objects are linked in an order which makes only CTK code (which is never
+   called by uIP code) use that 8kB of Main memory. The only call from uIP code
+   that triggers mapping out the 8kB of Aux memory is the uIP upcall into a
+   program for processing incoming IP data as some program may potentially call
+   CTK code while processing that data.
+
+   Beside that Contiki makes use of the Language Card bank 2 to store the code
+   of the C-libary. Most of this 4 kB can be considered free although officially
+   marked as reserved by ProDOS 8. Only $D100-$D3FF are actually used to store
+   the ProDOS 8 dispatcher. As it is only used after terminating Contiki it can
+   be saved to /RAM on startup and restored from there while cleanup.
+
+   The code doing all that code relocation gets overwritten on setting the BSS
+   segment to zero. The code doing this (and the C-library initialization) gets
+   overwritten later by the heap content.
+   
+eof
\ No newline at end of file
diff --git a/contiki-apple2/uip/cs8900a.c b/contiki-apple2/uip/cs8900a.c
new file mode 100644
index 0000000..872691b
--- /dev/null
+++ b/contiki-apple2/uip/cs8900a.c
@@ -0,0 +1,324 @@
+/*
+ * 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. 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 C64 RealAudio server demo project.
+ *
+ * $Id: cs8900a.c,v 1.8 2005/05/22 14:04:21 oliverschmidt Exp $
+ *
+ */
+
+/* cs8900a.c: device driver for the CS8900a chip in 8-bit mode. Mostly
+   written in 6502 assembler for speed. */
+
+#include "cs8900a.h"
+#include "uip.h"
+#include "uip_arp.h"
+
+extern u8_t lanslot;
+extern u8_t *cs8900a_rxtxreg,
+            *cs8900a_txcmd,
+            *cs8900a_txlen,
+            *cs8900a_packetpp,
+            *cs8900a_ppdata;
+
+static u8_t idx;
+static u16_t len;
+static u16_t cnt;
+
+
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+void
+cs8900a_init(void)
+{
+  asm("lda %v", lanslot);
+  asm("beq %g", bailout);
+  asm("asl");
+  asm("asl");
+  asm("asl");
+  asm("asl");
+  asm("sta %v", idx);
+  asm("tax");
+
+  /* Turn on transmission and reception of frames. */
+  /* PACKETPP = 0x0112;
+     PPDATA   = 0x00c0; */
+  asm("lda #$12");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda #$c0");
+  asm("sta %v,x", cs8900a_ppdata);
+  asm("lda #$00");
+  asm("sta %v+1,x", cs8900a_ppdata);
+
+  /* Accept valid unicast+broadcast frames. */
+  /* PACKETPP = 0x0104;
+     PPDATA   = 0x0d05; */
+  asm("lda #$04");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda #$05");
+  asm("sta %v,x", cs8900a_ppdata);
+  asm("lda #$0d");
+  asm("sta %v+1,x", cs8900a_ppdata);
+
+  /* Set MAC address. */
+  /* PACKETPP = 0x0158;
+     PPDATA   = (ETHADDR1 << 8) | (ETHADDR0); */
+  asm("lda #$58");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda %v", uip_ethaddr);
+  asm("sta %v,x", cs8900a_ppdata);
+  asm("lda %v+1", uip_ethaddr);
+  asm("sta %v+1,x", cs8900a_ppdata);
+
+  /* PACKETPP = 0x015a;
+     PPDATA   = (ETHADDR3 << 8) | (ETHADDR2); */
+  asm("lda #$5a");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda %v+2", uip_ethaddr);
+  asm("sta %v,x", cs8900a_ppdata);
+  asm("lda %v+3", uip_ethaddr);
+  asm("sta %v+1,x", cs8900a_ppdata);
+
+  /* PACKETPP = 0x015c;
+     PPDATA   = (ETHADDR5 << 8) | (ETHADDR4); */
+  asm("lda #$5c");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda %v+4", uip_ethaddr);
+  asm("sta %v,x", cs8900a_ppdata);
+  asm("lda %v+5", uip_ethaddr);
+  asm("sta %v+1,x", cs8900a_ppdata);
+bailout:
+}
+#pragma optimize(pop)
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+void
+cs8900a_send(void)
+{
+  asm("ldx %v", idx);
+  asm("beq %g", bailout);
+
+  /* Transmit command. */
+  asm("lda #$c0");
+  asm("sta %v,x", cs8900a_txcmd);
+  asm("lda #$00");
+  asm("sta %v+1,x", cs8900a_txcmd);
+  asm("lda %v", uip_len);
+  asm("sta %v,x", cs8900a_txlen);
+  asm("lda %v+1", uip_len);
+  asm("sta %v+1,x", cs8900a_txlen);
+
+  asm("ldy #8");
+tryagain:
+  /* Check for avaliable buffer space. */
+  asm("lda #$38");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda %v+1,x", cs8900a_ppdata);
+  asm("and #1");
+  asm("bne %g", send);
+
+  /* No space avaliable, skip a received frame and try again. */
+  asm("lda #$02");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda %v,x", cs8900a_ppdata);
+  asm("ora #$40");
+  asm("sta %v,x", cs8900a_ppdata);
+
+  asm("dey");
+  asm("bne %g", tryagain);
+bailout:
+  return;
+
+  /* Send the frame. */
+send:
+
+  /* First, send 14+40=54 bytes of header. */
+  asm("ldy #0");
+sendloop1:
+  asm("lda %v,y", uip_buf);
+  asm("sta %v,x", cs8900a_rxtxreg);
+  asm("iny");
+  asm("lda %v,y", uip_buf);
+  asm("sta %v+1,x", cs8900a_rxtxreg);
+  asm("iny");
+  asm("cpy #%b", UIP_LLH_LEN + UIP_TCPIP_HLEN);
+  asm("bne %g", sendloop1);
+
+  if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
+    return;
+  }
+
+  /* Next, send rest of the packet. */
+  cnt = uip_len - (UIP_LLH_LEN + UIP_TCPIP_HLEN);
+
+  asm("ldx %v", idx);
+
+  asm("lda %v", cnt);
+  asm("lsr");
+  asm("bcc %g", noinc);
+  asm("inc %v", cnt);
+  asm("bne %g", noinc);
+  asm("inc %v+1", cnt);
+noinc:
+
+  asm("lda %v", uip_appdata);
+  asm("sta ptr1");
+  asm("lda %v+1", uip_appdata);
+  asm("sta ptr1+1");  
+
+  asm("ldy #0");
+sendloop2:
+  asm("lda (ptr1),y");
+  asm("sta %v,x", cs8900a_rxtxreg);
+  asm("iny");
+  asm("lda (ptr1),y");
+  asm("sta %v+1,x", cs8900a_rxtxreg);
+  asm("iny");
+  asm("bne %g", check);
+  asm("inc ptr1+1");
+check:
+  asm("cpy %v", cnt);
+  asm("bne %g", sendloop2);
+  asm("dec %v+1", cnt);
+  asm("bpl %g", sendloop2);
+}
+#pragma optimize(pop)
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+static void
+skip_frame(void)
+{
+  asm("ldx %v", idx);
+
+  /* PACKETPP = 0x0102;
+     PPDATA   = PPDATA | 0x0040; */
+  asm("lda #$02");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda %v,x", cs8900a_ppdata);
+  asm("ora #$40");
+  asm("sta %v,x", cs8900a_ppdata);
+}
+#pragma optimize(pop)
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+u16_t
+cs8900a_poll(void)
+{
+  asm("ldx %v", idx);
+  asm("beq %g", bailout);
+
+  /* Check receiver event register to see if there are any valid
+     unicast frames avaliable.  */
+  /* PACKETPP = 0x0124;
+     if(PPDATA & 0x000d == 0x0000) {
+       return 0;
+     }
+  */
+  asm("lda #$24");
+  asm("sta %v,x", cs8900a_packetpp);
+  asm("lda #$01");
+  asm("sta %v+1,x", cs8900a_packetpp);
+  asm("lda %v+1,x", cs8900a_ppdata);
+  asm("and #$0d");
+  asm("cmp #$00");
+  asm("bne %g", noreturn);
+  /* No frame ready. */
+bailout:
+  return 0;
+  
+noreturn:
+  /* Process the incoming frame. */
+  
+  /* Read receiver event and discard it. */
+  /* RXTXREG; */
+  asm("lda %v+1,x", cs8900a_rxtxreg);
+  asm("lda %v,x", cs8900a_rxtxreg);
+  
+  /* Read frame length. */
+  /* cnt = len = RXTXREG; */
+  asm("lda %v+1,x", cs8900a_rxtxreg);
+  asm("sta %v+1", len);
+  asm("sta %v+1", cnt);
+  asm("lda %v,x", cs8900a_rxtxreg);
+  asm("sta %v", len);
+  asm("sta %v", cnt);
+
+  asm("lsr");
+  asm("bcc %g", noinc);
+  asm("inc %v", cnt);
+  asm("bne %g", noinc);
+  asm("inc %v+1", cnt);
+noinc:
+
+  if(cnt > UIP_BUFSIZE) {
+    skip_frame();
+    return 0;
+  }
+
+  /* Read bytes into uip_buf. */
+  asm("ldx %v", idx);
+
+  asm("lda #<%v", uip_buf);
+  asm("sta ptr1");
+  asm("lda #>%v", uip_buf);
+  asm("sta ptr1+1");  
+  
+  asm("ldy #0");
+readloop:
+  asm("lda %v,x", cs8900a_rxtxreg);
+  asm("sta (ptr1),y");
+  asm("iny");
+  asm("lda %v+1,x", cs8900a_rxtxreg);
+  asm("sta (ptr1),y");
+  asm("iny");
+  asm("bne %g", check);
+  asm("inc ptr1+1");
+check:
+  asm("cpy %v", cnt);
+  asm("bne %g", readloop);
+  asm("dec %v+1", cnt);
+  asm("bpl %g", readloop);
+  return len;
+}
+#pragma optimize(pop)
diff --git a/contiki-apple2/uip/cs8900a.h b/contiki-apple2/uip/cs8900a.h
new file mode 100644
index 0000000..2beae51
--- /dev/null
+++ b/contiki-apple2/uip/cs8900a.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cs8900a.h,v 1.2 2005/01/26 21:33:30 oliverschmidt Exp $
+ */
+#ifndef __CS8900A_H__
+#define __CS8900A_H__
+
+#include "uip_arch.h"
+
+void cs8900a_init(void);
+void cs8900a_send(void);
+u16_t cs8900a_poll(void);
+
+#endif /* __CS8900A_H__ */
diff --git a/contiki-apple2/uip/lan91c96.c b/contiki-apple2/uip/lan91c96.c
new file mode 100644
index 0000000..28d1c10
--- /dev/null
+++ b/contiki-apple2/uip/lan91c96.c
@@ -0,0 +1,359 @@
+/*
+ * uIP lan91c96 (smc9194) driver
+ * Based on cs8900a driver, copyrighted (c) 2001, by Adam Dunkels
+ * Copyright (c) 2003, Josef Soucek
+ * 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. 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.
+ *
+ * $Id: lan91c96.c,v 1.6 2005/05/22 14:04:21 oliverschmidt Exp $
+ *
+ */
+
+#include "lan91c96.h"
+#include "uip.h"
+#include "uip_arp.h"
+
+#include <stdio.h>
+
+#define ETHBASE 0xc080
+
+#define ETHBSR     ETHBASE+0x0e	 /* Bank select register             R/W (2B) */
+
+/* Register bank 0 */
+
+#define ETHTCR     ETHBASE       /* Transmition control register     R/W (2B) */
+#define ETHEPHSR   ETHBASE+2     /* EPH status register              R/O (2B) */
+#define ETHRCR     ETHBASE+4     /* Receive control register         R/W (2B) */
+#define ETHECR     ETHBASE+6     /* Counter register                 R/O (2B) */
+#define ETHMIR     ETHBASE+8     /* Memory information register      R/O (2B) */
+#define ETHMCR     ETHBASE+0x0a  /* Memory Config. reg.    +0 R/W +1 R/O (2B) */
+
+/* Register bank 1 */
+
+#define ETHCR      ETHBASE       /* Configuration register           R/W (2B) */
+#define ETHBAR     ETHBASE+2     /* Base address register            R/W (2B) */
+#define ETHIAR     ETHBASE+4     /* Individual address register      R/W (6B) */
+#define ETHGPR     ETHBASE+0x0a  /* General address register         R/W (2B) */
+#define ETHCTR     ETHBASE+0x0c  /* Control register                 R/W (2B) */
+
+/* Register bank 2 */
+
+#define ETHMMUCR   ETHBASE       /* MMU command register             W/O (1B) */
+#define ETHAUTOTX  ETHBASE+1     /* AUTO TX start register           R/W (1B) */
+#define ETHPNR     ETHBASE+2     /* Packet number register           R/W (1B) */
+#define ETHARR     ETHBASE+3     /* Allocation result register       R/O (1B) */
+#define ETHFIFO    ETHBASE+4     /* FIFO ports register              R/O (2B) */
+#define ETHPTR     ETHBASE+6     /* Pointer register                 R/W (2B) */
+#define ETHDATA    ETHBASE+8     /* Data register                    R/W (4B) */
+#define ETHIST     ETHBASE+0x0c  /* Interrupt status register        R/O (1B) */
+#define ETHACK     ETHBASE+0x0c  /* Interrupt acknowledge register   W/O (1B) */
+#define ETHMSK     ETHBASE+0x0d  /* Interrupt mask register          R/W (1B) */
+
+/* Register bank 3 */
+
+#define ETHMT      ETHBASE       /* Multicast table                  R/W (8B) */
+#define ETHMGMT    ETHBASE+8     /* Management interface             R/W (2B) */
+#define ETHREV     ETHBASE+0x0a  /* Revision register                R/W (2B) */
+#define ETHERCV    ETHBASE+0x0c  /* Early RCV register               R/W (2B) */
+
+#define BANK(num) asm("lda #%b", num); asm("sta %w,x", ETHBSR);
+
+extern u8_t lanslot;
+
+static u8_t slot_index;
+static u8_t packet_status;
+static u16_t packet_length;
+
+
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+void lan91c96_init(void)
+{
+  asm("lda %v", lanslot);
+  asm("beq %g", L1);
+  asm("asl");
+  asm("asl");
+  asm("asl");
+  asm("asl");
+  asm("tax");
+
+  /* Check if high byte is 0x33 */
+  asm("lda %w,x", ETHBSR+1);
+  asm("cmp #$33");
+  asm("bne %g", L1);
+  asm("stx %v", slot_index);
+
+  /* Reset ETH card */
+  BANK(0);
+  asm("lda #%%10000000");        /* Software reset */
+  asm("sta %w,x", ETHRCR+1);
+
+  asm("lda #0");
+  asm("sta %w,x", ETHRCR);
+  asm("sta %w,x", ETHRCR+1);
+
+  /* Enable transmit and receive */
+  asm("lda #%%10000001");        /* Enable transmit TXENA, PAD_EN */
+  asm("sta %w,x", ETHTCR);
+  asm("lda #%%00000011");        /* Enable receive, strip CRC ??? */
+  asm("sta %w,x", ETHRCR+1);
+
+  BANK(1);
+  asm("lda %w,x", ETHCR+1);
+  asm("ora #%%00010000");        /* No wait (IOCHRDY) */
+  asm("sta %w,x", ETHCR+1);
+
+  asm("lda #%%00001001");        /* Auto release */
+  asm("sta %w,x", ETHCTR+1);
+  
+  /* Set MAC address */
+  asm("lda %v", uip_ethaddr);
+  asm("sta %w,x", ETHIAR);
+  asm("lda %v+1", uip_ethaddr);
+  asm("sta %w,x", ETHIAR+1);
+  asm("lda %v+2", uip_ethaddr);
+  asm("sta %w,x", ETHIAR+2);
+  asm("lda %v+3", uip_ethaddr);
+  asm("sta %w,x", ETHIAR+3);
+  asm("lda %v+4", uip_ethaddr);
+  asm("sta %w,x", ETHIAR+4);
+  asm("lda %v+5", uip_ethaddr);
+  asm("sta %w,x", ETHIAR+5);
+
+  BANK(2);
+  asm("lda #%%00000000");        /* No interrupts */
+  asm("sta %w,x", ETHMSK);
+L1:
+}
+#pragma optimize(pop)
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+u16_t lan91c96_poll(void)
+{
+  asm("ldx %v", slot_index);
+  asm("beq %g", L0);
+
+  asm("lda %w,x", ETHIST);
+  asm("and #%%00000001");        /* RCV INT */
+  asm("bne %g", L1);
+
+  /* No packet available */
+L0:
+  return 0;
+
+L1:
+  asm("lda #0");
+  asm("sta %w,x", ETHPTR);
+  asm("lda #%%11100000");        /* RCV,AUTO INCR.,READ */
+  asm("sta %w,x", ETHPTR+1);
+
+  asm("lda %w,x", ETHDATA);      /* Status word */
+  asm("lda %w,x", ETHDATA);
+  asm("sta %v", packet_status);  /* High byte only */
+
+  asm("lda %w,x", ETHDATA);      /* Total number of bytes */
+  asm("sta %v", packet_length);
+  asm("lda %w,x", ETHDATA);
+  asm("sta %v+1", packet_length);
+
+  /* Last word contain 'last data byte' and 0x60 */
+  /* or 'fill byte' and 0x40 */
+
+  packet_length -= 6;            /* The packet contains 3 extra words */
+
+  asm("lda %v", packet_status);
+  asm("and #$10");
+  asm("beq %g", L2);
+
+  packet_length++;
+
+L2:
+  if(packet_length > UIP_BUFSIZE) {
+
+    asm("ldx %v", slot_index);
+
+    /* Remove and release RX packet from FIFO */ 
+    asm("lda #%%10000000");
+    asm("sta %w,x", ETHMMUCR);
+    return 0;
+  }
+
+  asm("ldx %v", slot_index);
+
+  asm("lda #<%v", uip_buf);
+  asm("sta ptr1");
+  asm("lda #>%v", uip_buf);
+  asm("sta ptr1+1");
+
+  asm("lda %v+1", packet_length);
+  asm("sta tmp1");
+
+  asm("ldy #0");
+L3:
+  asm("lda %w,x", ETHDATA);
+  asm("sta (ptr1),y");
+  asm("iny");
+  asm("bne %g", L4);
+  asm("inc ptr1+1");
+L4:
+  asm("cpy %v", packet_length);
+  asm("bne %g", L3);
+  asm("dec tmp1");
+  asm("bpl %g", L3);
+
+  /* Remove and release RX packet from FIFO */ 
+  asm("lda #%%10000000");
+  asm("sta %w,x", ETHMMUCR);
+  return packet_length;
+}
+#pragma optimize(pop)
+/*-----------------------------------------------------------------------------------*/
+#pragma optimize(push, off)
+void lan91c96_send(void)
+{
+  /* First 14+40 (IP and TCP header) is send from uip_buf */
+  /* than data from uip_appdata */
+
+  asm("ldx %v", slot_index);
+  asm("beq %g", L0);
+
+  asm("lda %v+1", uip_len);
+  asm("ora #%%00100000");        /* Allocate memory for TX */
+  asm("sta %w,x", ETHMMUCR);
+
+  asm("ldy #8");                 /* Wait... */
+L1:                              /* Wait for allocation ready */
+  asm("lda %w,x", ETHIST);
+  asm("and #%%00001000");        /* ALLOC INT */
+  asm("bne %g", L2);
+  asm("dey");
+  asm("bne %g", L1);
+L0:
+  return;
+
+L2:
+  asm("lda #%%00001000");        /* Acknowledge int, is it necessary ??? */
+  asm("sta %w,x", ETHACK);
+
+  asm("lda %w,x", ETHARR);
+  asm("sta %w,x", ETHPNR);       /* Set packet address */
+
+  asm("lda #0");
+  asm("sta %w,x", ETHPTR);
+  asm("lda #%%01000000");        /* AUTO INCR. */
+  asm("sta %w,x", ETHPTR+1);
+
+  asm("lda #0");                 /* Status written by CSMA */
+  asm("sta %w,x", ETHDATA);
+  asm("sta %w,x", ETHDATA);
+
+  asm("lda %v", uip_len);
+  asm("and #$01");
+  asm("beq %g", L3);
+
+  packet_length = uip_len + 5;
+  asm("jmp %g", L4);
+
+L3:
+  packet_length = uip_len + 6;   /* +6 for status word, length and ctl byte */
+
+L4:
+  asm("ldx %v", slot_index);
+
+  asm("lda %v", packet_length);
+  asm("sta %w,x", ETHDATA);
+  asm("lda %v+1", packet_length);
+  asm("sta %w,x", ETHDATA);
+
+  /* Send 14+40=54 bytes of header */
+
+  if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
+
+    asm("ldx %v", slot_index);
+
+    asm("ldy #0");
+L5:
+    asm("lda %v,y", uip_buf);
+    asm("sta %w,x", ETHDATA);
+    asm("iny");
+    asm("cpy %v", uip_len);
+    asm("bne %g", L5);
+
+  } else {
+
+    asm("ldx %v", slot_index);
+
+    asm("ldy #0");
+L6:
+    asm("lda %v,y", uip_buf);
+    asm("sta %w,x", ETHDATA);
+    asm("iny");
+    asm("cpy #%b", UIP_LLH_LEN + UIP_TCPIP_HLEN);
+    asm("bne %g", L6);
+
+    packet_length = uip_len - (UIP_LLH_LEN + UIP_TCPIP_HLEN);
+
+    asm("ldx %v", slot_index);
+
+    asm("lda %v", uip_appdata);  /* uip_appdata is pointer */
+    asm("sta ptr1");
+    asm("lda %v+1", uip_appdata);
+    asm("sta ptr1+1");
+
+    asm("ldy #0");
+L7:
+    asm("lda (ptr1),y");
+    asm("sta %w,x", ETHDATA);
+    asm("iny");
+    asm("bne %g", L8);
+    asm("inc ptr1+1");
+L8:
+    asm("cpy %v", packet_length);
+    asm("bne %g", L7);
+    asm("dec %v+1", packet_length);
+    asm("bpl %g", L7);
+  }
+
+  asm("lda %v", packet_length);
+  asm("and #$01");
+  asm("beq %g", L9);
+
+  asm("lda #%%00100000");
+  asm("sta %w,x", ETHDATA);      /* Control byte */
+
+  asm("lda #%%11000000");        /* ENQUEUE PACKET - transmit packet */
+  asm("sta %w,x", ETHMMUCR);
+  return;
+
+L9:
+  asm("lda #0");
+  asm("sta %w,x", ETHDATA);      /* Fill byte */
+  asm("sta %w,x", ETHDATA);      /* Control byte */
+
+  asm("lda #%%11000000");        /* ENQUEUE PACKET - transmit packet */
+  asm("sta %w,x", ETHMMUCR);
+}
+#pragma optimize(pop)
diff --git a/contiki-apple2/uip/lan91c96.h b/contiki-apple2/uip/lan91c96.h
new file mode 100644
index 0000000..494653c
--- /dev/null
+++ b/contiki-apple2/uip/lan91c96.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lan91c96.h,v 1.1 2005/03/13 21:33:57 oliverschmidt Exp $
+ */
+
+#ifndef __LAN91C96_H__
+#define __LAN91C96_H__
+
+#include "uip_arch.h"
+
+void lan91c96_init(void);
+void lan91c96_send(void);
+u16_t lan91c96_poll(void);
+
+#endif /* __LAN91C96_H__ */
diff --git a/contiki-apple2/uip/lancegs-drv.c b/contiki-apple2/uip/lancegs-drv.c
new file mode 100644
index 0000000..e25c2d0
--- /dev/null
+++ b/contiki-apple2/uip/lancegs-drv.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2001-2004, 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. 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: lancegs-drv.c,v 1.3 2005/05/13 00:01:56 oliverschmidt Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "packet-service.h"
+
+#include "lan91c96.h"
+
+#include "uip_arp.h"
+
+static void output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen);
+
+/* 00:80:0F is the OUI of Standard Microsystems, A2:A2 just means Apple2 */
+static const struct uip_eth_addr addr =
+  {{0x00,0x80,0x0f,0xa2,0xa2,0x00}};
+
+static const struct packet_service_state state =
+  {
+    PACKET_SERVICE_VERSION,
+    output
+  };
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_POLLHANDLER(pollhandler);
+EK_PROCESS(proc, PACKET_SERVICE_NAME ": LANceGS", EK_PRIO_NORMAL,
+	   eventhandler, pollhandler, (void *)&state);
+
+/*---------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(lancegs_drv_init, arg)
+{
+  arg_free(arg);
+  ek_service_start(PACKET_SERVICE_NAME, &proc);
+}
+/*---------------------------------------------------------------------------*/
+static void
+output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen)
+{
+  uip_arp_out();
+  lan91c96_send();
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  switch(ev) {
+  case EK_EVENT_INIT:
+  case EK_EVENT_REPLACE:
+    /* Don't overwrite LSB */
+    memcpy(&uip_ethaddr, &addr, 5);
+    lan91c96_init();
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    ek_replace((struct ek_proc *)data, NULL);
+    LOADER_UNLOAD();
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    ek_exit();
+    LOADER_UNLOAD();
+    break;
+  default:
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+EK_POLLHANDLER(pollhandler)
+{
+#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+  
+  /* Poll Ethernet device to see if there is a frame avaliable. */
+  uip_len = lan91c96_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);
+      tcpip_input();
+    } 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) {
+        lan91c96_send();
+      }
+    }
+  }
+
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki-apple2/uip/lancegs-dsc.c b/contiki-apple2/uip/lancegs-dsc.c
new file mode 100644
index 0000000..80fa020
--- /dev/null
+++ b/contiki-apple2/uip/lancegs-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: lancegs-dsc.c,v 1.1 2005/05/06 22:34:58 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon lancegs_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(tfe_dsc,
+    "LANceGS driver",
+    "lancegs.drv",
+    lancegs_init,
+    &lancegs_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char lancegsicon_bitmap[3*3*8] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char lancegsicon_textmap[9] = {
+  'L', 'A', 'N',
+  '\\', 'c', 'e',
+  'G', 'S', '/'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon lancegs_icon =
+  {CTK_ICON("LANceGS driver", lancegsicon_bitmap, lancegsicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki-apple2/uip/uther-drv-asm.S b/contiki-apple2/uip/uther-drv-asm.S
new file mode 100644
index 0000000..69ccb8b
--- /dev/null
+++ b/contiki-apple2/uip/uther-drv-asm.S
@@ -0,0 +1,16 @@
+
+;---------------------------------------------------------------------       
+	.export		_cs8900a_rxtxreg
+	.export		_cs8900a_txcmd
+	.export		_cs8900a_txlen
+	.export		_cs8900a_packetpp
+	.export		_cs8900a_ppdata
+	
+
+;---------------------------------------------------------------------
+
+	_cs8900a_rxtxreg	= $c080
+	_cs8900a_txcmd		= $c084
+	_cs8900a_txlen		= $c086
+	_cs8900a_packetpp	= $c08a
+	_cs8900a_ppdata		= $c08c
diff --git a/contiki-apple2/uip/uther-drv.c b/contiki-apple2/uip/uther-drv.c
new file mode 100644
index 0000000..d05e8b5
--- /dev/null
+++ b/contiki-apple2/uip/uther-drv.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2001-2004, 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. 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: uther-drv.c,v 1.2 2005/05/13 00:01:56 oliverschmidt Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "packet-service.h"
+
+#include "cs8900a.h"
+
+#include "uip_arp.h"
+
+static void output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen);
+
+/* 00:0E:3A is the OUI of Cirrus Logic, A2:A2 just means Apple2 */
+static const struct uip_eth_addr addr =
+  {{0x00,0x0e,0x3a,0xa2,0xa2,0x00}};
+
+static const struct packet_service_state state =
+  {
+    PACKET_SERVICE_VERSION,
+    output
+  };
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_POLLHANDLER(pollhandler);
+EK_PROCESS(proc, PACKET_SERVICE_NAME ": Uther", EK_PRIO_NORMAL,
+	   eventhandler, pollhandler, (void *)&state);
+
+/*---------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(uther_drv_init, arg)
+{
+  arg_free(arg);
+  ek_service_start(PACKET_SERVICE_NAME, &proc);
+}
+/*---------------------------------------------------------------------------*/
+static void
+output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen)
+{
+  uip_arp_out();
+  cs8900a_send();
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  switch(ev) {
+  case EK_EVENT_INIT:
+  case EK_EVENT_REPLACE:
+    /* Don't overwrite LSB */
+    memcpy(&uip_ethaddr, &addr, 5);
+    cs8900a_init();
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    ek_replace((struct ek_proc *)data, NULL);
+    LOADER_UNLOAD();
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    ek_exit();
+    LOADER_UNLOAD();
+    break;
+  default:
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+EK_POLLHANDLER(pollhandler)
+{
+#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+  
+  /* 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);
+      tcpip_input();
+    } 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();
+      }
+    }
+  }
+
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki-apple2/uip/uther-dsc.c b/contiki-apple2/uip/uther-dsc.c
new file mode 100644
index 0000000..f088268
--- /dev/null
+++ b/contiki-apple2/uip/uther-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: uther-dsc.c,v 1.1 2005/05/06 22:34:58 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon uther_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(tfe_dsc,
+    "Uther driver",
+    "uther.drv",
+    uther_init,
+    &uther_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char uthericon_bitmap[3*3*8] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char uthericon_textmap[9] = {
+  '/', 'U', '\\',
+  't', 'h', 'e',
+  '\\', 'r', '/'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon uther_icon =
+  {CTK_ICON("Uther driver", uthericon_bitmap, uthericon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/Makefile.common b/contiki/Makefile.common
new file mode 100644
index 0000000..12ca89c
--- /dev/null
+++ b/contiki/Makefile.common
@@ -0,0 +1,27 @@
+UIP=uip.o uip_arch.o uiplib.o resolv.o tcpip.o
+
+DHCP=dhcp.o dhcpc.o
+
+DIRECTORY=directory.o loader-arch-dsc.o
+
+EDITOR=editor.o memb.o ctk-filedialog.o
+
+EMAIL=email.o smtp-socket.o smtp-strings.o ctk-textentry-multiline.o psock.o uipbuf.o memb.o
+
+FTP=ftp.o ftpc.o memb.o
+
+IRC=irc.o ircc.o psock.o uipbuf.o ircc-strings.o ctk-textentry-cmdline.o
+
+SHELL_=shell-gui.o shell.o ctk-textentry-cmdline.o
+
+TELNET=simpletelnet.o telnet.o
+
+TELNETD=telnetd.o shell.o memb.o telnetd-gui.o
+
+VNCVIEWER=vnc.o vnc-viewer.o vnc-draw.o
+
+WEBSERVER=webserver.o httpd.o http-strings.o psock.o uipbuf.o memb.o httpd-fs.o httpd-cgi.o
+
+WGET=wget.o webclient.o http-strings.o http-user-agent-string.o 
+
+WWW=www.o webclient.o http-strings.o http-user-agent-string.o htmlparser.o html-strings.o 
diff --git a/contiki/README b/contiki/README
new file mode 100644
index 0000000..9c71711
--- /dev/null
+++ b/contiki/README
@@ -0,0 +1,31 @@
+Contiki is an open source, highly portable, networked, multi-tasking
+operating system for memory-constrained systems.
+
+Contiki runs on a variety of tiny systems ranging from embedded 8-bit
+microcontrollers to old homecomputers such the Commodore 64. Code
+footprint is on the order of kilobytes and memory usage can be
+configured to be as low as tens of bytes.
+
+Contiki provides a simple event-driven kernel with per-process
+optional preemptive multi-threading, interprocess communication using
+message passing through events, a dynamic process structure with
+support for loading and unloading programs, native TCP/IP support
+using the uIP TCP/IP stack, and a GUI subsystem with either direct
+graphic support for locally connected terminals or networked virtual
+display with VNC or over Telnet.
+
+The Contiki source code is split into the following directories:
+
+  apps/ - Applications
+  conf/ - Example configuration files
+  ctk/  - CTK, the Contiki GUI toolkit
+  doc/  - Files for building documentation from the sources
+  ek/   - Event kernel, multitasking, protothreads
+  lib/  - Libraries 
+  uip/  - The uIP TCP/IP stack
+
+To build a Contiki system, you also need a Contiki port. This contains
+all the architecture specific files needed to build an actual
+system. For most ports, the build procedure is simple: place the
+port's directory in the same directory as the contiki/ directory and
+run "make" (or "gmake" under FreeBSD) in the port's directory.
diff --git a/contiki/apps/FILES b/contiki/apps/FILES
new file mode 100644
index 0000000..167bd5e
--- /dev/null
+++ b/contiki/apps/FILES
@@ -0,0 +1,73 @@
+The contiki/apps/ directory contains source code for a number of
+Contiki application programs.
+
+about*.[ch]
+
+  A program showing an "About Contiki" dialog box.
+
+calc*.[ch]
+
+  A simple desktop calculator.
+
+dhcp.[ch]
+
+  A simple frontend for the DHCP client.
+
+email*.[ch], smtp*.[ch], pop*.[ch]
+
+  An email program with network protocols SMTP and POP3.
+
+ftp*.[ch], ftpc*.[ch]
+
+  An FTP client.
+
+htmlparser.[ch], http-*[ch], webclient.[ch], www.[ch]
+
+  A simple web browser with an HTML parser and an HTTP client
+  implementation.
+
+httpd*.[ch], webserver.[ch]
+
+  A simple web server (HTTP server implementation).
+
+irc*.[ch], ircc*.[ch]
+
+  An IRC client.
+
+netconf*.[ch]
+
+  A program for changing network settings.
+
+processes*.[ch]
+
+  A program that shows currently running processes.
+
+shell*.[ch]
+
+  A command shell
+
+telnet*.[ch]
+
+  A simple telnet-like program
+
+telnetd*.[ch]
+
+  A telnet server.
+
+vnc*.[ch]
+
+  A VNC client.  
+  
+makestrings
+
+  Creates .c and .h files from the -strings files.
+
+httpd-fs/
+
+  Directory containing static files for the web server.  
+  
+makefsdata
+
+  Creates the httpd-fsdata.c file from the httpd-fs/ directory
+             
+  
\ No newline at end of file
diff --git a/contiki/apps/about-dsc.c b/contiki/apps/about-dsc.c
new file mode 100644
index 0000000..c47c921
--- /dev/null
+++ b/contiki/apps/about-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: about-dsc.c,v 1.6 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon about_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(about_dsc,
+    "About Contiki",
+    "about.prg",
+    about_init,
+    &about_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char abouticon_textmap[9] = {
+  ' ', ' ', 'c',
+  ' ', '?', ' ',
+  '.', ' ', ' '
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon about_icon =
+  {CTK_ICON("About Contiki", abouticon_bitmap, abouticon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/about-dsc.h b/contiki/apps/about-dsc.h
new file mode 100644
index 0000000..6b405c8
--- /dev/null
+++ b/contiki/apps/about-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: about-dsc.h,v 1.1 2003/04/17 19:00:00 adamdunkels Exp $
+ *
+ */
+#ifndef __ABOUT_DSC_H__
+#define __ABOUT_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(about_dsc);
+
+#endif /* __ABOUT_DSC_H__ */
diff --git a/contiki/apps/about.c b/contiki/apps/about.c
new file mode 100644
index 0000000..283464c
--- /dev/null
+++ b/contiki/apps/about.c
@@ -0,0 +1,145 @@
+/*
+ * 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. 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: about.c,v 1.14 2004/09/12 17:52:58 adamdunkels Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "ek.h"
+#include "ctk.h"
+#include "ctk-draw.h"
+
+#include "petsciiconv.h"
+
+#include "loader.h"
+
+static struct ctk_window aboutdialog;
+static struct ctk_label aboutlabel1 =
+  {CTK_LABEL(2, 0, 28, 1, "The Contiki Operating System")};
+static struct ctk_label aboutlabel2 =
+  {CTK_LABEL(3, 2, 28, 1, "A modern, Internet-enabled")};
+static struct ctk_label aboutlabel3 =
+  {CTK_LABEL(6, 3, 20, 1, "operating system and")};
+static struct ctk_label aboutlabel4 =
+  {CTK_LABEL(6, 4, 20, 1, "desktop environment.")};
+
+static char abouturl_petscii[] = "http://www.sics.se/~adam/contiki/";
+static char abouturl_ascii[40];
+static struct ctk_hyperlink abouturl = 
+  {CTK_HYPERLINK(0, 6, 32, "http://www.sics.se/~adam/contiki/",
+		 abouturl_ascii)};
+static struct ctk_button aboutclose =
+  {CTK_BUTTON(12, 8, 5, "Close")};
+
+EK_EVENTHANDLER(about_eventhandler, ev, data);
+
+EK_PROCESS(p, "About Contiki", EK_PRIO_NORMAL, about_eventhandler, NULL, NULL);
+/*static DISPATCHER_SIGHANDLER(about_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("About Contiki", NULL, about_sighandler, NULL)};
+  static ek_id_t id;*/
+static ek_id_t id = EK_ID_NONE;
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(about_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    /*    id = dispatcher_start(&p); */
+    id = ek_start(&p);
+  }
+  /*  ctk_desktop_redraw(aboutdialog.desktop);*/
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+about_quit(void)
+{
+  ctk_dialog_close();
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+/*static DISPATCHER_SIGHANDLER(about_sighandler, s, data)*/
+EK_EVENTHANDLER(about_eventhandler, ev, data)
+{
+  unsigned char width;
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    width = ctk_desktop_width(NULL);
+    
+    strcpy(abouturl_ascii, abouturl_petscii);
+    petsciiconv_toascii(abouturl_ascii, sizeof(abouturl_ascii));
+
+    if(width > 34) {
+      ctk_dialog_new(&aboutdialog, 32, 9);
+    } else {
+      ctk_dialog_new(&aboutdialog, width - 2, 9);
+    }
+    CTK_WIDGET_ADD(&aboutdialog, &aboutlabel1);
+    CTK_WIDGET_ADD(&aboutdialog, &aboutlabel2);
+    CTK_WIDGET_ADD(&aboutdialog, &aboutlabel3);
+    CTK_WIDGET_ADD(&aboutdialog, &aboutlabel4);
+    if(width > 34) {
+      CTK_WIDGET_ADD(&aboutdialog, &abouturl);
+      CTK_WIDGET_SET_FLAG(&abouturl, CTK_WIDGET_FLAG_MONOSPACE);
+    } else {
+      CTK_WIDGET_SET_XPOS(&aboutlabel1, 0);
+      CTK_WIDGET_SET_XPOS(&aboutlabel2, 0);
+      CTK_WIDGET_SET_XPOS(&aboutlabel3, 0);
+      CTK_WIDGET_SET_XPOS(&aboutlabel4, 0);
+      
+      CTK_WIDGET_SET_XPOS(&aboutclose, 0);
+    }
+    CTK_WIDGET_ADD(&aboutdialog, &aboutclose);
+    CTK_WIDGET_FOCUS(&aboutdialog, &aboutclose);
+    
+    /*    dispatcher_listen(ctk_signal_button_activate);
+	  dispatcher_listen(ctk_signal_hyperlink_activate);*/
+    ctk_dialog_open(&aboutdialog);
+    
+  } else if(ev == EK_EVENT_REQUEST_EXIT) {
+    about_quit();
+  } else if(ev == ctk_signal_button_activate) {
+    if(data == (ek_data_t)&aboutclose) {
+      about_quit();
+    }
+  } else if(ev == ctk_signal_hyperlink_activate) {
+    if((struct ctk_widget *)data == (struct ctk_widget *)&abouturl) {
+      about_quit();
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/calc-dsc.c b/contiki/apps/calc-dsc.c
new file mode 100644
index 0000000..aedec22
--- /dev/null
+++ b/contiki/apps/calc-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: calc-dsc.c,v 1.3 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon calc_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(calc_dsc,
+    "Simple calculator",
+    "calc.prg",
+    calc_init,
+    &calc_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char calcicon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char calcicon_textmap[9] = {
+  '+', ' ', '-',
+  ' ', '*', ' ',
+  '=', ' ', '/'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon calc_icon =
+  {CTK_ICON("Calculator", calcicon_bitmap, calcicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/calc-dsc.h b/contiki/apps/calc-dsc.h
new file mode 100644
index 0000000..db821ee
--- /dev/null
+++ b/contiki/apps/calc-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: calc-dsc.h,v 1.1 2003/05/29 19:15:37 adamdunkels Exp $
+ *
+ */
+#ifndef __CALC_DSC_H__
+#define __CALC_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(calc_dsc);
+
+#endif /* __CALC_DSC_H__ */
diff --git a/contiki/apps/calc.c b/contiki/apps/calc.c
new file mode 100644
index 0000000..603e610
--- /dev/null
+++ b/contiki/apps/calc.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2003, 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. 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 an example program for the Contiki desktop OS
+ *
+ * $Id: calc.c,v 1.8 2005/02/07 23:13:00 oliverschmidt Exp $
+ *
+ */
+
+/* This is an example of how to write programs for Contiki. It
+   displays a window with the famous message "Hello world" and two
+   buttons; one which changes the message slightly and one which quits
+   the application. */
+
+#include "ek.h"
+#include "ctk.h"
+#include "loader.h"
+
+static struct ctk_window window;
+
+static char input[16];
+static struct ctk_label inputlabel =
+  {CTK_LABEL(0, 0, 12, 1, input)};
+
+static struct ctk_button button7 =
+  {CTK_BUTTON(0, 3, 1, "7")};
+static struct ctk_button button8 =
+  {CTK_BUTTON(3, 3, 1, "8")};
+static struct ctk_button button9 =
+  {CTK_BUTTON(6, 3, 1, "9")};
+static struct ctk_button button4 =
+  {CTK_BUTTON(0, 4, 1, "4")};
+static struct ctk_button button5 =
+  {CTK_BUTTON(3, 4, 1, "5")};
+static struct ctk_button button6 =
+  {CTK_BUTTON(6, 4, 1, "6")};
+static struct ctk_button button1 =
+  {CTK_BUTTON(0, 5, 1, "1")};
+static struct ctk_button button2 =
+  {CTK_BUTTON(3, 5, 1, "2")};
+static struct ctk_button button3 =
+  {CTK_BUTTON(6, 5, 1, "3")};
+static struct ctk_button button0 =
+  {CTK_BUTTON(0, 6, 3, " 0 ")};
+
+static struct ctk_button cbutton =
+  {CTK_BUTTON(0, 2, 1, "C")};
+
+static struct ctk_button divbutton =
+  {CTK_BUTTON(9, 2, 1, "/")};
+static struct ctk_button mulbutton =
+  {CTK_BUTTON(9, 3, 1, "*")};
+
+static struct ctk_button subbutton =
+  {CTK_BUTTON(9, 4, 1, "-")};
+static struct ctk_button addbutton =
+  {CTK_BUTTON(9, 5, 1, "+")};
+static struct ctk_button calcbutton =
+  {CTK_BUTTON(9, 6, 1, "=")};
+
+EK_EVENTHANDLER(calc_eventhandler, ev, data);
+EK_PROCESS(p, "Calculator", EK_PRIO_NORMAL,
+	   calc_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*
+static DISPATCHER_SIGHANDLER(calc_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Calculator", NULL, calc_sighandler, NULL)};
+static ek_id_t id;
+*/
+
+static unsigned long operand1, operand2;
+static unsigned char op;
+#define OP_ADD 1
+#define OP_SUB 2
+#define OP_MUL 3
+#define OP_DIV 4
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(calc_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }    
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+calc_quit(void)
+{
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+add_to_input(char c)
+{
+  unsigned char i;
+    
+  for(i = 0; i < 11; ++i) {
+    input[i] = input[i + 1];
+  }
+  input[11] = c;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+clear_input(void)
+{
+  unsigned char i;
+  
+  for(i = 0; i < sizeof(input); ++i) {
+    input[i] = ' ';
+  }      
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+input_to_operand1(void)
+{
+  unsigned int m;
+  unsigned char i;
+
+  operand1 = 0;
+  for(m = 1, i = 11;
+      i > 7; --i, m *= 10) {
+    if(input[i] >= '0' &&
+       input[i] <= '9') {
+      operand1 += (input[i] - '0') * m;
+    }
+  }
+  clear_input();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+operand2_to_input(void)
+{
+  unsigned char i;
+  
+  input[7] = (operand2/10000) % 10 + '0';
+  input[8] = (operand2/1000) % 10 + '0';
+  input[9] = (operand2/100) % 10 + '0';
+  input[10] = (operand2/10) % 10 + '0';
+  input[11] = operand2 % 10 + '0';
+
+  for(i = 0; i < 4; ++i) {
+    if(input[7 + i] == '0') {
+      input[7 + i] = ' ';
+    } else {
+      break;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+calculate(void)
+{
+  operand2 = operand1;
+  input_to_operand1();
+  switch(op) {
+  case OP_ADD:
+    operand2 = operand2 + operand1;
+    break;
+  case OP_SUB:
+    operand2 = operand2 - operand1;
+    break;
+  case OP_MUL:
+    operand2 = operand2 * operand1;
+    break;
+  case OP_DIV:
+    operand2 = operand2 / operand1;
+    break;
+  }
+  operand2_to_input();      
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(calc_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&window, 12, 7, "Calc");
+
+    CTK_WIDGET_ADD(&window, &inputlabel);
+    CTK_WIDGET_SET_FLAG(&inputlabel, CTK_WIDGET_FLAG_MONOSPACE);
+
+    CTK_WIDGET_ADD(&window, &cbutton);
+    
+    CTK_WIDGET_ADD(&window, &divbutton);
+	    
+    CTK_WIDGET_ADD(&window, &button7);
+    CTK_WIDGET_ADD(&window, &button8);
+    CTK_WIDGET_ADD(&window, &button9);
+
+    CTK_WIDGET_ADD(&window, &mulbutton);
+
+   
+
+    CTK_WIDGET_ADD(&window, &button4);
+    CTK_WIDGET_ADD(&window, &button5);
+    CTK_WIDGET_ADD(&window, &button6);
+
+    CTK_WIDGET_ADD(&window, &subbutton);
+
+    CTK_WIDGET_ADD(&window, &button1);
+    CTK_WIDGET_ADD(&window, &button2);
+    CTK_WIDGET_ADD(&window, &button3);
+    
+    CTK_WIDGET_ADD(&window, &addbutton);
+    
+    CTK_WIDGET_ADD(&window, &button0);
+
+    CTK_WIDGET_ADD(&window, &calcbutton);
+	
+    clear_input();
+    
+    ctk_window_open(&window);
+
+  } else if(ev == ctk_signal_keypress) {
+    if((char)data >= '0' &&
+       (char)data <= '9') {
+      add_to_input((char)data);
+    } else if((char)data == ' ') {
+      clear_input();
+    } else if((char)data == '+') {
+      input_to_operand1();
+      op = OP_ADD;
+    } else if((char)data == '-') {
+      input_to_operand1();
+      op = OP_SUB;
+    } else if((char)data == '*') {
+      input_to_operand1();
+      op = OP_MUL;
+    } else if((char)data == '/') {
+      input_to_operand1();
+      op = OP_DIV;
+    } else if((char)data == '=' ||
+	      (char)data == CH_ENTER) {
+      calculate();
+    }
+
+    CTK_WIDGET_REDRAW(&inputlabel);
+  } else if(ev == ctk_signal_button_activate) {
+    if(data == (ek_data_t)&button0) {
+      add_to_input('0');
+    } else if(data == (ek_data_t)&button1) {
+      add_to_input('1');
+    } else if(data == (ek_data_t)&button2) {
+      add_to_input('2');
+    } else if(data == (ek_data_t)&button3) {
+      add_to_input('3');
+    } else if(data == (ek_data_t)&button4) {
+      add_to_input('4');
+    } else if(data == (ek_data_t)&button5) {
+      add_to_input('5');
+    } else if(data == (ek_data_t)&button6) {
+      add_to_input('6');
+    } else if(data == (ek_data_t)&button7) {
+      add_to_input('7');
+    } else if(data == (ek_data_t)&button8) {
+      add_to_input('8');
+    } else if(data == (ek_data_t)&button9) {
+      add_to_input('9');
+    } else if(data == (ek_data_t)&cbutton) {
+      clear_input();
+    } else if(data == (ek_data_t)&calcbutton) {
+      calculate();
+    } else if(data == (ek_data_t)&addbutton) {
+      input_to_operand1();
+      op = OP_ADD;
+    } else if(data == (ek_data_t)&subbutton) {
+      input_to_operand1();
+      op = OP_SUB;
+    } else if(data == (ek_data_t)&mulbutton) {
+      input_to_operand1();
+      op = OP_MUL;
+    } else if(data == (ek_data_t)&divbutton) {
+      input_to_operand1();
+      op = OP_DIV;
+    }
+    CTK_WIDGET_REDRAW(&inputlabel);
+  } else if(ev == ctk_signal_window_close &&
+	    data == (ek_data_t)&window) {
+    calc_quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/dhcp-dsc.c b/contiki/apps/dhcp-dsc.c
new file mode 100644
index 0000000..a9bd423
--- /dev/null
+++ b/contiki/apps/dhcp-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: dhcp-dsc.c,v 1.2 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon dhcp_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(dhcp_dsc,
+    "Obtain IP address automatically",
+    "dhcp.prg",
+    dhcp_init,
+    &dhcp_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char tcpipconficon_textmap[9] = {
+  'T', 'C', 'P',
+  '/', 'I', 'P',
+  'C', 'f', 'g'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon dhcp_icon =
+  {CTK_ICON("DHCP client", tcpipconficon_bitmap, tcpipconficon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/dhcp-dsc.h b/contiki/apps/dhcp-dsc.h
new file mode 100644
index 0000000..b7e39f9
--- /dev/null
+++ b/contiki/apps/dhcp-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: dhcp-dsc.h,v 1.1 2004/09/17 20:42:08 adamdunkels Exp $
+ *
+ */
+#ifndef __DHCP_DSC_H__
+#define __DHCP_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(dhcp_dsc);
+
+#endif /* __DHCP_DSC_H__ */
diff --git a/contiki/apps/dhcp.c b/contiki/apps/dhcp.c
new file mode 100644
index 0000000..8d5617a
--- /dev/null
+++ b/contiki/apps/dhcp.c
@@ -0,0 +1,150 @@
+#include "contiki.h"
+#include "ctk.h"
+#include "dhcpc.h"
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "DHCP", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static struct ctk_window window;
+static struct ctk_button getbutton =
+  {CTK_BUTTON(0, 0, 16, "Request address")};
+static struct ctk_label statuslabel =
+  {CTK_LABEL(0, 1, 16, 1, "")};
+
+
+static struct ctk_label ipaddrlabel =
+  {CTK_LABEL(0, 3, 10, 1, "IP address")};
+static char ipaddr[17];
+static struct ctk_textentry ipaddrentry =
+  {CTK_LABEL(11, 3, 16, 1, ipaddr)};
+static struct ctk_label netmasklabel =
+  {CTK_LABEL(0, 4, 10, 1, "Netmask")};
+static char netmask[17];
+static struct ctk_textentry netmaskentry =
+  {CTK_LABEL(11, 4, 16, 1, netmask)};
+static struct ctk_label gatewaylabel =
+  {CTK_LABEL(0, 5, 10, 1, "Gateway")};
+static char gateway[17];
+static struct ctk_textentry gatewayentry =
+  {CTK_LABEL(11, 5, 16, 1, gateway)};
+static struct ctk_label dnsserverlabel =
+  {CTK_LABEL(0, 6, 10, 1, "DNS server")};
+static char dnsserver[17];
+static struct ctk_textentry dnsserverentry =
+  {CTK_LABEL(11, 6, 16, 1, dnsserver)};
+
+enum {
+  SHOWCONFIG
+};
+/*---------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(dhcp_init, arg)
+{
+  arg_free(arg);
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+set_statustext(char *text)
+{
+  ctk_label_set_text(&statuslabel, text);
+  CTK_WIDGET_REDRAW(&statuslabel);
+}
+/*---------------------------------------------------------------------------*/
+static char *
+makebyte(u8_t byte, char *str)
+{
+  if(byte >= 100) {
+    *str++ = (byte / 100 ) % 10 + '0';
+  }
+  if(byte >= 10) {
+    *str++ = (byte / 10) % 10 + '0';
+  }
+  *str++ = (byte % 10) + '0';
+
+  return str;
+}
+/*---------------------------------------------------------------------------*/
+static void
+makeaddr(u16_t *addr, char *str)
+{
+  str = makebyte(HTONS(addr[0]) >> 8, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[0]) & 0xff, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[1]) >> 8, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[1]) & 0xff, str);
+  *str++ = 0;
+}
+/*---------------------------------------------------------------------------*/
+static void
+makestrings(void)
+{
+  u16_t addr[2], *addrptr;
+
+  uip_gethostaddr(addr);
+  makeaddr(addr, ipaddr);
+  
+  uip_getnetmask(addr);
+  makeaddr(addr, netmask);
+  
+  uip_getdraddr(addr);
+  makeaddr(addr, gateway);
+
+  addrptr = resolv_getserver();
+  if(addrptr != NULL) {
+    makeaddr(addrptr, dnsserver);
+  }
+ 
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&window, 28, 7, "DHCP");
+
+    CTK_WIDGET_ADD(&window, &getbutton);
+    CTK_WIDGET_ADD(&window, &statuslabel);
+    CTK_WIDGET_ADD(&window, &ipaddrlabel);
+    CTK_WIDGET_ADD(&window, &ipaddrentry);
+    CTK_WIDGET_ADD(&window, &netmasklabel);
+    CTK_WIDGET_ADD(&window, &netmaskentry);
+    CTK_WIDGET_ADD(&window, &gatewaylabel);
+    CTK_WIDGET_ADD(&window, &gatewayentry);
+    CTK_WIDGET_ADD(&window, &dnsserverlabel);
+    CTK_WIDGET_ADD(&window, &dnsserverentry);
+    
+    CTK_WIDGET_FOCUS(&window, &getbutton);
+
+    ctk_window_open(&window);
+    dhcpc_init();
+  } else if(ev == ctk_signal_widget_activate) {
+    if(data == (ek_data_t)&getbutton) {
+      dhcpc_request();
+      set_statustext("Requesting...");
+    }
+  } else if(ev == tcpip_event) {
+    dhcpc_appcall(data);
+  } else if(ev == EK_EVENT_REQUEST_EXIT ||
+	    ev == ctk_signal_window_close) {
+    ctk_window_close(&window);
+    ek_exit();
+    id = EK_ID_NONE;
+    LOADER_UNLOAD();
+  } else if(ev == SHOWCONFIG) {
+    makestrings();
+    ctk_window_redraw(&window);  
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+dhcpc_configured(void)
+{
+  set_statustext("Configured.");
+  ek_post(EK_PROC_ID(EK_CURRENT()), SHOWCONFIG, NULL);
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/dhcp.h b/contiki/apps/dhcp.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contiki/apps/dhcp.h
diff --git a/contiki/apps/directory-dsc.c b/contiki/apps/directory-dsc.c
new file mode 100644
index 0000000..eaf4382
--- /dev/null
+++ b/contiki/apps/directory-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: directory-dsc.c,v 1.1 2005/04/18 23:17:55 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon directory_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(directory_dsc,
+    "Directory reader",
+    "directory.prg",
+    directory_init,
+    &directory_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char directoryicon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char directoryicon_textmap[9] = {
+  '+', '-', '+',
+  '|', 'o', '|',
+  '+', '-', '+'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon directory_icon =
+  {CTK_ICON("Directory", directoryicon_bitmap, directoryicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/directory-dsc.h b/contiki/apps/directory-dsc.h
new file mode 100644
index 0000000..9875d26
--- /dev/null
+++ b/contiki/apps/directory-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: directory-dsc.h,v 1.1 2005/04/18 23:17:55 oliverschmidt Exp $
+ *
+ */
+#ifndef __DIRECTORY_DSC_H__
+#define __DIRECTORY_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(directory_dsc);
+
+#endif /* __DIRECTORY_DSC_H__ */
diff --git a/contiki/apps/directory.c b/contiki/apps/directory.c
new file mode 100644
index 0000000..62b4f25
--- /dev/null
+++ b/contiki/apps/directory.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2003, 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. 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: directory.c,v 1.3 2006/05/24 19:34:39 oliverschmidt Exp $
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ek.h"
+#include "loader.h"
+
+#include "cfs.h"
+
+#include "program-handler.h"
+
+#define FILENAMELEN 24
+#define MAX_NUMFILES 40
+#define WIDTH 36
+#define HEIGHT 22
+
+static char (filenames[FILENAMELEN + 1])[MAX_NUMFILES];
+static struct dsc *dscs[MAX_NUMFILES];
+static unsigned char numfiles, morestart, filenameptr;
+
+static struct ctk_window window;
+
+static struct ctk_label description =
+  {CTK_LABEL(0, HEIGHT - 1, WIDTH, 1, "")};
+
+static char autoexit = 1;
+static struct ctk_button autoexitbutton =
+  {CTK_BUTTON(WIDTH/2 - 9, 20, 9, "Auto-exit")};
+static char autoexiton[] = "is On ";
+static char autoexitoff[] = "is Off";
+static struct ctk_label autoexitlabel =
+  {CTK_LABEL(WIDTH/2 - 9 + 12, 20, 6, 1, autoexiton)};
+
+static struct ctk_button morebutton =
+  {CTK_BUTTON(0, 20, 4, "More")};
+
+static struct ctk_button backbutton =
+  {CTK_BUTTON(0, 20, 4, "Back")};
+
+static struct ctk_button reloadbutton =
+  {CTK_BUTTON(30, 20, 6, "Reload")};
+
+EK_EVENTHANDLER(directory_eventhandler, ev, data);
+EK_PROCESS(p, "Directory browser", EK_PRIO_NORMAL,
+	   directory_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static unsigned char width, height;
+
+#define LOADING_DIR 1
+#define LOADING_DSC 2
+static char loading = 0;
+static struct cfs_dir dir;
+/*-----------------------------------------------------------------------------------*/
+static void
+show_statustext(char *text)
+{
+  ctk_label_set_text(&description, text);
+  CTK_WIDGET_REDRAW(&description);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+startloading(void)
+{
+  if(cfs_opendir(&dir, "/") != 0) {
+    show_statustext("Cannot open directory");
+    loading = 0;
+  } else {
+    loading = LOADING_DIR;
+    ek_post(id, EK_EVENT_CONTINUE, NULL);
+    numfiles = 0;
+  }
+}    
+/*-----------------------------------------------------------------------------------*/
+static void
+makewindow(unsigned char i)
+{
+  unsigned char x, y;
+
+  ctk_window_clear(&window);
+  CTK_WIDGET_SET_YPOS(&description, height - 3);
+  CTK_WIDGET_SET_WIDTH(&description, width);
+  CTK_WIDGET_ADD(&window, &description);
+
+  morestart = i;
+  
+  x = 0; y = 1;
+  for(; dscs[i] != NULL; ++i) {
+
+    if(x + strlen(dscs[i]->icon->title) >= width) {
+      y += 5;
+      x = 0;
+      if(y >= height - 2 - 4) {
+	morestart = i;
+	break;
+      }
+    }
+    CTK_WIDGET_SET_XPOS(dscs[i]->icon, x);
+    CTK_WIDGET_SET_YPOS(dscs[i]->icon, y);
+    CTK_WIDGET_ADD(&window, dscs[i]->icon);
+
+    x += strlen(dscs[i]->icon->title) + 2;
+  }
+  CTK_WIDGET_SET_YPOS(&autoexitbutton, height - 2);
+  CTK_WIDGET_ADD(&window, &autoexitbutton);
+  CTK_WIDGET_SET_YPOS(&autoexitlabel, height - 2);
+  CTK_WIDGET_ADD(&window, &autoexitlabel);
+  CTK_WIDGET_FOCUS(&window, &autoexitbutton);
+
+  if(i != morestart) {
+    CTK_WIDGET_SET_YPOS(&backbutton, height - 1);
+    CTK_WIDGET_ADD(&window, &backbutton);
+  } else {
+    CTK_WIDGET_SET_YPOS(&morebutton, height - 1);
+    CTK_WIDGET_ADD(&window, &morebutton);
+  }
+  CTK_WIDGET_SET_XPOS(&reloadbutton, width - 8);
+  CTK_WIDGET_SET_YPOS(&reloadbutton, height - 1);
+  CTK_WIDGET_ADD(&window, &reloadbutton);    
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(directory_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+
+    width = ctk_draw_width() - 2;
+    height = ctk_draw_height() - 3;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+quit(void)
+{
+  unsigned char i;
+
+  if(loading == LOADING_DIR) {
+    cfs_closedir(&dir);
+  }
+  ctk_window_close(&window);
+  for(i = 0; dscs[i] != NULL; ++i) {
+    LOADER_UNLOAD_DSC(dscs[i]);
+  }
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+read_dirent(void)
+{
+  static struct cfs_dirent dirent;
+  static char message[40];
+    
+  if(loading == LOADING_DIR) {
+    if(cfs_readdir(&dir, &dirent)) {
+      cfs_closedir(&dir);
+      loading = LOADING_DSC;
+      filenameptr = 0;
+    } else if(strcasecmp(&dirent.name[strlen(dirent.name) - 4], ".dsc") == 0) {
+      strncpy(filenames[numfiles], dirent.name, FILENAMELEN);
+      ++numfiles;
+      if(numfiles == MAX_NUMFILES) {
+	cfs_closedir(&dir);	
+	loading = LOADING_DSC;
+	filenameptr = 0;
+	return;
+      }      
+      strcpy(message, "Found \"");
+      strcpy(message + 7, dirent.name);
+      strcpy(message + 7 + strlen(dirent.name), "\"...");
+      show_statustext(message);
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+load_dirent(void)
+{
+  static char message[40];
+  char *name;
+    
+  if(loading == LOADING_DSC) {
+
+    name = filenames[filenameptr];
+    dscs[filenameptr] = LOADER_LOAD_DSC(name);
+    if(dscs[filenameptr] == NULL || filenameptr + 1 >= numfiles) {
+      loading = 0;
+      makewindow(0);
+      show_statustext("Directory loaded");
+      ctk_window_redraw(&window);
+      return;
+    }
+    ++filenameptr;
+    strcpy(message, "Loading \"");
+    strcpy(message + 9, name);
+    strcpy(message + 9 + strlen(name), "\"...");
+    show_statustext(message);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(directory_eventhandler, ev, data)
+{
+  unsigned char i;
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&window, width, height, "Directory");
+
+    /*    loaddirectory();*/
+    makewindow(0);
+    show_statustext("Loading directory...");
+    startloading();
+    
+    ctk_window_open(&window);
+
+  } else if(ev == EK_EVENT_CONTINUE) {
+    read_dirent();
+    load_dirent();
+    if(loading != 0) {
+      ek_post(id, EK_EVENT_CONTINUE, NULL);
+    }
+  } else if(ev == ctk_signal_widget_activate) {
+    if(data == (ek_data_t)&reloadbutton) {
+      for(i = 0; dscs[i] != NULL; ++i) {
+	LOADER_UNLOAD_DSC(dscs[i]);
+	dscs[i] = NULL;
+      }     
+      /*      loaddirectory();*/
+      startloading();
+      makewindow(0);
+      ctk_window_open(&window);
+    } else if(data == (ek_data_t)&morebutton) {
+      makewindow(morestart);
+      ctk_window_open(&window);
+    } else if(data == (ek_data_t)&backbutton) {
+      makewindow(0);
+      ctk_window_open(&window);
+    } else if(data == (ek_data_t)&autoexitbutton) {
+      autoexit = 1 - autoexit;
+      if(autoexit == 1) {
+	ctk_label_set_text(&autoexitlabel, autoexiton);
+      } else {
+	ctk_label_set_text(&autoexitlabel, autoexitoff);
+      }
+      CTK_WIDGET_REDRAW(&autoexitlabel);
+    } else {
+      for(i = 0; dscs[i] != NULL; ++i) {
+	if(data == (ek_data_t)(dscs[i]->icon)) {
+	  program_handler_load(dscs[i]->prgname, NULL);
+	  if(autoexit) {
+	    ctk_window_close(&window);
+	    quit();
+	  }
+	  break;
+	}
+      }
+    }
+  } else if(ev == ctk_signal_widget_select) {
+    if(data == (ek_data_t)&reloadbutton) {
+      show_statustext("Reload directory");
+    } else if(data == (ek_data_t)&morebutton) {
+      show_statustext("Show more files");
+    } else if(data == (ek_data_t)&backbutton) {
+      show_statustext("Show first files");
+    } else if(data == (ek_data_t)&autoexitbutton) {
+      show_statustext("Exit when loading program");
+    } else {
+      for(i = 0; dscs[i] != NULL; ++i) {
+	if(data == (ek_data_t)(dscs[i]->icon)) {
+	  show_statustext(dscs[i]->description);
+	  break;
+	}
+      }
+    }
+  } else if(ev == ctk_signal_window_close &&
+	    data == (ek_data_t)&window) {
+    quit();
+  } else if(ev == EK_EVENT_REQUEST_EXIT) {
+    ctk_window_close(&window);
+    quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/editor-dsc.c b/contiki/apps/editor-dsc.c
new file mode 100644
index 0000000..1865a85
--- /dev/null
+++ b/contiki/apps/editor-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2004, 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. 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: editor-dsc.c,v 1.3 2005/04/19 22:00:53 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon editor_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(editor_dsc,
+    "A simple text editor",
+    "editor.prg",
+    editor_init,
+    &editor_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char editoricon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char editoricon_textmap[9] = {
+  't', 'x', 't',
+  'e', 'd', 'i',
+  't', 'o', 'r'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon editor_icon =
+  {CTK_ICON("Editor", editoricon_bitmap, editoricon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/editor-dsc.h b/contiki/apps/editor-dsc.h
new file mode 100644
index 0000000..6ab77c8
--- /dev/null
+++ b/contiki/apps/editor-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004, 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. 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: editor-dsc.h,v 1.1 2004/08/09 20:08:10 adamdunkels Exp $
+ *
+ */
+#ifndef __EDITOR_DSC_H__
+#define __EDITOR_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(editor_dsc);
+
+#endif /* __EDITOR_DSC_H__ */
diff --git a/contiki/apps/editor.c b/contiki/apps/editor.c
new file mode 100644
index 0000000..35defb1
--- /dev/null
+++ b/contiki/apps/editor.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: editor.c,v 1.4 2005/04/24 13:37:42 oliverschmidt Exp $
+ */
+#define EDITOR_CONF_WIDTH 32
+#define EDITOR_CONF_HEIGHT 16
+#define EDITOR_CONF_MAX_FILENAME_LEN 16
+
+#include "contiki.h"
+#include "ctk.h"
+#include "cfs.h"
+
+#include "ctk-filedialog.h"
+
+#define ISO_nl 0x0a
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "Editor", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static struct ctk_window window;
+
+#define LINE_LEN 60
+#define NUM_LINES EDITOR_CONF_HEIGHT
+
+struct line {
+  struct line *next, *prev;
+  char text[LINE_LEN];
+};
+MEMB(linesmem, sizeof(struct line), NUM_LINES);
+
+static struct line *lines;
+
+static struct {
+  unsigned char x, y;
+  struct ctk_label labels[NUM_LINES];
+
+} editor_state;
+
+static struct ctk_button openbutton =
+  {CTK_BUTTON(0, 0, 4, "Open")};
+static char statustext[EDITOR_CONF_WIDTH + 1];
+static struct ctk_label statuslabel =
+  {CTK_LABEL(0, EDITOR_CONF_HEIGHT + 2, EDITOR_CONF_WIDTH, 1, statustext)};
+
+static struct ctk_menu menu;
+static unsigned char menuitem_new, menuitem_open, menuitem_save;
+
+static char filename[EDITOR_CONF_MAX_FILENAME_LEN];
+
+
+static struct ctk_filedialog_state filedialog;
+
+enum {
+  OPEN_EVENT
+};
+
+/*---------------------------------------------------------------------------*/
+static void
+show_statustext(char *text1, char *text2)
+{
+  int len;
+
+  len = strlen(text1);
+  if(len < sizeof(statustext)) {
+    strncpy(statustext, text1, sizeof(statustext));
+    strncpy(statustext + len, text2, sizeof(statustext) - len);
+    CTK_WIDGET_REDRAW(&statuslabel);
+  }  
+  
+}
+/*---------------------------------------------------------------------------*/
+static void
+editor_start(void)
+{
+  unsigned char i;
+  register struct ctk_label *label;
+  struct line *l, *m;
+
+  m = NULL;
+  
+  for(i = 0; i < NUM_LINES; ++i) {
+    label = &editor_state.labels[i];
+    l = (struct line *)memb_alloc(&linesmem);
+    
+    if(l != NULL) {
+      l->next = NULL;
+      l->prev = m;
+      if(m == NULL) {
+	/* First line */
+	lines = l;
+      } else {
+	m->next = l;
+      }
+      CTK_LABEL_NEW(label, 0, i + 1, EDITOR_CONF_WIDTH, 1, l->text);
+      CTK_WIDGET_SET_FLAG(label, CTK_WIDGET_FLAG_MONOSPACE);
+      CTK_WIDGET_ADD(&window, label);
+    }
+    m = l;
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+editor_eventhandler(ek_event_t ev, ek_data_t data)
+{
+  char *textptr, *textptr2;
+  unsigned char len;
+  
+  if(ev == ctk_signal_keypress) {
+    /*    CTK_WIDGET_FOCUS(t->label.window, &t->label);*/
+    textptr = &(editor_state.labels[editor_state.y].text[editor_state.x]);
+    *textptr &= 0x7f;
+    CTK_WIDGET_REDRAW(&(editor_state.labels[editor_state.y]));
+    
+    switch((ctk_arch_key_t)data) {
+    case CH_CURS_DOWN:
+      ++editor_state.y;
+      if(editor_state.y >= EDITOR_CONF_HEIGHT) {
+	editor_state.y = EDITOR_CONF_HEIGHT - 1;
+      }
+      break; 
+    case CH_CURS_UP:
+      if(editor_state.y > 0) {
+	--editor_state.y;
+      }
+      break; 
+    case CH_CURS_RIGHT:
+      if(editor_state.x < strlen(editor_state.labels[editor_state.y].text)) {
+	++editor_state.x;
+      }
+      break; 
+    case CH_CURS_LEFT:
+      if(editor_state.x > 0) {
+	--editor_state.x;
+      } else {
+	if(editor_state.y > 0) {
+	  --editor_state.y;
+	  editor_state.x = strlen(editor_state.labels[editor_state.y].text);
+	}       
+      }
+      break;
+    case CH_ENTER:
+      editor_state.x = 0;
+      ++editor_state.y;
+      if(editor_state.y >= EDITOR_CONF_HEIGHT) {
+	editor_state.y = EDITOR_CONF_HEIGHT - 1;
+      }
+      break;
+    case CH_DEL:
+      /*      len = t->label.w - t->xpos;
+      if(t->xpos > 0 && len > 0) {
+	strncpy(textptr - 1, textptr,
+		len);
+	*(textptr + len - 1) = 0;
+	--t->xpos;
+	}*/
+      break;      
+    default:
+      len = EDITOR_CONF_WIDTH - editor_state.x;
+      if(len > 0) {
+	textptr2 = textptr + len - 1;
+	while(textptr2 + 1 > textptr) {
+	  *(textptr2 + 1) = *textptr2;
+	  --textptr2;
+	}
+	
+	*textptr = (char)data;
+	++editor_state.x;
+	if(editor_state.x == EDITOR_CONF_WIDTH) {
+	  editor_state.x = 0;
+	  if(editor_state.y < EDITOR_CONF_HEIGHT - 1) {
+	    ++editor_state.y;
+	  }
+	}
+      }
+      break;
+    }
+    textptr = &(editor_state.labels[editor_state.y].text[editor_state.x]);
+    *textptr |= 0x80;
+    CTK_WIDGET_REDRAW(&(editor_state.labels[editor_state.y]));
+    /*  } else if(s == ctk_signal_widget_activate &&
+	    data == (ek_data_t)t) {
+    textptr = &(t->label.text[t->ypos * t->label.w + t->xpos]);
+    *textptr &= 0x7f;
+    t->xpos = 0;
+    if(t->ypos < t->label.h - 1) {
+      ++t->ypos;
+    }
+    textptr = &(t->label.text[t->ypos * t->label.w + t->xpos]);
+    *textptr |= 0x80;
+    CTK_WIDGET_REDRAW(&t->label);*/ 
+  
+
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+open_file(char *name)
+{
+  int fd;
+  struct line *l;
+  char line[LINE_LEN];
+  char *cptr;
+  int i, len, clen;
+  
+  fd = cfs_open(name, 0);
+  if(fd < 0) {
+    show_statustext("Could not open file ", name);
+    return;
+  }
+
+  l = lines; 
+  cptr = l->text;
+  clen = LINE_LEN;
+  
+  do {
+    /* Read a portion of the input file */
+    len = cfs_read(fd, line, LINE_LEN);  
+    
+    /* Split the input into lines. */
+    for(i = 0; i < len; ++i) {
+      if(line[i] == ISO_nl ||
+	 clen == 0) {
+	*cptr = 0;
+	l = l->next;
+	if(l != NULL) {
+	  cptr = l->text;
+	  clen = LINE_LEN;
+	} else {
+	  len = -1;
+	  break;
+	}
+      } else {
+	*cptr++ = line[i];
+	--clen;
+      }
+    }
+  } while(len > 0);
+
+
+  cfs_close(fd);
+}
+/*---------------------------------------------------------------------------*/
+static void
+quit(void)
+{
+  ctk_window_close(&window);
+  ek_exit();
+  LOADER_UNLOAD();
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+
+  if(ctk_filedialog_eventhandler(&filedialog, ev, data)) {
+    return;
+  }
+  
+  switch(ev) {
+  case EK_EVENT_INIT:
+
+    memb_init(&linesmem);
+   
+    ctk_window_new(&window,
+		   EDITOR_CONF_WIDTH + 2,
+		   EDITOR_CONF_HEIGHT + 3,
+		   "Editor");
+
+    CTK_WIDGET_ADD(&window, &openbutton);
+    CTK_WIDGET_ADD(&window, &statuslabel);
+
+    CTK_WIDGET_FOCUS(&window, &openbutton);
+
+    editor_start();
+    
+    ctk_window_open(&window);
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    quit();
+    break;
+  case OPEN_EVENT:
+    /*    printf("Open file '%s'\n", (char *)data);*/
+    open_file((char *)data);
+    ctk_window_redraw(&window);
+    break;
+  default:
+    if(ev == ctk_signal_window_close &&
+       data == (ek_data_t)&window) {
+      quit();
+    } else if(ev == ctk_signal_widget_activate) {
+      if(data == (ek_data_t)&openbutton) {
+	ctk_filedialog_open(&filedialog, "Open", OPEN_EVENT);
+      }      
+    } else {
+      editor_eventhandler(ev, data);
+    }
+  };
+}
+/*---------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(editor_init, arg)
+{
+  arg_free(arg);
+  id = ek_start(&p);
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/email-dsc.c b/contiki/apps/email-dsc.c
new file mode 100644
index 0000000..afb092a
--- /dev/null
+++ b/contiki/apps/email-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: email-dsc.c,v 1.4 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon email_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(email_dsc,
+    "Unfinished e-mail client",
+    "email.prg",
+    email_init,
+    &email_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char tcpipconficon_textmap[9] = {
+  '+', '-', '+',
+  '|', 'v', '|',
+  '+', '-', '+'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon email_icon =
+  {CTK_ICON("E-mail", tcpipconficon_bitmap, tcpipconficon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/email-dsc.h b/contiki/apps/email-dsc.h
new file mode 100644
index 0000000..21198aa
--- /dev/null
+++ b/contiki/apps/email-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: email-dsc.h,v 1.1 2003/08/11 22:23:39 adamdunkels Exp $
+ *
+ */
+#ifndef __EMAIL_DSC_H__
+#define __EMAIL_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(email_dsc);
+
+#endif /* __EMAIL_DSC_H__ */
diff --git a/contiki/apps/email.c b/contiki/apps/email.c
new file mode 100644
index 0000000..a792e84
--- /dev/null
+++ b/contiki/apps/email.c
@@ -0,0 +1,360 @@
+/*
+ * 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. 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.21 2005/05/05 22:15:49 oliverschmidt Exp $
+ *
+ */
+
+
+#include "ek.h"
+#include "ctk.h"
+#include "smtp.h"
+#include "uiplib.h"
+#include "resolv.h"
+#include "petsciiconv.h"
+#include "loader.h"
+#include "tcpip.h"
+
+#include "ctk-textentry-multiline.h"
+
+#include "email-conf.h"
+
+#include <string.h>
+
+#define MAIL_WIDTH EMAIL_CONF_WIDTH
+#define MAIL_HEIGHT EMAIL_CONF_HEIGHT
+/*
+#define MAIL_WIDTH 37
+#define MAIL_HEIGHT 17
+*/
+
+#if (MAIL_WIDTH - 9) < 39
+#define TEXTENTRY_WIDTH (MAIL_WIDTH - 9)
+#else
+#define TEXTENTRY_WIDTH 39
+#endif
+
+static struct ctk_menu menu;
+unsigned char menuitem_compose, menuitem_setup, menuitem_quit;
+
+/* The main window. */
+static struct ctk_window composewindow;
+
+static struct ctk_separator sep1 =
+ {CTK_SEPARATOR(0, MAIL_HEIGHT + 3, MAIL_WIDTH + 1)};
+static struct ctk_label statuslabel =
+ {CTK_LABEL(7, MAIL_HEIGHT + 4, MAIL_WIDTH - 14, 1, "")};
+
+
+static struct ctk_label tolabel =
+  {CTK_LABEL(0, 0, 3, 1, "To:")};
+static char to[40];
+static struct ctk_textentry totextentry =
+  {CTK_TEXTENTRY(8, 0, TEXTENTRY_WIDTH, 1, to, 39)};
+
+static struct ctk_label cclabel =
+  {CTK_LABEL(0, 1, 3, 1, "Cc:")};
+static char cc[40];
+static struct ctk_textentry cctextentry =
+  {CTK_TEXTENTRY(8, 1, TEXTENTRY_WIDTH, 1, cc, 39)};
+
+static struct ctk_label subjectlabel =
+  {CTK_LABEL(0, 2, 8, 1, "Subject:")};
+static char subject[40];
+static struct ctk_textentry subjecttextentry =
+  {CTK_TEXTENTRY(8, 2, TEXTENTRY_WIDTH, 1, subject, 39)};
+
+static char mail[MAIL_WIDTH * MAIL_HEIGHT];
+struct ctk_textentry mailtextentry =
+  {CTK_TEXTENTRY_INPUT(0, 3, MAIL_WIDTH - 1, MAIL_HEIGHT, mail, MAIL_WIDTH - 1, \
+		       ctk_textentry_multiline_input)};
+
+
+static struct ctk_button sendbutton =
+  {CTK_BUTTON(0, MAIL_HEIGHT + 4, 4, "Send")};
+static struct ctk_button erasebutton =
+  {CTK_BUTTON(MAIL_WIDTH - 6, MAIL_HEIGHT + 4, 5, "Erase")};
+
+/* The "Really erase message?" dialog. */
+static struct ctk_window erasedialog;
+static struct ctk_label erasedialoglabel1 =
+  {CTK_LABEL(2, 1, 22, 1, "Really erase message?")};
+static struct ctk_label erasedialoglabel2 =
+  {CTK_LABEL(0, 2, 26, 1, "All contents will be lost.")};
+static struct ctk_button eraseyesbutton =
+  {CTK_BUTTON(4, 4, 3, "Yes")};
+static struct ctk_button erasenobutton =
+  {CTK_BUTTON(18, 4, 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, 26, 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, 26, 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, 26, 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, 26, 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, 26, 1, pop3password, 39)};
+
+
+static struct ctk_button setupokbutton =
+  {CTK_BUTTON(24, 15, 2, "Ok")};
+
+/*
+static DISPATCHER_SIGHANDLER(email_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("E-mail client", NULL, email_sighandler, smtp_appcall)};
+static ek_id_t id;
+*/
+EK_EVENTHANDLER(email_eventhandler, ev, data);
+EK_PROCESS(p, "E-mail client", EK_PRIO_NORMAL,
+	   email_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*-----------------------------------------------------------------------------------*/
+static void
+email_quit(void)
+{
+  ctk_window_close(&setupwindow);
+  ctk_window_close(&composewindow);
+  ctk_menu_remove(&menu);
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(email_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  } else {
+    ctk_window_open(&composewindow);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+applyconfig(void)
+{
+  u16_t addr[2], *addrptr;
+  char *cptr;
+
+  for(cptr = smtpserver; *cptr != ' ' && *cptr != 0; ++cptr);
+  *cptr = 0;
+  
+  addrptr = &addr[0];
+  if(uiplib_ipaddrconv(smtpserver, (unsigned char *)addr) == 0) {
+    addrptr = resolv_lookup(smtpserver);
+    if(addrptr == NULL) {
+      resolv_query(smtpserver);
+      ctk_label_set_text(&statuslabel, "Resolving host...");
+      return;
+    }
+  }
+  smtp_configure("contiki", addrptr);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+prepare_message(void)
+{
+  /* Convert fields to ASCII. */
+  petsciiconv_toascii(to, sizeof(to));
+  petsciiconv_toascii(cc, sizeof(cc));
+  petsciiconv_toascii(subject, sizeof(subject));  
+  petsciiconv_toascii(mail, sizeof(mail));
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+erase_message(void)
+{
+  CTK_TEXTENTRY_CLEAR(&totextentry);
+  CTK_TEXTENTRY_CLEAR(&cctextentry);
+  CTK_TEXTENTRY_CLEAR(&subjecttextentry);
+  CTK_TEXTENTRY_CLEAR(&mailtextentry);
+}
+/*-----------------------------------------------------------------------------------*/
+/*static
+  DISPATCHER_SIGHANDLER(email_sighandler, s, data)*/
+EK_EVENTHANDLER(email_eventhandler, ev, data)
+{
+  struct ctk_widget *w;
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == tcpip_event) {
+    smtp_appcall(data);
+  } else if(ev == EK_EVENT_INIT) {
+
+    /* Create the "Really erase message?" dialog. */
+    ctk_dialog_new(&erasedialog, 26, 6);
+    CTK_WIDGET_ADD(&erasedialog, &erasedialoglabel1);
+    CTK_WIDGET_ADD(&erasedialog, &erasedialoglabel2);
+    CTK_WIDGET_ADD(&erasedialog, &eraseyesbutton);
+    CTK_WIDGET_ADD(&erasedialog, &erasenobutton);
+    CTK_WIDGET_FOCUS(&erasedialog, &erasenobutton);
+    
+    /* Create setup window. */
+    ctk_window_new(&setupwindow, 28, 16, "E-mail setup");
+    
+    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 compose window. */
+
+    ctk_window_new(&composewindow, MAIL_WIDTH + 1, MAIL_HEIGHT + 5, "Compose e-mail");
+    
+    CTK_WIDGET_ADD(&composewindow, &tolabel);
+    CTK_WIDGET_ADD(&composewindow, &cclabel);
+    CTK_WIDGET_ADD(&composewindow, &subjectlabel);
+    
+    CTK_WIDGET_ADD(&composewindow, &totextentry);
+    CTK_WIDGET_FOCUS(&composewindow, &totextentry);  
+    CTK_WIDGET_ADD(&composewindow, &cctextentry);  
+    CTK_WIDGET_ADD(&composewindow, &subjecttextentry);
+    
+    CTK_WIDGET_ADD(&composewindow, &mailtextentry);
+    
+    CTK_WIDGET_ADD(&composewindow, &sep1);
+    CTK_WIDGET_ADD(&composewindow, &statuslabel);
+    
+    CTK_WIDGET_ADD(&composewindow, &sendbutton);
+    CTK_WIDGET_ADD(&composewindow, &erasebutton);
+    
+    erase_message();
+
+    /* Create and add the menu */
+    ctk_menu_new(&menu, "E-mail");
+    menuitem_setup = ctk_menuitem_add(&menu, "Setup");
+    menuitem_compose = ctk_menuitem_add(&menu, "Compose");
+    menuitem_quit = ctk_menuitem_add(&menu, "Quit");
+    ctk_menu_add(&menu);
+
+    /* Attach listeners to signals. */
+    /*    dispatcher_listen(ctk_signal_widget_activate);
+    dispatcher_listen(ctk_signal_menu_activate);
+    dispatcher_listen(ctk_signal_window_close);
+
+    dispatcher_listen(ctk_signal_keypress);*/
+    
+    /* Open setup window */
+    ctk_window_open(&setupwindow);
+
+  } else if(ev == ctk_signal_widget_activate) {
+    w = (struct ctk_widget *)data;
+    if(w == (struct ctk_widget *)&sendbutton) {
+      prepare_message();
+      smtp_send(to, cc, fromaddress, subject, mail, MAIL_WIDTH, MAIL_HEIGHT);
+      ctk_label_set_text(&statuslabel, "Sending message...");
+      CTK_WIDGET_REDRAW(&statuslabel);
+    } else if(w == (struct ctk_widget *)&erasebutton) {
+      ctk_dialog_open(&erasedialog);      
+    } else if(w == (struct ctk_widget *)&eraseyesbutton) {
+      erase_message();
+      ctk_dialog_close();
+    } else if(w == (struct ctk_widget *)&erasenobutton) {
+      ctk_dialog_close();
+    } else if(w == (struct ctk_widget *)&setupokbutton) {
+      applyconfig();
+      ctk_window_close(&setupwindow);
+      ctk_window_open(&composewindow);
+    }
+  } else if(ev == ctk_signal_menu_activate) {
+    if((struct ctk_menu *)data == &menu) {
+      if(menu.active == menuitem_compose) {
+	ctk_window_open(&composewindow);
+      } else if(menu.active == menuitem_setup) {
+	ctk_window_open(&setupwindow);
+      } else if(menu.active == menuitem_quit) {
+	email_quit();
+      }
+    }
+  } else if(ev == resolv_event_found) {
+    if(strcmp(data, smtpserver) == 0) {
+      if(resolv_lookup(smtpserver) != NULL) {
+	applyconfig();
+	ctk_label_set_text(&statuslabel, "");
+      } else {
+	ctk_label_set_text(&statuslabel, "Host not found");
+      }
+      CTK_WIDGET_REDRAW(&statuslabel);  
+    }
+  } else if(ev == EK_EVENT_REQUEST_EXIT) {
+    email_quit();
+  } 
+}
+/*-----------------------------------------------------------------------------------*/
+void
+smtp_done(unsigned char error)
+{
+  if(error == SMTP_ERR_OK) {
+    ctk_label_set_text(&statuslabel, "Mail sent");
+    erase_message();
+    ctk_window_open(&composewindow);
+  } else {
+    ctk_label_set_text(&statuslabel, "Mail error");
+  }
+  CTK_WIDGET_REDRAW(&statuslabel);  
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/email.h b/contiki/apps/email.h
new file mode 100644
index 0000000..bc0d771
--- /dev/null
+++ b/contiki/apps/email.h
@@ -0,0 +1,40 @@
+/*
+ * 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. 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.2 2004/06/06 05:59:21 adamdunkels Exp $
+ *
+ */
+#ifndef __EMAIL_H__
+#define __EMAIL_H__
+
+void email_init(void);
+
+#endif /* __EMAIL_H__ */
diff --git a/contiki/apps/ftp-dsc.c b/contiki/apps/ftp-dsc.c
new file mode 100644
index 0000000..cf3fdeb
--- /dev/null
+++ b/contiki/apps/ftp-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2004, 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. 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: ftp-dsc.c,v 1.4 2005/04/19 22:00:53 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon ftp_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(ftp_dsc,
+    "FTP client",
+    "ftp.prg",
+    ftp_init,
+    &ftp_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char ftpicon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char ftpicon_textmap[9] = {
+  'F', 'T', 'P',
+  ' ', ' ', ' ',
+  'F', 'T', 'P'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon ftp_icon =
+  {CTK_ICON("FTP client", ftpicon_bitmap, ftpicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/ftp-dsc.h b/contiki/apps/ftp-dsc.h
new file mode 100644
index 0000000..7803823
--- /dev/null
+++ b/contiki/apps/ftp-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004, 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. 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: ftp-dsc.h,v 1.1 2004/08/09 20:09:27 adamdunkels Exp $
+ *
+ */
+#ifndef __FTP_DSC_H__
+#define __FTP_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(ftp_dsc);
+
+#endif /* __FTP_DSC_H__ */
diff --git a/contiki/apps/ftp.c b/contiki/apps/ftp.c
new file mode 100644
index 0000000..3203970
--- /dev/null
+++ b/contiki/apps/ftp.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ftp.c,v 1.8 2005/05/08 10:39:08 oliverschmidt Exp $
+ */
+/* Note to self: It would be nice to have a "View" option in the download dialog. */
+
+#include "ftpc.h"
+#include "contiki.h"
+#include "ctk.h"
+#include "cfs.h"
+#include <string.h>
+
+#define MAX_USERNAMELEN 16
+#define MAX_PASSWORDLEN 16
+#define MAX_HOSTNAMELEN 32
+#define MAX_FILENAMELEN 16
+#define FILES_WIDTH 17
+#define FILES_HEIGHT 18
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "FTP client", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static void *connection;
+
+/*  ---  The main window --- */
+
+static struct ctk_window window;
+
+static struct ctk_label localtextlabel =
+  {CTK_LABEL(1, 0, FILES_WIDTH, 1, "Local files")};
+static struct ctk_label remotetextlabel =
+  {CTK_LABEL(1 + FILES_WIDTH + 1, 0,
+	     FILES_WIDTH, 1, "Remote files")};
+
+static char leftptr[FILES_HEIGHT];
+static struct ctk_label leftptrlabel =
+  {CTK_LABEL(0, 1, 1, FILES_HEIGHT, leftptr)};
+static char midptr[FILES_HEIGHT];
+static struct ctk_label midptrlabel =
+  {CTK_LABEL(1 + FILES_WIDTH, 1, 1, FILES_HEIGHT, midptr)};
+static char rightptr[FILES_HEIGHT];
+static struct ctk_label rightptrlabel =
+   {CTK_LABEL(1 + FILES_WIDTH + 1 + FILES_WIDTH, 1,
+	      1, FILES_HEIGHT, rightptr)};
+
+static char localfiles[FILES_WIDTH * FILES_HEIGHT];
+static struct ctk_label localfileslabel =
+  {CTK_LABEL(1, 1,
+	     FILES_WIDTH, FILES_HEIGHT, localfiles)};
+static char remotefiles[FILES_WIDTH * FILES_HEIGHT];
+static struct ctk_label remotefileslabel =
+  {CTK_LABEL(FILES_WIDTH + 1 + 1, 1,
+	     FILES_WIDTH, FILES_HEIGHT, remotefiles)};
+
+static struct ctk_button reloadbutton =
+  {CTK_BUTTON(0, 1 + FILES_HEIGHT, 6, "Reload")};
+
+static struct ctk_button connectionbutton =
+  {CTK_BUTTON(8, 1 + FILES_HEIGHT, 13, "Connection...")};
+static struct ctk_button quitbutton =
+  {CTK_BUTTON(1 + FILES_WIDTH + 1 + FILES_WIDTH - 5,
+	      1 + FILES_HEIGHT, 4, "Quit")};
+
+static char statustext[3 + FILES_WIDTH * 2 + 1];
+static struct ctk_label statuslabel =
+  {CTK_LABEL(0, FILES_HEIGHT + 2, 3 + FILES_WIDTH * 2, 1, statustext)};
+
+
+
+/*  ---  The download/upload dialogs --- */
+static char remotefilename[MAX_FILENAMELEN + 1];
+static char localfilename[MAX_FILENAMELEN + 1];
+
+static struct ctk_window dialog;
+static struct ctk_label downloadlabel =
+  {CTK_LABEL(6, 1, 13, 1, "Download file")};
+static struct ctk_label uploadlabel =
+  {CTK_LABEL(7, 1, 11, 1, "Upload file")};
+static struct ctk_label localfilenametextlabel =
+  {CTK_LABEL(2, 3, 15, 1, "Local filename")};
+static struct ctk_label localfilenamelabel =
+  {CTK_LABEL(3, 5, 16, 1, localfilename)};
+static struct ctk_textentry localfilenameentry =
+  {CTK_TEXTENTRY(2, 5, 16, 1, localfilename, sizeof(localfilename) - 1)};
+static struct ctk_label remotefilenametextlabel =
+  {CTK_LABEL(2, 7, 15, 1, "Remote filename")};
+static struct ctk_label remotefilenamelabel =
+  {CTK_LABEL(3, 9, 16, 1, remotefilename)};
+static struct ctk_textentry remotefilenameentry =
+  {CTK_TEXTENTRY(2, 9, 16, 1, remotefilename, sizeof(remotefilename) - 1)};
+static struct ctk_button downloadbutton =
+  {CTK_BUTTON(0, 11, 13, "Download file")};
+static struct ctk_button uploadbutton =
+  {CTK_BUTTON(0, 11, 11, "Upload file")};
+static struct ctk_button cancelbutton =
+  {CTK_BUTTON(16, 11, 6, "Cancel")};
+  
+/*  ---  The connection window --- */
+static char hostname[MAX_HOSTNAMELEN + 1];
+static char username[MAX_USERNAMELEN + 1];
+static char password[MAX_PASSWORDLEN + 1];
+
+static struct ctk_window connectionwindow;
+static struct ctk_label serverlabel =
+  {CTK_LABEL(0, 1, 10, 1, "FTP server")};
+static struct ctk_textentry serverentry =
+  {CTK_TEXTENTRY(0, 2, 16, 1, hostname, MAX_HOSTNAMELEN)};
+
+static struct ctk_button anonymousbutton =
+  {CTK_BUTTON(10, 4, 9, "Anonymous")};
+static struct ctk_label userlabel =
+  {CTK_LABEL(0, 4, 8, 1, "Username")};
+static struct ctk_textentry userentry =
+  {CTK_TEXTENTRY(0, 5, 16, 1, username, sizeof(username) - 1)};
+static struct ctk_label passwordlabel =
+  {CTK_LABEL(0, 7, 8, 1, "Password")};
+static struct ctk_textentry passwordentry =
+  {CTK_TEXTENTRY(0, 8, 16, 1, password, sizeof(password) - 1)};
+
+static struct ctk_button connectbutton =
+  {CTK_BUTTON(0, 10, 7, "Connect")};
+static struct ctk_button closeconnectionbutton =
+  {CTK_BUTTON(0, 10, 16, "Close connection")};
+
+static struct ctk_button closebutton =
+  {CTK_BUTTON(18, 10, 5, "Close")};
+
+static struct cfs_dir dir;
+static struct cfs_dirent dirent;
+static unsigned char localfileptr = 0;
+
+static unsigned char remotefileptr = 0;
+
+static unsigned char ptrstate;
+#define PTRSTATE_LOCALFILES 0
+#define PTRSTATE_REMOTEFILES 1
+static unsigned char localptr, remoteptr;
+
+static int fd = -1;
+
+/*---------------------------------------------------------------------------*/
+static void
+make_uploaddialog(void)
+{
+  ctk_dialog_new(&dialog, 24, 13);
+
+  CTK_WIDGET_ADD(&dialog, &uploadlabel);
+  CTK_WIDGET_ADD(&dialog, &localfilenametextlabel);
+  CTK_WIDGET_ADD(&dialog, &localfilenamelabel);
+  CTK_WIDGET_ADD(&dialog, &remotefilenametextlabel);
+  CTK_WIDGET_ADD(&dialog, &remotefilenameentry);
+  CTK_WIDGET_ADD(&dialog, &uploadbutton);
+  CTK_WIDGET_ADD(&dialog, &cancelbutton);  
+
+  CTK_WIDGET_FOCUS(&dialog, &uploadbutton);
+}
+/*---------------------------------------------------------------------------*/
+static void
+make_downloaddialog(void)
+{
+  ctk_dialog_new(&dialog, 24, 13);
+
+  CTK_WIDGET_ADD(&dialog, &downloadlabel);
+  CTK_WIDGET_ADD(&dialog, &localfilenametextlabel);
+  CTK_WIDGET_ADD(&dialog, &localfilenameentry);
+  CTK_WIDGET_ADD(&dialog, &remotefilenametextlabel);
+  CTK_WIDGET_ADD(&dialog, &remotefilenamelabel);
+  CTK_WIDGET_ADD(&dialog, &downloadbutton);
+  CTK_WIDGET_ADD(&dialog, &cancelbutton);
+
+  CTK_WIDGET_FOCUS(&dialog, &downloadbutton);
+}
+/*---------------------------------------------------------------------------*/
+static void
+show_statustext(char *text1, char *text2)
+{
+  int len;
+
+  len = strlen(text1);
+  if(len < sizeof(statustext)) {
+    strncpy(statustext, text1, sizeof(statustext));
+    strncpy(statustext + len, text2, sizeof(statustext) - len);
+    CTK_WIDGET_REDRAW(&statuslabel);
+  }  
+  
+}
+/*---------------------------------------------------------------------------*/
+static void
+close_file(void)
+{
+  if(fd != -1) {
+    cfs_close(fd);
+    fd = -1;
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+quit(void)
+{
+  close_file();
+  ctk_window_close(&window);
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*---------------------------------------------------------------------------*/
+static void
+clearptr(void)
+{
+  rightptr[remoteptr] = ' ';
+  midptr[remoteptr] = ' ';
+  leftptr[localptr] = ' ';
+  midptr[localptr] = ' ';    
+}
+/*---------------------------------------------------------------------------*/
+static void
+showptr(void)
+{
+  if(ptrstate == PTRSTATE_LOCALFILES) {
+    rightptr[remoteptr] = ' ';
+    midptr[remoteptr] = ' ';
+    leftptr[localptr] = '>';
+    midptr[localptr] = '<';
+  } else {
+    leftptr[localptr] = ' ';
+    midptr[localptr] = ' ';    
+    rightptr[remoteptr] = '<';
+    midptr[remoteptr] = '>';
+  }
+
+  CTK_WIDGET_REDRAW(&leftptrlabel);
+  CTK_WIDGET_REDRAW(&midptrlabel);
+  CTK_WIDGET_REDRAW(&rightptrlabel);
+}
+/*---------------------------------------------------------------------------*/
+static void
+start_loaddir(void)
+{
+  memset(localfiles, 0, sizeof(localfiles));
+  localfileptr = 0;
+  cfs_opendir(&dir, ".");
+  ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, NULL);
+}
+/*---------------------------------------------------------------------------*/
+static void
+start_loadremote(void)
+{
+  memset(remotefiles, 0, sizeof(remotefiles));
+  remotefileptr = 0;
+  clearptr();
+  remoteptr = 0;
+  showptr();
+  ftpc_list(connection);
+}
+/*---------------------------------------------------------------------------*/
+static void
+make_connectionwindow(void)
+{
+  ctk_dialog_new(&connectionwindow, 25, 11);
+  
+  CTK_WIDGET_ADD(&connectionwindow, &serverlabel);
+  CTK_WIDGET_ADD(&connectionwindow, &serverentry);
+  
+  CTK_WIDGET_ADD(&connectionwindow, &userlabel);
+  CTK_WIDGET_ADD(&connectionwindow, &anonymousbutton);
+  CTK_WIDGET_ADD(&connectionwindow, &userentry);
+  CTK_WIDGET_ADD(&connectionwindow, &passwordlabel);
+  CTK_WIDGET_ADD(&connectionwindow, &passwordentry);
+  
+  if(connection == NULL) {
+    CTK_WIDGET_ADD(&connectionwindow, &connectbutton);
+  } else {
+    CTK_WIDGET_ADD(&connectionwindow, &closeconnectionbutton);
+  }
+  CTK_WIDGET_ADD(&connectionwindow, &closebutton);
+
+  CTK_WIDGET_FOCUS(&connectionwindow, &serverentry);
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  u16_t ipaddr[2], *ipaddrptr;
+  
+  switch(ev) {
+    
+  case EK_EVENT_INIT:
+    ftpc_init();
+
+    memset(statustext, 0, sizeof(statustext));
+    memset(remotefiles, 0, sizeof(remotefiles));
+    memset(localfiles, 0, sizeof(localfiles));
+    memset(leftptr, 0, sizeof(leftptr));
+    memset(midptr, 0, sizeof(midptr));	    
+    memset(rightptr, 0, sizeof(rightptr));
+
+    ptrstate = PTRSTATE_REMOTEFILES;
+    localptr = remoteptr = 0;
+
+    connection = NULL;
+    
+    ctk_window_new(&window,
+		   3 + FILES_WIDTH * 2, 3 + FILES_HEIGHT,
+		   "FTP Client");
+
+    CTK_WIDGET_ADD(&window, &localtextlabel);
+    CTK_WIDGET_ADD(&window, &remotetextlabel);
+    
+    CTK_WIDGET_ADD(&window, &leftptrlabel);
+    CTK_WIDGET_ADD(&window, &localfileslabel);
+    CTK_WIDGET_ADD(&window, &midptrlabel);
+    CTK_WIDGET_ADD(&window, &remotefileslabel);
+    CTK_WIDGET_ADD(&window, &rightptrlabel);
+
+    CTK_WIDGET_ADD(&window, &reloadbutton);
+    CTK_WIDGET_ADD(&window, &connectionbutton);
+    CTK_WIDGET_ADD(&window, &quitbutton);
+    
+    CTK_WIDGET_ADD(&window, &statuslabel);
+
+    CTK_WIDGET_FOCUS(&window, &connectionbutton);
+    ctk_window_open(&window);
+
+    showptr();
+
+    start_loaddir();
+    
+    break;
+  case EK_EVENT_CONTINUE:
+    if(cfs_readdir(&dir, &dirent) == 0 &&
+       localfileptr < FILES_HEIGHT) {
+      strncpy(&localfiles[localfileptr * FILES_WIDTH],
+	      dirent.name, FILES_WIDTH);
+      CTK_WIDGET_REDRAW(&localfileslabel);
+      ++localfileptr;
+      ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, NULL);
+    } else{
+      cfs_closedir(&dir);
+    }   
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    quit();
+    break;
+  default:
+    if(ev == tcpip_event) {
+      ftpc_appcall(data);
+    } else if(ev == resolv_event_found) {
+      /* Either found a hostname, or not. */
+      if((char *)data != NULL &&
+	 (ipaddrptr = resolv_lookup((char *)data)) != NULL) {
+	connection = ftpc_connect(ipaddrptr, HTONS(21));
+	show_statustext("Connecting to ", hostname);
+      } else {
+	show_statustext("Host not found: ", hostname);
+      }
+      
+    } else if(ev == ctk_signal_window_close &&
+	      data == (ek_data_t)&window) {
+      quit();
+    } else if(ev == ctk_signal_widget_activate) {
+      if((struct ctk_button *)data == &quitbutton) {
+	quit();
+      } else if((struct ctk_button *)data == &cancelbutton) {
+	ctk_dialog_close();
+      } else if((struct ctk_button *)data == &downloadbutton) {
+	ctk_dialog_close();
+	close_file();
+	fd = cfs_open(localfilename, CFS_WRITE);
+	if(fd != -1) {
+	  show_statustext("Downloading ", remotefilename);
+	  ftpc_get(connection, remotefilename);
+	} else {
+	  show_statustext("Could not create ", localfilename);
+	}
+      } else if((struct ctk_button *)data == &reloadbutton) {	
+	start_loaddir();
+      } else if((struct ctk_button *)data == &connectionbutton) {	
+	make_connectionwindow();
+	ctk_dialog_open(&connectionwindow);
+      } else if((struct ctk_button *)data == &closebutton) {
+	ctk_dialog_close();
+      } else if((struct ctk_button *)data == &anonymousbutton) {
+	strcpy(username, "ftp");
+	strcpy(password, "contiki@ftp");
+	CTK_WIDGET_REDRAW(&userentry);
+	CTK_WIDGET_REDRAW(&passwordentry);
+      } else if((struct ctk_button *)data == &closeconnectionbutton) {
+	ctk_dialog_close();
+	ftpc_close(connection);
+      } else if((struct ctk_button *)data == &connectbutton) {
+	ctk_dialog_close();
+	if(uiplib_ipaddrconv(hostname, (unsigned char *)ipaddr) == 0) {
+	  ipaddrptr = resolv_lookup(hostname);
+	  if(ipaddrptr == NULL) {
+	    resolv_query(hostname);
+	    show_statustext("Resolving host ", hostname);
+	    break;
+	  }
+	  connection = ftpc_connect(ipaddrptr, HTONS(21));
+	  show_statustext("Connecting to ", hostname);
+	} else {
+	  connection = ftpc_connect(ipaddr, HTONS(21));
+	  show_statustext("Connecting to ", hostname);
+	}       	
+      } 
+      /*      if((struct ctk_button *)data == &closebutton) {
+	ftpc_close(connection);
+	}*/
+    } else if(ev == ctk_signal_keypress) {
+      /* if((ctk_arch_key_t)data == ' ') {
+	if(ptrstate == PTRSTATE_LOCALFILES) {
+	  ptrstate = PTRSTATE_REMOTEFILES;
+	} else {
+	  ptrstate = PTRSTATE_LOCALFILES;
+	}
+      } else */ if((ctk_arch_key_t)data == CH_CURS_UP) {
+	clearptr();
+	if(ptrstate == PTRSTATE_LOCALFILES) {
+	  if(localptr > 0) {
+	    --localptr;
+	  }
+	} else {
+	  if(remoteptr > 0) {
+	    --remoteptr;
+	  }
+	}
+      } else if((ctk_arch_key_t)data == CH_CURS_DOWN) {
+	clearptr();
+	if(ptrstate == PTRSTATE_LOCALFILES) {
+	  if(localptr < FILES_HEIGHT - 1) {
+	    ++localptr;
+	  }
+	} else {
+	  if(remoteptr < FILES_HEIGHT - 1) {
+	    ++remoteptr;
+	  }
+	}
+      } else if((ctk_arch_key_t)data == CH_ENTER) {	
+	if(ptrstate == PTRSTATE_LOCALFILES) {
+	  strncpy(localfilename,
+		  &localfiles[localptr * FILES_WIDTH], FILES_WIDTH);
+	  strncpy(remotefilename,
+		  &localfiles[localptr * FILES_WIDTH], FILES_WIDTH);
+	  make_uploaddialog();
+	  ctk_dialog_open(&dialog);
+	} else {
+	  strncpy(localfilename,
+		  &remotefiles[remoteptr * FILES_WIDTH], FILES_WIDTH);
+	  strncpy(remotefilename,
+		  &remotefiles[remoteptr * FILES_WIDTH], FILES_WIDTH);
+	  ftpc_cwd(connection, remotefilename);
+	  /*	  make_downloaddialog();
+		  ctk_dialog_open(&dialog);*/
+	}
+      } else if((ctk_arch_key_t)data == 'u') {
+	ftpc_cdup(connection);
+      }
+
+      showptr();
+    }
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(ftp_init, arg)
+{
+  arg_free(arg);
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_closed(void)
+{
+  strcpy(statustext, "Connection closed");
+  CTK_WIDGET_REDRAW(&statuslabel);
+  connection = NULL;
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_aborted(void)
+{
+  strcpy(statustext, "Connection reset");
+  CTK_WIDGET_REDRAW(&statuslabel);
+  connection = NULL;
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_timedout(void)
+{
+  strcpy(statustext, "Connection timed out");
+  CTK_WIDGET_REDRAW(&statuslabel);
+  connection = NULL;
+}
+/*---------------------------------------------------------------------------*/
+char *
+ftpc_username(void)
+{
+  return username;
+}
+/*---------------------------------------------------------------------------*/
+char *
+ftpc_password(void)
+{
+  return password;
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_list_file(char *filename)
+{
+  if(remotefileptr < FILES_HEIGHT && filename != NULL) {
+    strncpy(&remotefiles[remotefileptr * FILES_WIDTH], filename, FILES_WIDTH);
+    CTK_WIDGET_REDRAW(&remotefileslabel);
+    ++remotefileptr;
+  }
+
+  if(filename == NULL) {
+    strcpy(statustext, "Connected");
+    CTK_WIDGET_REDRAW(&statuslabel);  
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_cwd_done(unsigned short status)
+{
+  if(status == FTPC_COMPLETED ||
+     status == FTPC_OK) {
+    start_loadremote();
+  } else {
+    make_downloaddialog();
+    ctk_dialog_open(&dialog);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_connected(void *connection)
+{
+  strcpy(statustext, "Loading remote directory");
+  CTK_WIDGET_REDRAW(&statuslabel);
+
+  start_loadremote();
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_data(u8_t *data, u16_t len)
+{
+  if(data == NULL) {
+    show_statustext("Download complete", "");
+    close_file();
+    start_loaddir();
+  } else {
+    cfs_write(fd, data, len);
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/ftpc.c b/contiki/apps/ftpc.c
new file mode 100644
index 0000000..92e50fb
--- /dev/null
+++ b/contiki/apps/ftpc.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ftpc.c,v 1.3 2005/04/17 22:42:33 oliverschmidt Exp $
+ */
+#include "contiki.h"
+#include "ftpc.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+
+#define DATAPORT 6510
+
+#define MAX_FILENAMELEN 32
+
+struct ftp_dataconn {
+  unsigned char type;
+  unsigned char conntype;
+#define CONNTYPE_LIST 0
+#define CONNTYPE_FILE 1
+
+  u16_t port;
+  
+  unsigned char filenameptr;
+  char filename[MAX_FILENAMELEN];  
+
+  
+};
+
+struct ftp_connection {
+  unsigned char type;
+#define TYPE_CONTROL 1
+#define TYPE_DATA    2
+#define TYPE_ABORT   3
+#define TYPE_CLOSE   4
+
+  unsigned char state;
+#define STATE_NONE         0
+#define STATE_INITIAL      1  
+#define STATE_SEND_USER    2
+#define STATE_USER_SENT    3
+#define STATE_SEND_PASS    4
+#define STATE_PASS_SENT    5
+#define STATE_SEND_PORT    6
+#define STATE_PORT_SENT    7
+#define STATE_SEND_OPTIONS 8
+#define STATE_OPTION_SENT  9
+#define STATE_CONNECTED   10
+#define STATE_SEND_NLST   11
+#define STATE_NLST_SENT   12
+#define STATE_SEND_RETR   13
+#define STATE_RETR_SENT   14
+  
+#define STATE_SEND_CWD    15
+#define STATE_CWD_SENT    16
+
+#define STATE_SEND_CDUP   17
+#define STATE_CDUP_SENT   18
+
+#define STATE_SEND_QUIT   19
+#define STATE_QUIT_SENT   20
+  
+  unsigned char connected_confirmed;
+  
+  struct ftp_dataconn dataconn;
+  
+  char code[3];
+  unsigned char codeptr;
+
+  unsigned char optionsptr;
+
+  char filename[MAX_FILENAMELEN];
+
+};
+
+#define NUM_OPTIONS 1
+static const struct {
+  unsigned char num;
+  char *commands[NUM_OPTIONS];
+} options = {
+  NUM_OPTIONS,
+  {"TYPE I\r\n"}
+};
+
+static struct ftp_connection *waiting_for_dataconn;
+
+MEMB(connections, sizeof(struct ftp_connection), 1);
+
+/*---------------------------------------------------------------------------*/
+void
+ftpc_init(void)
+{
+  memb_init(&connections);
+  /*  tcp_listen(HTONS(DATAPORT));*/
+}
+/*---------------------------------------------------------------------------*/
+void *
+ftpc_connect(u16_t *ipaddr, u16_t port)
+{
+  struct ftp_connection *c;
+
+  c = (struct ftp_connection *)memb_alloc(&connections);
+  if(c == NULL) {
+    return NULL;
+  }
+  c->type = TYPE_CONTROL;
+  c->state = STATE_INITIAL;
+  c->connected_confirmed = 0;
+  c->codeptr = 0;  
+  c->dataconn.type = TYPE_DATA;
+  c->dataconn.port = DATAPORT;
+  tcp_listen(HTONS(DATAPORT));
+
+  if(tcp_connect(ipaddr, port, c) == NULL) {
+    memb_free(&connections, c);
+    return NULL;
+  }
+
+  return c;  
+}
+/*---------------------------------------------------------------------------*/
+static void
+handle_input(struct ftp_connection *c)
+{
+  int code;
+
+  code = (c->code[0] - '0') * 100 +
+    (c->code[1] - '0') * 10 +
+    (c->code[2] - '0');
+  /*  printf("Handle input code %d state %d\n", code, c->state);*/
+
+  if(c->state == STATE_INITIAL) {
+    if(code == 220) {
+      c->state = STATE_SEND_USER;
+    }
+  } else if(c->state == STATE_USER_SENT) {
+    if(code == 331) {
+      c->state = STATE_SEND_PASS;
+    }
+  } else if(c->state == STATE_PASS_SENT) {
+    if(code == 230) {
+      c->state = STATE_SEND_OPTIONS;
+      c->optionsptr = 0;
+    }
+  } else if(c->state == STATE_PORT_SENT) {
+    c->state = STATE_CONNECTED;
+    if(c->connected_confirmed == 0) {
+      ftpc_connected(c);
+      c->connected_confirmed = 1;
+    }
+  } else if(c->state == STATE_OPTION_SENT) {
+    if(c->optionsptr >= options.num) {
+      c->state = STATE_SEND_PORT;
+    } else {
+      c->state = STATE_SEND_OPTIONS;
+    }
+  } else if((c->state == STATE_NLST_SENT ||
+	     c->state == STATE_RETR_SENT ||
+	     c->state == STATE_CONNECTED)) {
+    if(code == 226 || code == 550) {
+      tcp_unlisten(htons(c->dataconn.port));
+      ++c->dataconn.port;
+      tcp_listen(htons(c->dataconn.port));
+      c->state = STATE_SEND_PORT;
+    }
+
+    if(code == 550) {
+      ftpc_list_file(NULL);
+    }
+  } else if(c->state == STATE_CWD_SENT ||
+	    c->state == STATE_CDUP_SENT) {
+    c->state = STATE_CONNECTED;
+    ftpc_cwd_done(code);
+    /*  } else if(c->state == STATE_) {
+	c->state = STATE_CONNECTED;*/
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+newdata(struct ftp_connection *c)
+{
+  u16_t i;
+  u8_t d;
+  
+  for(i = 0; i < uip_datalen(); ++i) {
+    d = ((char *)uip_appdata)[i];
+    if(c->codeptr < sizeof(c->code)) {
+      c->code[c->codeptr] = d;
+      ++c->codeptr;
+    }
+
+    if(d == ISO_nl) {
+      handle_input(c);
+      c->codeptr = 0;
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+acked(struct ftp_connection *c)
+{
+  switch(c->state) {
+  case STATE_SEND_USER:
+    c->state = STATE_USER_SENT;
+    break;
+  case STATE_SEND_PASS:
+    c->state = STATE_PASS_SENT;
+    break;
+  case STATE_SEND_PORT:
+    c->state = STATE_PORT_SENT;
+    break;
+  case STATE_SEND_OPTIONS:
+    ++c->optionsptr;
+    c->state = STATE_OPTION_SENT;
+    break;
+  case STATE_SEND_NLST:
+    c->state = STATE_NLST_SENT;
+    break;
+  case STATE_SEND_RETR:
+    c->state = STATE_RETR_SENT;
+    break;
+  case STATE_SEND_CWD:
+    c->state = STATE_CWD_SENT;
+    break;
+  case STATE_SEND_CDUP:
+    c->state = STATE_CDUP_SENT;
+    break;
+  case STATE_SEND_QUIT:
+    c->state = STATE_QUIT_SENT;
+    uip_close();
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+senddata(struct ftp_connection *c)
+{
+  u16_t len;
+  
+  switch(c->state) {
+  case STATE_SEND_USER:
+    strcpy(uip_appdata, "USER ");
+    strncpy(uip_appdata + 5, ftpc_username(), uip_mss() - 7);
+    len = strlen(ftpc_username());
+    strcpy(uip_appdata + 5 + len, "\r\n");
+    uip_send(uip_appdata, len + 2 + 5);
+    break;
+  case STATE_SEND_PASS:
+    strcpy(uip_appdata, "PASS ");
+    strncpy(uip_appdata + 5, ftpc_password(), uip_mss() - 7);
+    len = strlen(ftpc_password());
+    strcpy(uip_appdata + 5 + len, "\r\n");
+    uip_send(uip_appdata, len + 2 + 5);
+    break;
+  case STATE_SEND_PORT:
+    len = sprintf(uip_appdata, "PORT %d,%d,%d,%d,%d,%d\n",
+		  uip_ipaddr1(uip_hostaddr),
+		  uip_ipaddr2(uip_hostaddr),
+		  uip_ipaddr3(uip_hostaddr),
+		  uip_ipaddr4(uip_hostaddr),
+		  (c->dataconn.port) >> 8,
+		  (c->dataconn.port) & 0xff);
+    uip_send(uip_appdata, len);		  
+    break;
+  case STATE_SEND_OPTIONS:
+    len = strlen(options.commands[c->optionsptr]);
+    uip_send(options.commands[c->optionsptr], len);
+    break;
+  case STATE_SEND_NLST:
+    uip_send("NLST\r\n", 6);
+    break;
+  case STATE_SEND_RETR:    
+    len = sprintf(uip_appdata, "RETR %s\r\n", c->filename);
+    uip_send(uip_appdata, len);
+    break;
+  case STATE_SEND_CWD:    
+    len = sprintf(uip_appdata, "CWD %s\r\n", c->filename);
+    uip_send(uip_appdata, len);
+    break;
+  case STATE_SEND_CDUP:
+    uip_send("CDUP\r\n", 6);
+    break;
+  case STATE_SEND_QUIT:
+    uip_send("QUIT\r\n", 6);
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_appcall(void *state)
+{
+  int i, t;
+  struct ftp_connection *c = (struct ftp_connection *)state;
+  struct ftp_dataconn *d = (struct ftp_dataconn *)state;
+    
+  if(uip_connected()) {
+    if(state == NULL) {
+      if(waiting_for_dataconn != NULL) {
+	d = &waiting_for_dataconn->dataconn;
+	waiting_for_dataconn = NULL;
+	tcp_markconn(uip_conn, d);
+	d->filenameptr = 0;
+	
+      } else {
+	uip_abort();
+      }
+    } else {
+      /*      tcp_listen(uip_conn->lport);*/
+      senddata(c);
+    }
+    return;
+  }
+
+  if(c->type == TYPE_ABORT) {
+    uip_abort();
+    return;
+  }
+
+  if(c->type == TYPE_CLOSE) {
+    uip_close();
+    c->type = TYPE_CONTROL;
+    return;
+  }
+
+  if(c->type == TYPE_CONTROL) {
+    if(uip_closed()) {
+      c->dataconn.type = TYPE_ABORT;
+      ftpc_closed();
+      memb_free(&connections, c);
+    }  
+    if(uip_aborted()) {
+      c->dataconn.type = TYPE_ABORT;
+      ftpc_aborted();
+      memb_free(&connections, c);
+    }
+    if(uip_timedout()) {
+      c->dataconn.type = TYPE_ABORT;
+      ftpc_timedout();
+      memb_free(&connections, c);
+    }
+
+
+    if(uip_acked()) {
+      acked(c);
+    }
+    if(uip_newdata()) {
+      newdata(c);
+    }
+    if(uip_rexmit() ||
+       uip_newdata() ||
+     uip_acked()) {
+      senddata(c);
+    } else if(uip_poll()) {    
+      senddata(c);
+    }
+  } else {
+    if(d->conntype == CONNTYPE_LIST) {
+      if(uip_newdata()) {
+	for(i = 0; i < uip_datalen(); ++i) {
+	  t = ((char *)uip_appdata)[i];
+	  
+	  if(d->filenameptr < sizeof(d->filename) - 1 &&
+	     t != ISO_cr &&
+	     t != ISO_nl) {	    
+	    d->filename[d->filenameptr] = t;
+	    ++d->filenameptr;
+	  }
+	  
+	  if(t == ISO_nl) {
+	    d->filename[d->filenameptr] = 0;
+	    ftpc_list_file(d->filename);
+	    d->filenameptr = 0;
+	  }
+
+	}
+      }
+      if(uip_closed()) {
+	ftpc_list_file(NULL);
+      }
+    } else {
+      if(uip_newdata()) {
+	ftpc_data(uip_appdata, uip_datalen());
+	/*	printf("Received %d data bytes: '%s'\n",
+		uip_datalen(), uip_appdata);*/
+      } else if(uip_closed() || uip_timedout() || uip_aborted()) {
+	ftpc_data(NULL, 0);
+      }
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+char
+ftpc_list(void *conn)
+{
+  struct ftp_connection *c;
+
+  c = conn;
+  
+  if(c == NULL ||
+     c->state != STATE_CONNECTED) {
+    return 0;
+  }
+
+  c->state = STATE_SEND_NLST;
+  c->dataconn.conntype = CONNTYPE_LIST;
+  waiting_for_dataconn = c;
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+char
+ftpc_get(void *conn, char *filename)
+{
+  struct ftp_connection *c;
+
+  c = conn;
+  
+  if(c == NULL ||
+     c->state != STATE_CONNECTED) {
+    return 0;
+  }
+
+  strncpy(c->filename, filename, sizeof(c->filename));
+
+  c->state = STATE_SEND_RETR;
+  c->dataconn.conntype = CONNTYPE_FILE;
+  waiting_for_dataconn = c;
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_close(void *conn)
+{
+  struct ftp_connection *c;
+  
+  c = conn;
+  
+  if(c == NULL) {
+    return;
+  }
+
+  c->type = TYPE_CLOSE;
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_cwd(void *conn, char *dirname)
+{
+  struct ftp_connection *c;
+  
+  c = conn;
+  
+  if(c == NULL ||
+     c->state != STATE_CONNECTED) {
+    return;
+  }
+
+  strncpy(c->filename, dirname, sizeof(c->filename));
+  c->state = STATE_SEND_CWD;  
+}
+/*---------------------------------------------------------------------------*/
+void
+ftpc_cdup(void *conn)
+{
+  struct ftp_connection *c;
+  
+  c = conn;
+  
+  if(c == NULL ||
+     c->state != STATE_CONNECTED) {
+    return;
+  }
+  
+  c->state = STATE_SEND_CDUP;  
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/ftpc.h b/contiki/apps/ftpc.h
new file mode 100644
index 0000000..71b0536
--- /dev/null
+++ b/contiki/apps/ftpc.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ftpc.h,v 1.2 2004/09/12 20:24:54 adamdunkels Exp $
+ */
+#ifndef __FTPC_H__
+#define __FTPC_H__
+
+#include "uip.h"
+
+void ftpc_init(void);
+
+void *ftpc_connect(u16_t *ipaddr, u16_t port);
+char ftpc_list(void *connection);
+void ftpc_cwd(void *connection, char *dir);
+void ftpc_cdup(void *connection);
+char ftpc_get(void *connection, char *filename);
+void ftpc_close(void *connection);
+
+
+void ftpc_appcall(void *state);
+
+#define FTPC_OK        200
+#define FTPC_COMPLETED 250
+#define FTPC_NODIR     431
+#define FTPC_NOTDIR    550
+
+/* Functions to be implemented by the calling module: */
+void ftpc_connected(void *connection);
+void ftpc_cwd_done(unsigned short status);
+char *ftpc_username(void);
+char *ftpc_password(void);
+void ftpc_closed(void);
+void ftpc_aborted(void);
+void ftpc_timedout(void);
+void ftpc_list_file(char *filename);
+void ftpc_data(u8_t *data, u16_t len);
+
+#endif /* __FTPC_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..e4062ec
--- /dev/null
+++ b/contiki/apps/html-strings.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: html-strings.c,v 1.3 2004/09/12 20:24:54 adamdunkels Exp $
+ */
+const char html_slasha[4] = 
+/* "/a\0" */
+{0x2f, 0x61, 00, };
+const char html_slashcenter[9] = 
+/* "/center\0" */
+{0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 00, };
+const char html_slashform[7] = 
+/* "/form\0" */
+{0x2f, 0x66, 0x6f, 0x72, 0x6d, 00, };
+const char html_slashh[4] = 
+/* "/h\0" */
+{0x2f, 0x68, 00, };
+const char html_slashscript[9] = 
+/* "/script\0" */
+{0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 00, };
+const char html_slashselect[9] = 
+/* "/select\0" */
+{0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 00, };
+const char html_slashstyle[8] = 
+/* "/style\0" */
+{0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 00, };
+const char html_a[3] = 
+/* "a\0" */
+{0x61, 00, };
+const char html_body[6] = 
+/* "body\0" */
+{0x62, 0x6f, 0x64, 0x79, 00, };
+const char html_br[4] = 
+/* "br\0" */
+{0x62, 0x72, 00, };
+const char html_center[8] = 
+/* "center\0" */
+{0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 00, };
+const char html_form[6] = 
+/* "form\0" */
+{0x66, 0x6f, 0x72, 0x6d, 00, };
+const char html_frame[7] = 
+/* "frame\0" */
+{0x66, 0x72, 0x61, 0x6d, 0x65, 00, };
+const char html_h1[4] = 
+/* "h1\0" */
+{0x68, 0x31, 00, };
+const char html_h2[4] = 
+/* "h2\0" */
+{0x68, 0x32, 00, };
+const char html_h3[4] = 
+/* "h3\0" */
+{0x68, 0x33, 00, };
+const char html_h4[4] = 
+/* "h4\0" */
+{0x68, 0x34, 00, };
+const char html_img[5] = 
+/* "img\0" */
+{0x69, 0x6d, 0x67, 00, };
+const char html_input[7] = 
+/* "input\0" */
+{0x69, 0x6e, 0x70, 0x75, 0x74, 00, };
+const char html_li[4] = 
+/* "li\0" */
+{0x6c, 0x69, 00, };
+const char html_p[3] = 
+/* "p\0" */
+{0x70, 00, };
+const char html_script[8] = 
+/* "script\0" */
+{0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 00, };
+const char html_select[8] = 
+/* "select\0" */
+{0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 00, };
+const char html_style[7] = 
+/* "style\0" */
+{0x73, 0x74, 0x79, 0x6c, 0x65, 00, };
+const char html_tr[4] = 
+/* "tr\0" */
+{0x74, 0x72, 00, };
+const char html_href[6] = 
+/* "href\0" */
+{0x68, 0x72, 0x65, 0x66, 00, };
+const char html_alt[5] = 
+/* "alt\0" */
+{0x61, 0x6c, 0x74, 00, };
+const char html_src[5] = 
+/* "src\0" */
+{0x73, 0x72, 0x63, 00, };
+const char html_type[6] = 
+/* "type\0" */
+{0x74, 0x79, 0x70, 0x65, 00, };
+const char html_submit[8] = 
+/* "submit\0" */
+{0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 00, };
+const char html_value[7] = 
+/* "value\0" */
+{0x76, 0x61, 0x6c, 0x75, 0x65, 00, };
+const char html_action[8] = 
+/* "action\0" */
+{0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 00, };
+const char html_name[6] = 
+/* "name\0" */
+{0x6e, 0x61, 0x6d, 0x65, 00, };
+const char html_text[6] = 
+/* "text\0" */
+{0x74, 0x65, 0x78, 0x74, 00, };
+const char html_size[6] = 
+/* "size\0" */
+{0x73, 0x69, 0x7a, 0x65, 00, };
+const 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..5f53c44
--- /dev/null
+++ b/contiki/apps/html-strings.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: html-strings.h,v 1.3 2004/09/12 20:24:54 adamdunkels Exp $
+ */
+extern const char html_slasha[4];
+extern const char html_slashcenter[9];
+extern const char html_slashform[7];
+extern const char html_slashh[4];
+extern const char html_slashscript[9];
+extern const char html_slashselect[9];
+extern const char html_slashstyle[8];
+extern const char html_a[3];
+extern const char html_body[6];
+extern const char html_br[4];
+extern const char html_center[8];
+extern const char html_form[6];
+extern const char html_frame[7];
+extern const char html_h1[4];
+extern const char html_h2[4];
+extern const char html_h3[4];
+extern const char html_h4[4];
+extern const char html_img[5];
+extern const char html_input[7];
+extern const char html_li[4];
+extern const char html_p[3];
+extern const char html_script[8];
+extern const char html_select[8];
+extern const char html_style[7];
+extern const char html_tr[4];
+extern const char html_href[6];
+extern const char html_alt[5];
+extern const char html_src[5];
+extern const char html_type[6];
+extern const char html_submit[8];
+extern const char html_value[7];
+extern const char html_action[8];
+extern const char html_name[6];
+extern const char html_text[6];
+extern const char html_size[6];
+extern const char html_image[7];
diff --git a/contiki/apps/htmlparser.c b/contiki/apps/htmlparser.c
new file mode 100644
index 0000000..1102e6b
--- /dev/null
+++ b/contiki/apps/htmlparser.c
@@ -0,0 +1,842 @@
+/*
+ * 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. 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.11 2005/06/12 23:44:29 oliverschmidt 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"
+#include "cc.h"
+
+#include <string.h>
+
+#if 1
+#define PRINTF(x)
+#else
+#include <stdio.h>
+#define PRINTF(x) printf x
+#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 word[WWW_CONF_WEBPAGE_WIDTH];
+  unsigned char wordlen;  
+  
+#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 const 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 CC_FASTCALL
+iswhitespace(char c)
+{
+  return (c == ISO_space ||
+	  c == ISO_nl ||
+	  c == ISO_cr ||
+	  c == ISO_ht);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_init(void)
+{
+  s.majorstate = s.lastmajorstate = MAJORSTATE_DISCARD;
+  s.minorstate = MINORSTATE_TEXT;
+  s.lastchar = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static char CC_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;
+}
+/*-----------------------------------------------------------------------------------*/
+static void CC_FASTCALL
+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 CC_FASTCALL
+add_char(unsigned char c)
+{
+  if(s.wordlen < WWW_CONF_WEBPAGE_WIDTH - 1 && c < 0x80) {
+    s.word[s.wordlen] = c;
+    ++s.wordlen;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+do_word(void)
+{
+  if(s.wordlen > 0) {
+    if(s.majorstate == MAJORSTATE_LINK) {
+      if(s.word[s.wordlen] != ISO_space) {
+	add_char(ISO_space);
+      }
+    } else if(s.majorstate == MAJORSTATE_DISCARD) {
+      s.wordlen = 0;
+    } else {
+      s.word[s.wordlen] = '\0';
+      htmlparser_word(s.word, s.wordlen);
+      s.wordlen = 0;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+newline(void)
+{
+  do_word();
+  htmlparser_newline();
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char CC_FASTCALL
+find_tag(char *tag)
+{
+  static unsigned char first, last, i, tabi;
+  static char tagc;
+  
+  first = TAG_FIRST;
+  last = TAG_LAST;
+  i = 0;
+  
+  do {
+    tagc = tag[i];
+
+    if(tagc == 0 &&
+       tags[first][i] == 0) {
+      return first;
+    }
+
+    tabi = 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 non-match
+       and return. Else we continue with the next character. */
+    ++i;
+
+  } while(last != first);
+  return TAG_LAST;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+parse_tag(void)
+{
+  static char *tagattrparam;
+  static unsigned char size;
+
+  static char dummy;
+  
+  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);*/
+    newline();
+    /* FALLTHROUGH */
+  case TAG_BR:
+  case TAG_TR:
+  case TAG_SLASHH:
+    /*    parse_char(ISO_nl);*/
+    dummy = 0;
+    newline();
+    break;
+  case TAG_LI:
+    newline();
+    add_char(ISO_asterisk);
+    add_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:
+    do_word();
+    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);
+      newline();
+      add_char(ISO_rbrack);
+      do_word();
+      htmlparser_link((char *)html_frame, strlen(html_frame), s.tagattrparam);
+      PRINTF(("Frame [%s]\n", s.tagattrparam));
+      add_char(ISO_lbrack);
+      newline();
+    }
+    break;
+  case TAG_IMG:
+    if(strncmp(s.tagattr, html_alt, sizeof(html_alt)) == 0 &&
+       s.tagattrparam[0] != 0) {
+      /*      parse_char(ISO_lt);*/
+      add_char(ISO_lt);
+      tagattrparam = &s.tagattrparam[0];
+      while(*tagattrparam) {
+	/*	parse_char(*tagattrparam);*/
+	add_char(*tagattrparam);
+	++tagattrparam;
+      }
+      /*      parse_char(ISO_gt);*/
+      add_char(ISO_gt);
+      do_word();
+    }
+    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);
+      do_word();
+      switch_majorstate(MAJORSTATE_LINK);
+    }
+    break;
+  case TAG_SLASHA:
+    if(s.majorstate == MAJORSTATE_LINK) {
+      switch_majorstate(s.lastmajorstate);
+      s.word[s.wordlen] = 0;
+      htmlparser_link(s.word, s.wordlen, s.linkurl);
+      s.wordlen = 0;
+    }
+    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:
+	  s.inputvalue[s.inputvaluesize] = 0;
+	  htmlparser_inputfield(s.inputvaluesize, 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);    */
+    newline();
+    htmlparser_renderstate(HTMLPARSER_RENDERSTATE_BEGIN |
+			   HTMLPARSER_RENDERSTATE_CENTER);
+    break;
+  case TAG_SLASHCENTER:
+    /*    parse_char(ISO_nl);*/
+    newline();
+    htmlparser_renderstate(HTMLPARSER_RENDERSTATE_END |
+			   HTMLPARSER_RENDERSTATE_CENTER);
+    break;
+#endif /* WWW_CONF_RENDERSTATE */
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static u16_t
+parse_word(char *data, u8_t dlen)
+{
+  static u8_t i;
+  static u8_t len;
+  unsigned char c;
+
+  len = dlen;
+
+  switch(s.minorstate) {
+  case MINORSTATE_TEXT:
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(iswhitespace(c)) {
+	do_word();
+      } else if(c == ISO_lt) {
+	s.minorstate = MINORSTATE_TAG;
+	s.tagptr = 0;
+	/*	do_word();*/
+	break;
+      } else if(c == ISO_ampersand) {
+	s.minorstate = MINORSTATE_EXTCHAR;
+	break;
+      } else {
+	add_char(c);
+      }
+    }
+    break;
+  case MINORSTATE_EXTCHAR:
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(c == ISO_semicolon) {	
+	s.minorstate = MINORSTATE_TEXT;
+	add_char(' ');
+	break;
+      } else if(iswhitespace(c)) {	
+	s.minorstate = MINORSTATE_TEXT;
+	add_char('&');
+	add_char(' ');
+	break;
+      }
+    }
+    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). */
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(c == ISO_gt) {
+	/* Full tag found. We continue parsing regular text. */
+	s.minorstate = MINORSTATE_TEXT;
+	s.tagattrptr = s.tagattrparamptr = 0;
+	endtagfound();	  
+	parse_tag();
+	break;
+      } else if(iswhitespace(c)) {
+	/* The name of the tag found. We continue parsing the tag
+	   attr.*/
+	s.minorstate = MINORSTATE_TAGATTR;
+	s.tagattrptr = 0;
+	endtagfound();
+	break;
+      } 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;
+	  break;
+	}
+      }
+	
+      /* 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;
+      }
+    }
+    break;
+  case MINORSTATE_TAGATTR:
+    /* We parse the "tag attr", i.e., the "href" in <a
+       href="...">. */
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(c == ISO_gt) {
+	/* Full tag found. */
+	s.minorstate = MINORSTATE_TEXT;
+	s.tagattrparamptr = 0;
+	s.tagattrptr = 0;
+	endtagfound();
+	parse_tag();
+	s.tagptr = 0;
+	endtagfound();
+	break;
+      } 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;
+	  break;
+	  /*	    s.tagattrptr = 0;
+		    endtagfound();*/
+	}
+      } else if(c == ISO_eq) {	
+	s.minorstate = MINORSTATE_TAGATTRPARAMNQ;
+	s.tagattrparamptr = 0;
+	endtagfound();
+	break;
+      } 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;
+	}
+      }
+    }
+    break;
+  case MINORSTATE_TAGATTRSPACE:
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(iswhitespace(c)) {
+	/* Discard spaces. */
+      } else if(c == ISO_eq) {
+	s.minorstate = MINORSTATE_TAGATTRPARAMNQ;
+	s.tagattrparamptr = 0;
+	endtagfound();
+	parse_tag();
+	break;
+      } else {
+	s.tagattr[0] = lowercase(c);
+	s.tagattrptr = 1;
+	s.minorstate = MINORSTATE_TAGATTR;
+	break;
+      }
+    }
+    break;
+  case MINORSTATE_TAGATTRPARAMNQ:
+    /* We are parsing the "tag attr parameter", i.e., the link part
+       in <a href="link">. */
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(c == ISO_gt) {
+	/* Full tag found. */
+	endtagfound();
+	parse_tag();
+	s.minorstate = MINORSTATE_TEXT;
+	s.tagattrptr = 0;       
+	endtagfound();
+	parse_tag();
+	s.tagptr = 0;       
+	endtagfound();
+	break;
+      } 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"));
+	break;
+      } 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();
+	break;
+      } 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;
+	}
+      }
+    }
+    break;
+  case MINORSTATE_TAGATTRPARAM:
+    /* We are parsing the "tag attr parameter", i.e., the link
+       part in <a href="link">. */
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(c == s.quotechar) {
+	/* Found end of tag attr parameter. */
+	endtagfound();
+	parse_tag();
+	  
+	s.minorstate = MINORSTATE_TAGATTR;
+	s.tagattrptr = 0;
+	endtagfound();
+	break;
+      } else {
+	if(iswhitespace(c)) {
+	  s.tagattrparam[s.tagattrparamptr] = ISO_space;
+	} 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;
+	}
+      }
+    }
+    break;
+  case MINORSTATE_HTMLCOMMENT:
+    for(i = 0; i < len; ++i) {
+      c = data[i];
+      if(c == ISO_dash) {
+	++s.tagptr;
+      } else if(c == ISO_gt && s.tagptr > 0) {
+	PRINTF(("Comment done.\n"));
+	s.minorstate = MINORSTATE_TEXT;
+	break;
+      } else {
+	s.tagptr = 0;
+      }
+    }
+    break;
+  case MINORSTATE_TAGEND:
+    /* Discard characters until a '>' is seen. */
+    for(i = 0; i < len; ++i) {
+      if(data[i] == ISO_gt) {
+	s.minorstate = MINORSTATE_TEXT;
+	s.tagattrptr = 0;
+	endtagfound();
+	parse_tag();
+	break;
+      }
+    }
+    break;
+  default:
+    i = 0;
+    break;
+  }
+  if(i >= len) {
+    return len;
+  }
+  return i + 1;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_parse(char *data, u16_t datalen)
+{
+  u16_t plen;
+  
+  while(datalen > 0) {
+    if(datalen > 255) {
+      plen = parse_word(data, 255);
+    } else {
+      plen = parse_word(data, datalen);
+    }
+    datalen -= plen;
+    data += plen;
+  }  
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/htmlparser.h b/contiki/apps/htmlparser.h
new file mode 100644
index 0000000..ce9f7ef
--- /dev/null
+++ b/contiki/apps/htmlparser.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. 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.4 2005/06/12 23:44:30 oliverschmidt Exp $
+ *
+ */
+#ifndef __HTMLPARSER_H__
+#define __HTMLPARSER_H__
+
+#include "uip.h"
+
+/* Callbacks. */
+void htmlparser_link(char *text, unsigned char textlen, char *url);
+void htmlparser_submitbutton(char *value,
+			     char *name,
+			     char *formname,
+			     char *formaction);
+void htmlparser_inputfield(unsigned char size,
+			   char *value,
+			   char *name,
+			   char *formname,
+			   char *formaction);
+void htmlparser_newline(void);
+void htmlparser_word(char *word, unsigned char wordlen);
+
+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..d77c32f
--- /dev/null
+++ b/contiki/apps/http-strings
@@ -0,0 +1,35 @@
+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_crnl "\r\n"
+http_index_html "/index.html"
+http_404_html "/404.html"
+http_referer "Referer:"
+http_header_200 "HTTP/1.0 200 OK\r\nServer: Contiki/1.2 http://www.sics.se/~adam/contiki/\r\nConnection: close\r\n"
+http_header_404 "HTTP/1.0 404 Not found\r\nServer: Contiki/1.2 http://www.sics.se/~adam/contiki/\r\nConnection: close\r\n"
+http_content_type_plain "Content-type: text/plain\r\n\r\n"
+http_content_type_html "Content-type: text/html\r\n\r\n"
+http_content_type_css  "Content-type: text/css\r\n\r\n"
+http_content_type_text "Content-type: text/text\r\n\r\n"
+http_content_type_png  "Content-type: image/png\r\n\r\n"
+http_content_type_gif  "Content-type: image/gif\r\n\r\n"
+http_content_type_jpg  "Content-type: image/jpeg\r\n\r\n"
+http_content_type_binary "Content-type: application/octet-stream\r\n\r\n"
+http_html ".html"
+http_shtml ".shtml"
+http_htm ".htm"
+http_css ".css"
+http_png ".png"
+http_gif ".gif"
+http_jpg ".jpg"
+http_text ".txt"
+http_txt ".txt"
+
diff --git a/contiki/apps/http-strings.c b/contiki/apps/http-strings.c
new file mode 100644
index 0000000..ea743bb
--- /dev/null
+++ b/contiki/apps/http-strings.c
@@ -0,0 +1,102 @@
+const char http_http[8] = 
+/* "http://" */
+{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, };
+const char http_200[5] = 
+/* "200 " */
+{0x32, 0x30, 0x30, 0x20, };
+const char http_301[5] = 
+/* "301 " */
+{0x33, 0x30, 0x31, 0x20, };
+const char http_302[5] = 
+/* "302 " */
+{0x33, 0x30, 0x32, 0x20, };
+const char http_get[5] = 
+/* "GET " */
+{0x47, 0x45, 0x54, 0x20, };
+const char http_10[9] = 
+/* "HTTP/1.0" */
+{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, };
+const char http_11[9] = 
+/* "HTTP/1.1" */
+{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, };
+const char http_content_type[15] = 
+/* "content-type: " */
+{0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, };
+const char http_texthtml[10] = 
+/* "text/html" */
+{0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, };
+const char http_location[11] = 
+/* "location: " */
+{0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, };
+const char http_host[7] = 
+/* "host: " */
+{0x68, 0x6f, 0x73, 0x74, 0x3a, 0x20, };
+const char http_crnl[3] = 
+/* "\r\n" */
+{0xd, 0xa, };
+const char http_index_html[12] = 
+/* "/index.html" */
+{0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, };
+const char http_404_html[10] = 
+/* "/404.html" */
+{0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, };
+const char http_referer[9] = 
+/* "Referer:" */
+{0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x3a, };
+const char http_header_200[92] = 
+/* "HTTP/1.0 200 OK\r\nServer: Contiki/1.2 http://www.sics.se/~adam/contiki/\r\nConnection: close\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, 0x32, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, };
+const char http_header_404[99] = 
+/* "HTTP/1.0 404 Not found\r\nServer: Contiki/1.2 http://www.sics.se/~adam/contiki/\r\nConnection: close\r\n" */
+{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x34, 0x30, 0x34, 0x20, 0x4e, 0x6f, 0x74, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0xd, 0xa, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0x31, 0x2e, 0x32, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, };
+const char http_content_type_plain[29] = 
+/* "Content-type: text/plain\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0xd, 0xa, 0xd, 0xa, };
+const char http_content_type_html[28] = 
+/* "Content-type: text/html\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, };
+const char http_content_type_css [27] = 
+/* "Content-type: text/css\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0xd, 0xa, 0xd, 0xa, };
+const char http_content_type_text[28] = 
+/* "Content-type: text/text\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x65, 0x78, 0x74, 0xd, 0xa, 0xd, 0xa, };
+const char http_content_type_png [28] = 
+/* "Content-type: image/png\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0xd, 0xa, 0xd, 0xa, };
+const char http_content_type_gif [28] = 
+/* "Content-type: image/gif\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0xd, 0xa, 0xd, 0xa, };
+const char http_content_type_jpg [29] = 
+/* "Content-type: image/jpeg\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0xd, 0xa, 0xd, 0xa, };
+const char http_content_type_binary[43] = 
+/* "Content-type: application/octet-stream\r\n\r\n" */
+{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 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, 0xd, 0xa, };
+const char http_html[6] = 
+/* ".html" */
+{0x2e, 0x68, 0x74, 0x6d, 0x6c, };
+const char http_shtml[7] = 
+/* ".shtml" */
+{0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, };
+const char http_htm[5] = 
+/* ".htm" */
+{0x2e, 0x68, 0x74, 0x6d, };
+const char http_css[5] = 
+/* ".css" */
+{0x2e, 0x63, 0x73, 0x73, };
+const char http_png[5] = 
+/* ".png" */
+{0x2e, 0x70, 0x6e, 0x67, };
+const char http_gif[5] = 
+/* ".gif" */
+{0x2e, 0x67, 0x69, 0x66, };
+const char http_jpg[5] = 
+/* ".jpg" */
+{0x2e, 0x6a, 0x70, 0x67, };
+const char http_text[5] = 
+/* ".txt" */
+{0x2e, 0x74, 0x78, 0x74, };
+const char http_txt[5] = 
+/* ".txt" */
+{0x2e, 0x74, 0x78, 0x74, };
diff --git a/contiki/apps/http-strings.h b/contiki/apps/http-strings.h
new file mode 100644
index 0000000..ec5b1fe
--- /dev/null
+++ b/contiki/apps/http-strings.h
@@ -0,0 +1,34 @@
+extern const char http_http[8];
+extern const char http_200[5];
+extern const char http_301[5];
+extern const char http_302[5];
+extern const char http_get[5];
+extern const char http_10[9];
+extern const char http_11[9];
+extern const char http_content_type[15];
+extern const char http_texthtml[10];
+extern const char http_location[11];
+extern const char http_host[7];
+extern const char http_crnl[3];
+extern const char http_index_html[12];
+extern const char http_404_html[10];
+extern const char http_referer[9];
+extern const char http_header_200[92];
+extern const char http_header_404[99];
+extern const char http_content_type_plain[29];
+extern const char http_content_type_html[28];
+extern const char http_content_type_css [27];
+extern const char http_content_type_text[28];
+extern const char http_content_type_png [28];
+extern const char http_content_type_gif [28];
+extern const char http_content_type_jpg [29];
+extern const char http_content_type_binary[43];
+extern const char http_html[6];
+extern const char http_shtml[7];
+extern const char http_htm[5];
+extern const char http_css[5];
+extern const char http_png[5];
+extern const char http_gif[5];
+extern const char http_jpg[5];
+extern const char http_text[5];
+extern const char http_txt[5];
diff --git a/contiki/apps/http-user-agent-string b/contiki/apps/http-user-agent-string
new file mode 100644
index 0000000..451ab12
--- /dev/null
+++ b/contiki/apps/http-user-agent-string
@@ -0,0 +1 @@
+http_user_agent_fields "Connection: close\r\nUser-Agent: Contiki/1.2 (; http://www.sics.se/~adam/contiki/)\r\n\r\n"
diff --git a/contiki/apps/http-user-agent-string.c b/contiki/apps/http-user-agent-string.c
new file mode 100644
index 0000000..9ee4b18
--- /dev/null
+++ b/contiki/apps/http-user-agent-string.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: http-user-agent-string.c,v 1.4 2005/05/16 22:00:43 oliverschmidt Exp $
+ */
+const char http_user_agent_fields[85] = 
+/* "Connection: close\r\nUser-Agent: Contiki/1.1 (; http://www.sics.se/~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, 0x32, 0x20, 0x28, 0x3b, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0x29, 0xd, 0xa, 0xd, 0xa, };
diff --git a/contiki/apps/http-user-agent-string.h b/contiki/apps/http-user-agent-string.h
new file mode 100644
index 0000000..80ea025
--- /dev/null
+++ b/contiki/apps/http-user-agent-string.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: http-user-agent-string.h,v 1.4 2005/05/16 22:00:43 oliverschmidt Exp $
+ */
+extern const char http_user_agent_fields[85];
diff --git a/contiki/apps/httpd-cgi.c b/contiki/apps/httpd-cgi.c
new file mode 100644
index 0000000..495141b
--- /dev/null
+++ b/contiki/apps/httpd-cgi.c
@@ -0,0 +1,218 @@
+/*
+ * 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. 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: httpd-cgi.c,v 1.10 2007/06/02 07:32:06 ryohji Exp $
+ *
+ */
+
+/*
+ * This file includes functions that are called by the web server
+ * scripts. The functions takes no argument, and the return value is
+ * interpreted as follows. A zero means that the function did not
+ * complete and should be invoked for the next packet as well. A
+ * non-zero value indicates that the function has completed and that
+ * the web server should move along to the next script line.
+ *
+ */
+
+#include "uip.h"
+#include "httpd.h"
+#include "httpd-cgi.h"
+#include "httpd-fs.h"
+
+#include "petsciiconv.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static PT_THREAD(file_stats(struct httpd_state *s, char *arg));
+static PT_THREAD(tcp_stats(struct httpd_state *s, char *arg));
+static PT_THREAD(processes(struct httpd_state *s, char *arg));
+
+struct cgifunction {
+  char *name;
+  httpd_cgifunction function;
+};
+
+static struct cgifunction cgitab[] = {
+  {"file-stats", file_stats},
+  {"tcp-connections", tcp_stats},
+  {"processes", processes},
+  {NULL, NULL}
+};
+
+
+static const char closed[] =   /*  "CLOSED",*/
+{0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0};
+static const char syn_rcvd[] = /*  "SYN-RCVD",*/
+{0x53, 0x59, 0x4e, 0x2d, 0x52, 0x43, 0x56, 
+ 0x44,  0};
+static const char syn_sent[] = /*  "SYN-SENT",*/
+{0x53, 0x59, 0x4e, 0x2d, 0x53, 0x45, 0x4e, 
+ 0x54,  0};
+static const char established[] = /*  "ESTABLISHED",*/
+{0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, 
+ 0x45, 0x44, 0};
+static const char fin_wait_1[] = /*  "FIN-WAIT-1",*/
+{0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, 
+ 0x54, 0x2d, 0x31, 0};
+static const char fin_wait_2[] = /*  "FIN-WAIT-2",*/
+{0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, 
+ 0x54, 0x2d, 0x32, 0};
+static const char closing[] = /*  "CLOSING",*/
+{0x43, 0x4c, 0x4f, 0x53, 0x49, 
+ 0x4e, 0x47, 0};
+static const char time_wait[] = /*  "TIME-WAIT,"*/
+{0x54, 0x49, 0x4d, 0x45, 0x2d, 0x57, 0x41, 
+ 0x49, 0x54, 0};
+static const char last_ack[] = /*  "LAST-ACK"*/
+{0x4c, 0x41, 0x53, 0x54, 0x2d, 0x41, 0x43, 
+ 0x4b, 0};
+
+static const char *states[] = {
+  closed,
+  syn_rcvd,
+  syn_sent,
+  established,
+  fin_wait_1,
+  fin_wait_2,
+  closing,
+  time_wait,
+  last_ack};
+  
+
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(nullfunction(struct httpd_state *s, char *ptr))
+{
+  PSOCK_BEGIN(&s->sout);  
+  PSOCK_END(&s->sout);
+}
+/*---------------------------------------------------------------------------*/
+httpd_cgifunction
+httpd_cgi(char *name)
+{
+  struct cgifunction *f;
+
+  /* Find the matching name in the table, return the function. */
+  for(f = cgitab; f->name != NULL; ++f) {
+    if(strncmp(f->name, name, strlen(f->name)) == 0) {
+      return f->function;
+    }
+  }
+  return nullfunction;
+}
+/*---------------------------------------------------------------------------*/
+static unsigned short
+generate_file_stats(void *arg)
+{
+  char *f = (char *)arg;
+  return sprintf((char *)uip_appdata, "%5u", httpd_fs_count(f));
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(file_stats(struct httpd_state *s, char *ptr))
+{
+  PSOCK_BEGIN(&s->sout);
+
+  PSOCK_GENERATOR_SEND(&s->sout, generate_file_stats, strchr(ptr, ' ') + 1);
+  
+  PSOCK_END(&s->sout);
+}
+/*---------------------------------------------------------------------------*/
+static unsigned short
+make_tcp_stats(void *arg)
+{
+  struct uip_conn *conn;
+  struct httpd_state *s = (struct httpd_state *)arg;
+    
+  conn = &uip_conns[s->count];
+  return sprintf((char *)uip_appdata,
+		 "<tr><td>%d</td><td>%u.%u.%u.%u:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n",
+		 htons(conn->lport),
+		 htons(conn->ripaddr[0]) >> 8,
+		 htons(conn->ripaddr[0]) & 0xff,
+		 htons(conn->ripaddr[1]) >> 8,
+		 htons(conn->ripaddr[1]) & 0xff,
+		 htons(conn->rport),
+		 states[conn->tcpstateflags & TS_MASK],
+		 conn->nrtx,
+		 conn->timer,
+		 (uip_outstanding(conn))? '*':' ',
+		 (uip_stopped(conn))? '!':' ');
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(tcp_stats(struct httpd_state *s, char *ptr))
+{
+  
+  PSOCK_BEGIN(&s->sout);
+
+  for(s->count = 0; s->count < UIP_CONNS; ++s->count) {   
+    if((uip_conns[s->count].tcpstateflags & TS_MASK) != CLOSED) {
+      PSOCK_GENERATOR_SEND(&s->sout, make_tcp_stats, s);
+    }
+  }
+
+  PSOCK_END(&s->sout);
+}
+/*---------------------------------------------------------------------------*/
+static unsigned short
+make_processes(void *s)
+{
+  struct ek_proc *p = (struct ek_proc *)s;
+  char name[40];
+
+  strncpy(name, p->name, 40);
+  petsciiconv_toascii(name, 40);
+
+  return sprintf((char *)uip_appdata,
+		 "<tr align=\"center\"><td>%3d</td><td>%s</td><td>0x%02x</td><td>%p</td><td>%p</td><td>%p</td></tr>\r\n",
+		 p->id, name, p->prio,
+		 p->pollhandler, p->eventhandler, p->procstate);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(processes(struct httpd_state *s, char *ptr))
+{
+  static struct ek_proc *p;
+  
+  PSOCK_BEGIN(&s->sout);
+
+  for(s->count = 0; s->count < EK_CONF_MAXPROCS; ++s->count) {
+    p = ek_process(s->count);
+    if(p != NULL) {
+      PSOCK_GENERATOR_SEND(&s->sout, make_processes, p);
+    }    
+  }
+  
+  PSOCK_END(&s->sout);
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/httpd-cgi.h b/contiki/apps/httpd-cgi.h
new file mode 100644
index 0000000..0171fdd
--- /dev/null
+++ b/contiki/apps/httpd-cgi.h
@@ -0,0 +1,45 @@
+/*
+ * 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. 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: httpd-cgi.h,v 1.4 2005/02/27 09:33:51 adamdunkels Exp $
+ *
+ */
+
+#ifndef __HTTPD_CGI_H__
+#define __HTTPD_CGI_H__
+
+#include "pt.h"
+#include "httpd.h"
+
+typedef PT_THREAD((* httpd_cgifunction)(struct httpd_state *, char *));
+
+httpd_cgifunction httpd_cgi(char *name);
+
+#endif /* __HTTPD_CGI_H__ */
diff --git a/contiki/apps/httpd-fs.c b/contiki/apps/httpd-fs.c
new file mode 100644
index 0000000..70958c3
--- /dev/null
+++ b/contiki/apps/httpd-fs.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: httpd-fs.c,v 1.3 2004/06/06 05:59:21 adamdunkels Exp $
+ */
+
+#include "uip.h"
+#include "httpd.h"
+#include "httpd-fs.h"
+#include "httpd-fsdata.h"
+
+#include "httpd-fsdata.c"
+
+#if HTTPD_FS_STATISTICS
+static u16_t count[HTTPD_FS_NUMFILES];
+#endif /* HTTPD_FS_STATISTICS */
+
+/*-----------------------------------------------------------------------------------*/
+static u8_t
+httpd_fs_strcmp(const char *str1, const char *str2)
+{
+  u8_t i;
+  i = 0;
+ loop:
+
+  if(str2[i] == 0 ||
+     str1[i] == '\r' || 
+     str1[i] == '\n') {
+    return 0;
+  }
+
+  if(str1[i] != str2[i]) {
+    return 1;
+  }
+
+
+  ++i;
+  goto loop;
+}
+/*-----------------------------------------------------------------------------------*/
+int
+httpd_fs_open(const char *name, struct httpd_fs_file *file)
+{
+#if HTTPD_FS_STATISTICS
+  u16_t i = 0;
+#endif /* HTTPD_FS_STATISTICS */
+  struct httpd_fsdata_file_noconst *f;
+
+  for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT;
+      f != NULL;
+      f = (struct httpd_fsdata_file_noconst *)f->next) {
+
+    if(httpd_fs_strcmp(name, f->name) == 0) {
+      file->data = f->data;
+      file->len = f->len;
+#if HTTPD_FS_STATISTICS
+      ++count[i];
+#endif /* HTTPD_FS_STATISTICS */
+      return 1;
+    }
+#if HTTPD_FS_STATISTICS
+    ++i;
+#endif /* HTTPD_FS_STATISTICS */
+
+  }
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+httpd_fs_init(void)
+{
+#if HTTPD_FS_STATISTICS
+  u16_t i;
+  for(i = 0; i < HTTPD_FS_NUMFILES; i++) {
+    count[i] = 0;
+  }
+#endif /* HTTPD_FS_STATISTICS */
+}
+/*-----------------------------------------------------------------------------------*/
+#if HTTPD_FS_STATISTICS
+u16_t httpd_fs_count
+(char *name)
+{
+  struct httpd_fsdata_file_noconst *f;
+  u16_t i;
+
+  i = 0;
+  for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT;
+      f != NULL;
+      f = (struct httpd_fsdata_file_noconst *)f->next) {
+
+    if(httpd_fs_strcmp(name, f->name) == 0) {
+      return count[i];
+    }
+    ++i;
+  }
+  return 0;
+}
+#endif /* HTTPD_FS_STATISTICS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/httpd-fs.h b/contiki/apps/httpd-fs.h
new file mode 100644
index 0000000..788924c
--- /dev/null
+++ b/contiki/apps/httpd-fs.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: httpd-fs.h,v 1.2 2004/06/06 05:59:21 adamdunkels Exp $
+ */
+#ifndef __HTTPD_FS_H__
+#define __HTTPD_FS_H__
+
+#include "uip.h"
+
+#define HTTPD_FS_STATISTICS 1
+
+struct httpd_fs_file {
+  char *data;
+  int len;
+};
+
+/* file must be allocated by caller and will be filled in
+   by the function. */
+int httpd_fs_open(const char *name, struct httpd_fs_file *file);
+
+#ifdef HTTPD_FS_STATISTICS
+#if HTTPD_FS_STATISTICS == 1  
+u16_t httpd_fs_count(char *name);
+#endif /* HTTPD_FS_STATISTICS */
+#endif /* HTTPD_FS_STATISTICS */
+
+void httpd_fs_init(void);
+
+#endif /* __HTTPD_FS_H__ */
diff --git a/contiki/apps/httpd-fs/404.html b/contiki/apps/httpd-fs/404.html
new file mode 100644
index 0000000..a17711d
--- /dev/null
+++ b/contiki/apps/httpd-fs/404.html
@@ -0,0 +1,8 @@
+<html>
+  <body bgcolor="white">
+    <center>
+      <h1>404 - file not found</h1>
+      <h3>Go <a href="/">here</a> instead.</h3>
+    </center>
+  </body>
+</html>
\ No newline at end of file
diff --git a/contiki/apps/httpd-fs/files.shtml b/contiki/apps/httpd-fs/files.shtml
new file mode 100644
index 0000000..7f985db
--- /dev/null
+++ b/contiki/apps/httpd-fs/files.shtml
@@ -0,0 +1,24 @@
+%!: /header.html
+ <h1>File statistics</h1><br><table width="100%">
+ <tr><td><a href="/index.html">/index.html</a></td>
+ <td>%! file-stats /index.html
+</td></tr>
+<tr><td><a href="/files.shtml">/files.shtml</a></td>
+<td>%! file-stats /files.shtml
+</td></tr>
+<tr><td><a href="/tcp.shtml">/tcp.shtml</a></td>
+<td>%! file-stats /tcp.shtml
+</td></tr>
+<tr><td><a href="/processes.shtml">/processes.shtml</a></td>
+<td>%! file-stats /processes.shtml
+</td></tr>
+<tr><td><a href="/style.css">/style.css</a></td>
+<td>%! file-stats /contiki.css
+</td></tr>
+<tr><td><a href="/404.html">/404.html</a></td>
+<td>%! file-stats /404.html
+</td></tr>
+<tr><td><a href="/img/screenshot.png">/img/screenshot.png</a></td>
+<td>%! file-stats /img/screenshot.png
+</td></tr></table>
+%!: /footer.html
\ No newline at end of file
diff --git a/contiki/apps/httpd-fs/footer.html b/contiki/apps/httpd-fs/footer.html
new file mode 100644
index 0000000..1fd5f4f
--- /dev/null
+++ b/contiki/apps/httpd-fs/footer.html
@@ -0,0 +1,2 @@
+  </body>
+</html>
\ No newline at end of file
diff --git a/contiki/apps/httpd-fs/header.html b/contiki/apps/httpd-fs/header.html
new file mode 100644
index 0000000..815e57c
--- /dev/null
+++ b/contiki/apps/httpd-fs/header.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>Welcome to the Contiki-demo server!</title>
+    <link rel="stylesheet" type="text/css" href="/style.css">  
+  </head>
+  <body bgcolor="#fffeec" text="black">
+
+  <div class="menublock">
+
+  <div class="menu">
+  <p class="border-title">Menu</p>
+  <p class="menu">
+  
+  <a href="/">Front page</a><br>
+  <a href="files.shtml">File statistics</a><br>
+  <a href="tcp.shtml">Network connections</a><br>
+  <a href="processes.shtml">System processes</a><br>
+
+  </p>
+  </div>
+  </div>
+
+  <div class="contentblock">
+  <p class="border-title">
+  Welcome to the <a href="http://www.sics.se/~adam/contiki/">Contiki</a> 
+  web server!
+  </p>
diff --git a/contiki/apps/httpd-fs/img/screenshot.png b/contiki/apps/httpd-fs/img/screenshot.png
new file mode 100644
index 0000000..7ee2431
--- /dev/null
+++ b/contiki/apps/httpd-fs/img/screenshot.png
Binary files differ
diff --git a/contiki/apps/httpd-fs/index.html b/contiki/apps/httpd-fs/index.html
new file mode 100644
index 0000000..40fad31
--- /dev/null
+++ b/contiki/apps/httpd-fs/index.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>Welcome to the Contiki web server!</title>
+    <link rel="stylesheet" type="text/css" href="/style.css">  
+  </head>
+  <body bgcolor="#fffeec" text="black">
+
+  <div class="menublock">
+
+  <div class="menu">
+  <p class="border-title">Menu</p>
+  <p class="menu">
+  
+  <a href="/">Front page</a><br>
+  <a href="files.shtml">File statistics</a><br>
+  <a href="tcp.shtml">Network connections</a><br>
+  <a href="processes.shtml">System processes</a><br>
+
+  </p>
+  </div>
+  </div>
+
+  <div class="contentblock">
+  <p class="border-title">
+  Welcome to the <a href="http://www.sics.se/~adam/contiki/">Contiki</a> 
+  web server!
+  </p>
+	      
+	  <p class="intro">
+	    The web pages you are watching are served by a <a
+	    href="http://www.sics.se/~adam/contiki/apps/webserver.html">web
+	    server</a> running under the <a
+	    href="http://www.sics.se/~adam/contiki/">Contiki operating
+	    system</a>.
+	  </p>
+
+	  
+	 
+  </body>
+</html>
\ No newline at end of file
diff --git a/contiki/apps/httpd-fs/processes.shtml b/contiki/apps/httpd-fs/processes.shtml
new file mode 100644
index 0000000..2f93e35
--- /dev/null
+++ b/contiki/apps/httpd-fs/processes.shtml
@@ -0,0 +1,5 @@
+%!: /header.html
+<h1>System processes</h1><br><table width="100%">
+<tr><th>ID</th><th>Name</th><th>Priority</th><th>Poll handler</th><th>Event handler</th><th>Procstate</th></tr>
+%! processes
+%!: /footer.html
\ No newline at end of file
diff --git a/contiki/apps/httpd-fs/style.css b/contiki/apps/httpd-fs/style.css
new file mode 100644
index 0000000..6a18127
--- /dev/null
+++ b/contiki/apps/httpd-fs/style.css
@@ -0,0 +1,239 @@
+h1 
+{
+  text-align: center;
+  font-size:14pt;
+  font-family:arial,helvetica;
+  font-weight:bold;
+  padding:10px; 
+}
+
+body
+{
+
+  background-color: #fffeec;
+  color:black;
+
+  font-size:8pt;
+  font-family:arial,helvetica;
+}
+
+.wrap {
+  width: 98%;
+  margin: 0 auto;
+  text-align: left;
+  font-family:arial,helvetica;        
+}
+
+.menublock
+{
+  margin: 4px;
+  width:15%;
+  float:left;
+
+  padding:10px;
+	
+  border: solid 1px;
+  background-color: #fffcd2;
+  text-align:left;
+  
+  font-size:9pt;
+  font-family:arial,helvetica;  
+}
+
+.contentblock
+{  
+  margin: 4px;
+  width:50%;
+  float:left;
+
+  padding:10px;
+
+  border: 1px dotted;
+  background-color: white;
+
+  font-size:8pt;
+  font-family:arial,helvetica;  
+
+}
+
+.newsblock
+{
+  margin: 4px;
+  width:24%;
+  float:left;
+
+
+  padding:10px;
+
+  border: solid 1px;
+  background-color: #fffcd2;
+  text-align:left;
+  font-size:8pt;
+  font-family:arial,helvetica;
+}
+
+.printable
+{
+  margin: 4px;
+  width:24%;
+  float:left;
+
+
+  padding:10px;
+
+  border: 0;
+  background-color: #fffeec;
+  text-align:right;
+  font-size:8pt;
+  font-family:arial,helvetica;
+}
+
+div.rfig
+{
+  border: solid 1px; 
+
+  text-align: left;
+
+  padding: 10px;
+  margin:10px;
+
+  font-size:8pt;
+
+  float:right;
+}
+
+pre.example
+{
+  border: solid 1px; 
+  padding: 10px;
+  margin:10px;
+  text-align: left;
+  font-size:8pt;
+  font-family:arial,helvetica;
+  white-space:pre;  
+}
+
+
+p.intro
+{
+  margin-left:20px;
+  margin-right:20px;
+
+  font-size:10pt;
+/*  font-weight:bold; */
+  font-family:arial,helvetica;  
+}
+
+p.clink
+{
+  font-size:12pt;
+  font-family:courier,monospace;  
+  text-align:center;
+}
+
+p.clink9
+{
+  font-size:9pt;
+  font-family:courier,monospace;  
+  text-align:center;
+}
+
+p.related
+{
+  font-size:10pt;
+  font-family:arial,helvetica;  
+  text-align:center;
+}
+
+
+
+img.right
+{
+  float:right;
+  margin:10px;
+}
+
+img.left
+{
+  float:left;
+  margin:10px;
+}
+
+p.fig
+{
+  border: solid 1px; 
+
+  text-align: center;
+
+  padding: 10px;
+  margin:10px;
+
+  font-size:7pt;
+}
+
+p.rfig
+{
+  border: solid 1px; 
+
+  text-align: center;
+
+  padding: 10px;
+  margin:10px;
+
+  font-size:7pt;
+
+  float:right;
+}
+
+
+p.lfig
+{
+  border: solid 1px; 
+
+  text-align: center;
+
+  padding: 10px;
+  margin:10px;
+
+  font-size:7pt;
+
+  float:left;
+}
+
+p
+{
+  padding-left:10px;
+}
+
+p.mailaddr
+{
+  padding-left:10px;
+  font-size:7pt;
+  font-family:courier,terminal;
+  text-align:right; 
+}
+
+p.right
+{
+  text-align:right; 
+}
+
+p.border-title
+{
+  text-align:center;
+
+  font-size:14pt;
+
+  padding:0px;
+  margin:4px;
+  margin-bottom:10px;
+
+  color: black;
+  background-color: #fffcba;
+  border: solid 1px;
+
+} 
+
+
+
+
diff --git a/contiki/apps/httpd-fs/tcp.shtml b/contiki/apps/httpd-fs/tcp.shtml
new file mode 100644
index 0000000..4c4bffe
--- /dev/null
+++ b/contiki/apps/httpd-fs/tcp.shtml
@@ -0,0 +1,5 @@
+%!: /header.html
+<h1>Current connections</h1><br><table width="100%">
+<tr><th>Local</th><th>Remote</th><th>State</th><th>Retransmissions</th><th>Timer</th><th>Flags</th></tr>
+%! tcp-connections
+%!: /footer.html
\ No newline at end of file
diff --git a/contiki/apps/httpd-fsdata.c b/contiki/apps/httpd-fsdata.c
new file mode 100644
index 0000000..420000a
--- /dev/null
+++ b/contiki/apps/httpd-fsdata.c
@@ -0,0 +1,875 @@
+static const unsigned char data_img_screenshot_png[] = {
+	/* /img/screenshot.png */
+	0x2f, 0x69, 0x6d, 0x67, 0x2f, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x2e, 0x70, 0x6e, 0x67, 0,
+	0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 00, 00, 
+	00, 0xd, 0x49, 0x48, 0x44, 0x52, 00, 00, 0x1, 0x80, 
+	00, 00, 0x1, 0xf, 0x4, 0x3, 00, 00, 00, 0xb9, 
+	0xf, 0xe, 0x81, 00, 00, 00, 0x30, 0x50, 0x4c, 0x54, 
+	0x45, 0x10, 0x10, 0x10, 0xff, 0xff, 0xff, 0xe0, 0x40, 0x40, 
+	0x60, 0xff, 0xff, 0xe0, 0x60, 0xe0, 0x40, 0xe0, 0x40, 0x40, 
+	0x40, 0xe0, 0xff, 0xff, 0x40, 0xe0, 0xa0, 0x40, 0x9c, 0x74, 
+	0x48, 0xff, 0xa0, 0xa0, 0x54, 0x54, 0x54, 0x88, 0x88, 0x88, 
+	0xa0, 0xff, 0xa0, 0xa0, 0xa0, 0xff, 0xc0, 0xc0, 0xc0, 0xe, 
+	0x8c, 0x9e, 0x90, 00, 00, 00, 0x9, 0x70, 0x48, 0x59, 
+	0x73, 00, 00, 0xf, 0xa0, 00, 00, 0xf, 0xa0, 0x1, 
+	0xa0, 0x6a, 0x8c, 0x77, 00, 00, 0x7, 0xcc, 0x49, 0x44, 
+	0x41, 0x54, 0x78, 0xda, 0xed, 0x5d, 0x4b, 0x8e, 0xa4, 0x38, 
+	0x10, 0xb5, 0x57, 0x6c, 0xed, 0x6d, 0x6f, 0xea, 0x32, 0xad, 
+	0x59, 0xf4, 0x39, 0x46, 0xb3, 0xa6, 0x57, 0x48, 0x75, 0x9b, 
+	0x92, 0x5a, 0x6a, 0xa9, 0xae, 0xc0, 0x22, 0xf, 0x96, 0xb, 
+	0xc6, 0xe1, 0x1f, 0x86, 0xcc, 0x82, 0x20, 0xe5, 0x24, 0x1c, 
+	0x59, 0x11, 0xee, 0x4c, 0x30, 0x55, 0xe0, 0x78, 0xf1, 0xfc, 
+	0xfc, 0xc1, 0x54, 0xa3, 0xfe, 0x63, 0x6e, 0x8a, 0xda, 0x1, 
+	0x1, 0x40, 0xed, 0x80, 00, 0xa0, 0x76, 0x40, 00, 0x50, 
+	0x3b, 0x20, 00, 0xa8, 0x1d, 0x10, 00, 0xd4, 0xe, 0x8, 
+	00, 0x6a, 0x7, 0x4, 00, 0xb5, 0x3, 0x2, 0x80, 0xda, 
+	0x1, 0x1, 0x40, 0xed, 0x80, 00, 0xa0, 0x76, 0x40, 00, 
+	0x50, 0x3b, 0x20, 00, 0xa8, 0x1d, 0x10, 00, 0xd4, 0xe, 
+	0x8, 00, 0x6a, 0x7, 0x4, 00, 0xb5, 0x3, 0x2, 0x80, 
+	0xda, 0x1, 0x1, 0xb0, 0x3e, 0x30, 0x80, 0x29, 0x35, 0x50, 
+	0x59, 0xaf, 0xba, 0xcd, 0x9f, 0xa3, 00, 0xf4, 0x5d, 0x3f, 
+	0x5f, 0x5, 0x76, 0xdd, 0xc7, 0x1f, 0xe9, 0xb7, 0x2f, 0x5e, 
+	0x5, 0x40, 0xa7, 0x8a, 0xfd, 0xdb, 0x32, 0x91, 00, 0x6, 
+	0xcf, 0x42, 0x1f, 0x3e, 0xdd, 0x30, 0x9c, 0xe2, 0xfb, 0x90, 
+	0x83, 0x7, 0x35, 0xc0, 0x95, 0xeb, 0x63, 0x7, 0xe5, 0x47, 
+	0x5f, 0xe, 0x1, 0x80, 0xb, 0xf9, 0x8b, 0x41, 0x46, 0x75, 
+	0x21, 0x32, 0x3b, 0xf4, 0xd6, 0x2, 0x10, 0x4b, 0xe, 0x65, 
+	0x7a, 0x17, 0xd2, 0x91, 0x47, 0x1, 0xc0, 0x46, 0x75, 0x27, 
+	0x55, 0x21, 0x97, 0x72, 0xd4, 0xbb, 0x47, 0x1, 0x14, 0x71, 
+	0xc8, 0x1a, 0x50, 0xa7, 0x69, 0x20, 0x14, 0x3, 0xa5, 0x17, 
+	0xc, 0x1c, 0xa9, 0x42, 0xb1, 0xe, 0x46, 0x31, 0xc7, 0x68, 
+	0xa4, 0xba, 0xf9, 0x6c, 00, 0x10, 0xf5, 0xa4, 0xbf, 0x45, 
+	0xf9, 0xc3, 0x1, 00, 0xd, 0x1a, 0x1a, 00, 0x37, 0x13, 
+	00, 0xd4, 0x26, 00, 0xa8, 0x4d, 00, 0x50, 0x9b, 00, 
+	0x78, 0xb6, 0xd9, 0xc2, 0x70, 00, 0xfe, 0x69, 0x2b, 0x19, 
+	0x95, 0x4d, 0xfb, 0x23, 0xdc, 0x18, 0x30, 0xd6, 0x2a, 0x88, 
+	0xbe, 0xfb, 0xd2, 0x28, 0x6, 0xc8, 0x43, 0xbe, 0x4a, 0xc6, 
+	0xb9, 0xee, 0x58, 0xd0, 0x6e, 0xa3, 0xef, 0x10, 0xc0, 0x80, 
+	0x1, 0xa3, 0x83, 00, 0x8c, 0xc6, 0x31, 0x40, 0x1e, 0xf2, 
+	0xb5, 0x6, 0x1c, 0x5, 0xde, 0xac, 0x66, 0xaa, 0x1, 0x9d, 
+	0xda, 0x20, 0xc3, 0x54, 0x3, 0x3a, 0x35, 0x42, 0x86, 0xa9, 
+	0x6, 0xe6, 0x6e, 00, 0xc9, 0x40, 0x63, 0x66, 0x72, 0x47, 
+	0xa0, 0x35, 0xe4, 0x85, 0x1, 0x2a, 0x6, 0x9c, 0x96, 0x99, 
+	0x33, 00, 0x43, 0x9, 0xc6, 0xc, 0x40, 0x67, 0xc0, 0x9a, 
+	0x1, 0xa3, 0xd8, 0x32, 0x60, 0x13, 0x1, 0x58, 0x6, 0xfe, 
+	0x6d, 0x2b, 0x85, 0x9e, 0xd8, 0xc0, 0x68, 0x4e, 0xfb, 0x23, 
+	0xec, 0x18, 0xd0, 0x30, 0x16, 0x35, 0xa, 0x86, 0x12, 0x28, 
+	0x6, 0xc8, 0x43, 0xbe, 0x4a, 0xc6, 0x84, 0x26, 0x8, 00, 
+	0xdc, 0x21, 0x80, 0x1, 0x3, 0x40, 0x81, 0x56, 0x78, 0x6, 
+	0xc8, 0x43, 0xbe, 0xd6, 0x80, 0x9f, 0x90, 0x29, 0xc6, 0x1a, 
+	0xf0, 0xb3, 0x49, 0x85, 0x6f, 0x85, 0xc8, 0x43, 0xbe, 0xd6, 
+	0x40, 0x31, 0xa9, 0x67, 0xa9, 0x81, 0xf2, 0xb6, 0xa, 0x8e, 
+	0x1, 0x42, 0x83, 0xd6, 0x7e, 0xcf, 0x9a, 0x66, 0xc0, 0xcd, 
+	0xbe, 0xa0, 0xb1, 0x59, 0x7a, 0xbc, 0xca, 0xb7, 0xcd, 0x80, 
+	0x4e, 0xfd, 0xae, 0xa, 0x4d, 0xbf, 0x4a, 0xb7, 0x54, 0xfc, 
+	0xd6, 0xc2, 0xcf, 0x1b, 0x67, 0xc0, 0x40, 0x6b, 0xe9, 0x1d, 
+	0xd, 0x29, 0x30, 0x30, 0xe7, 0x11, 00, 0xc8, 0x19, 0x8, 
+	0xff, 0x7c, 0xe4, 0x97, 00, 0x2c, 0x7, 0x6, 0x94, 0xcd, 
+	00, 0xe2, 0xa7, 0x4, 0x70, 0x6f, 0x52, 0xd3, 0x16, 0x3, 
+	0xd0, 0xa, 0xf9, 0xba, 0x6e, 0xb3, 0x6, 0xac, 0x8d, 0x1a, 
+	0xd0, 0xe1, 0xe, 0x69, 0xd3, 0xc, 0xec, 0x35, 0xa1, 00, 
+	0xb0, 0x69, 0x6, 0x30, 0xb6, 0xcf, 0xc0, 0xcf, 0xb6, 0xd3, 
+	0xeb, 0x33, 0x40, 0x1e, 0xe2, 0x9d, 0xf4, 0xfa, 0xc, 0x90, 
+	0x87, 0x58, 0x34, 0x40, 0x1d, 0xe2, 0x57, 0xd3, 0x40, 0xd9, 
+	0x91, 0xe1, 0x18, 0x68, 0xcc, 0xc, 0xdc, 0x14, 0x82, 0x21, 
+	0xb5, 0x31, 0x1a, 0xf2, 0xec, 0x18, 0x30, 0x61, 0x46, 0xf, 
+	0x23, 0x21, 0xcd, 0x94, 0x81, 0x70, 0x73, 0x14, 0x8c, 0x29, 
+	0x3, 0x26, 0x1, 0xe0, 0xca, 0x80, 0x79, 0x5, 0x6, 0x34, 
+	0xe3, 0x56, 0xc8, 0xaf, 0x13, 0xfb, 0x9b, 0xa3, 0xc8, 0x56, 
+	0xe8, 0x67, 0x5b, 0xc9, 0x58, 0xd, 0x13, 0x19, 0x3f, 0x21, 
+	0x83, 0x3c, 0x3f, 0x6, 0xac, 0xb2, 0x51, 0x2, 0x38, 0xd, 
+	0x90, 0x87, 0x7c, 0x95, 0xcc, 0xac, 0x61, 0xb, 0x79, 0x7e, 
+	0xc, 0x94, 00, 0x30, 0xc, 0x90, 0x87, 0x7c, 0x95, 0x8a, 
+	0x46, 0x88, 0xa7, 0x6, 0xf2, 0x40, 0x82, 0xab, 0x6, 0x6c, 
+	0x7e, 0xd2, 0x80, 0xa9, 0x6, 0xac, 0x3d, 0x38, 0x16, 0x3a, 
+	0x70, 0x61, 0x3b, 0xd9, 0xb7, 0xb7, 0xeb, 0x65, 0x1a, 0x27, 
+	0x94, 0x5d, 0xa7, 0x34, 0xae, 0x87, 0xf3, 0xca, 0x63, 0x5b, 
+	0xe5, 0x1c, 0x1e, 0x4a, 0x1c, 0x2, 0xe0, 0xdc, 0x48, 00, 
+	0xdc, 0x16, 0xf, 0xe0, 0x6d, 0x71, 0x6c, 0xda, 0x4, 0x10, 
+	0x6, 0x73, 0xbe, 0xe, 0xd5, 0x5, 00, 0xe5, 0x27, 00, 
+	0xe3, 0x38, 0x3, 0x18, 0xc7, 0x8b, 0xcf, 0xfb, 0x63, 0xd7, 
+	0xbc, 0xf, 0xce, 0x66, 0xf3, 0xe7, 0xc1, 0x19, 0xe1, 0xd8, 
+	0x36, 0x3, 0xbe, 0xe, 0xe9, 0xfa, 0xc, 0x4c, 0x89, 0x81, 
+	0xcb, 0x8, 0xce, 0x4, 0x27, 0x3, 0x13, 0x3e, 0xbf, 0x4a, 
+	0x37, 0xc, 0x44, 0x50, 0x2e, 0xb7, 0xc3, 0x40, 0x90, 0xf1, 
+	0x13, 00, 0xc4, 0x48, 0x8e, 0xe3, 0xe8, 0x3e, 0xd1, 0xc9, 
+	0xe0, 0x58, 0xc8, 0x47, 0x20, 0x71, 0x7f, 0xcd, 0x40, 0xa0, 
+	0xc, 0xc3, 0x80, 0x36, 0xcf, 0x2, 0x10, 0x18, 0x70, 0xee, 
+	0x27, 0x67, 0x63, 0xbd, 0x8e, 0xce, 0x47, 0x30, 0x69, 0xff, 
+	0x2b, 0x6, 0xf6, 00, 0x84, 0x47, 0x6d, 0x60, 0x52, 0xfc, 
+	0x64, 0xd, 0xa4, 0x2a, 0x4, 0xdb, 0xa4, 0x9, 0xf8, 0xca, 
+	0xfa, 0x78, 0x54, 0x3, 0x30, 0x98, 0x33, 0x9e, 0x83, 0xa7, 
+	00, 0xc0, 0xda, 0xf5, 0x3a, 0x2e, 00, 0x94, 0xc7, 0x36, 
+	0xcb, 0x29, 0xac, 0x3a, 00, 0x58, 0x92, 0xdb, 0x5d, 0xd8, 
+	0xbd, 0x67, 0x6a, 0x3e, 0x6d, 0x9a, 0x2e, 0xe3, 0x91, 0x53, 
+	0xf7, 0x1, 0xfc, 0xc1, 0xa5, 0x12, 0xc0, 0x7a, 0x69, 0xf7, 
+	0xfe, 0xf2, 0x8a, 0x2e, 0x76, 0xe7, 0x8c, 0x7, 0xb0, 0xba, 
+	0xc0, 0xcd, 0xf5, 0x8a, 0x3, 0xf5, 0x19, 0xc8, 0xeb, 0x57, 
+	0x36, 0x3e, 0x54, 0x32, 0xaf, 0xe9, 0xa6, 0xfd, 0x22, 0xf2, 
+	0x3a, 0x1, 0x48, 0xc7, 0x1, 0x40, 0x5c, 0x91, 0x54, 0xf3, 
+	0xb9, 0x37, 0xd7, 0xd3, 0xe9, 0x9c, 0x5d, 00, 0x48, 0x2, 
+	0x22, 00, 0xad, 0x4a, 0x67, 0xd2, 0x52, 0xe8, 0x3a, 0x5, 
+	0x67, 0xb4, 0x9d, 0x9f, 0xa4, 0x9f, 0x8f, 0x27, 0x6, 0xf2, 
+	0xb5, 0x7c, 0x5a, 0x5e, 0xaf, 0x5c, 0x2b, 0xae, 0xcb, 0x80, 
+	0xf2, 0xed, 0x43, 0xe1, 0xa4, 0xca, 0xeb, 0xbb, 0x11, 0xd8, 
+	0x5c, 0x59, 0x60, 0x27, 0x3, 0xbd, 0x3, 0xc0, 0x3f, 0xde, 
+	0x1d, 0xd7, 0x83, 0xd3, 0xf8, 0x39, 0xad, 0xd4, 0x1f, 0x2, 
+	0x70, 0x44, 0x3, 0xce, 0xfd, 0x1c, 0xa5, 0xa2, 0x76, 0xa7, 
+	0x65, 0xd2, 0xbc, 0x9f, 0xeb, 0xb1, 0xd1, 0x5f, 0x1, 0xb0, 
+	0xa9, 0x9a, 0xf8, 0x73, 0x94, 0x2d, 0xaf, 0x97, 0x1, 0x60, 
+	0xaa, 0xd0, 0x43, 0x1a, 0x48, 0x91, 0x4d, 0xcf, 0x37, 0xe8, 
+	0x39, 0xe2, 0x45, 0x7d, 0x9e, 0xf5, 0x90, 0x34, 0x92, 0x5b, 
+	0x21, 0xa8, 0xeb, 0x46, 0xcf, 0xa0, 0x57, 0xcf, 0x4c, 0x84, 
+	0xb5, 0x62, 0x7f, 0xb4, 0xaa, 0x6, 0x8e, 0x34, 0x7f, 0x5f, 
+	0xd9, 0x91, 0x66, 0x14, 0x5, 0xe0, 0x50, 0x47, 0x56, 0xc5, 
+	0x2e, 0x23, 0xb6, 0x4c, 0x54, 0x47, 0xf6, 0x7, 0x69, 0x35, 
+	0x1, 0x60, 0xcb, 0x4, 0x13, 0x6, 0x84, 0x1, 0x61, 0x40, 
+	0x18, 0x68, 0x9d, 0x81, 0x5f, 0xb8, 0x54, 0x95, 0x81, 0xad, 
+	0x72, 0xa, 0x83, 0x3c, 0x3b, 0x6, 0x4c, 0x1a, 0x82, 0xbb, 
+	0x2d, 0x8a, 0x1, 0x24, 0x1, 0x55, 0x35, 0xb0, 0x55, 0x8e, 
+	0xb1, 0xf9, 0xde, 0xa2, 0x86, 0x3c, 0x43, 0x6, 0x60, 0x24, 
+	0x67, 0xfd, 0x86, 0xa5, 0x6, 0xc, 0xc, 0xe1, 0x14, 0xdc, 
+	0x60, 0xb4, 0x9a, 0xa7, 0x6, 0x60, 0xc4, 0x6e, 0x35, 0x6c, 
+	0x78, 0x6a, 0xa0, 0x98, 0x87, 0x5a, 0x96, 0x1a, 0xb0, 0x2e, 
+	0xf6, 0x7e, 0xb6, 0x6c, 0xb5, 0xc5, 0x31, 0x80, 0xb4, 0xaa, 
+	0xc, 0x6c, 0x95, 0x93, 0x6f, 0x6a, 0x28, 0xb, 0x79, 0x7e, 
+	0xc, 0x68, 0x98, 0x79, 0x6b, 0x2f, 0x3, 0x9e, 0xc, 0x38, 
+	0xc7, 0x5d, 0x5f, 0xa0, 0x61, 0xcb, 0x94, 0x81, 0x3c, 0x23, 
+	0x66, 0xca, 0x80, 0xa, 0x55, 0x48, 0xf3, 0x65, 0x60, 0xae, 
+	0x42, 0x3c, 0x19, 0x28, 0xaa, 0x10, 0x4f, 0x6, 0xa0, 0x23, 
+	0x86, 0x9e, 0xc0, 0x6d, 0x78, 0x32, 00, 0x3d, 0x18, 0x24, 
+	0xf7, 0xf, 0xc7, 0xc0, 0x27, 0x2e, 0x55, 0x65, 0x60, 0xab, 
+	0x1c, 0x7f, 0x53, 0xd4, 0xfa, 0x31, 0x1d, 0xe4, 0xd9, 0x31, 
+	0x60, 0x52, 0x57, 0xec, 0xba, 0x32, 0x14, 0x3, 0x48, 0x2, 
+	0xaa, 0x6a, 0x60, 0xab, 0x1c, 0xe3, 0xef, 0x55, 0x7b, 0x2, 
+	0x34, 0xe4, 0xf9, 0x31, 0xa0, 0xd3, 0x84, 0xc6, 0xe0, 0x18, 
+	0x68, 0x4d, 0x3, 0xe5, 0x94, 0x92, 0xa7, 0x6, 0xe6, 0x35, 
+	0x5, 0x9e, 0x1a, 0x28, 0x6f, 0xab, 0xd4, 0xd7, 00, 0x3c, 
+	0xf7, 0x33, 0xa6, 0x5, 0xec, 0xeb, 0xbe, 0xaf, 0x8b, 0xdf, 
+	0x4f, 0xe7, 0x5c, 0xc6, 0x23, 0xeb, 0xcd, 0xfb, 0xc, 0x20, 
+	0x6d, 0x7e, 0xd4, 0x20, 0x3f, 0x23, 0xb1, 0xf, 0x20, 0xff, 
+	0xfe, 0x18, 0x3f, 0x4b, 00, 0xc5, 0xec, 0xf1, 0x71, 00, 
+	0x87, 0x18, 0x78, 0xcb, 0x4f, 0xa4, 0x1c, 0x3, 0x90, 0x9f, 
+	00, 0x29, 00, 0x14, 0xeb, 0x69, 0xf1, 0xaf, 0x59, 0xd3, 
+	0x1a, 0x9b, 0x2a, 0xd7, 0x9f, 0x9f, 0xc2, 0x40, 0xf9, 0xe0, 
+	0x6, 0xa, 0x40, 0x78, 0x28, 0xaa, 0x60, 0x60, 0xb5, 0xde, 
+	0x1c, 0x17, 0x1, 0x43, 0xd2, 0xaa, 0x5c, 0x7f, 0x7e, 0xe, 
+	0x3, 0x47, 0x1, 0xac, 0x19, 0x58, 0xad, 0x37, 0x97, 0x7f, 
+	0x3f, 0x6c, 0xc2, 0x7f, 0xd, 0x93, 0xd7, 0x9f, 0xdb, 0x60, 
+	0xe0, 0x6, 0xc0, 0x72, 0xbd, 0xb9, 0x4, 0x10, 0x1e, 0x4f, 
+	0x98, 0xd7, 0x9f, 0xab, 0x33, 0x30, 0xa5, 0x67, 0xe3, 0x90, 
+	00, 0x7c, 0x2b, 0xf4, 0x95, 0x6, 0x16, 0x55, 0xc8, 0xc6, 
+	0xbf, 0x29, 0x8e, 0x55, 0x2b, 0x1e, 0xab, 0xce, 0x40, 0xb2, 
+	0xc5, 0xf3, 0x40, 0x5b, 00, 0xa6, 0xf5, 0x39, 0x95, 0x1f, 
+	0xb7, 0xf9, 0xf5, 0x89, 0x4b, 0x55, 0x7b, 0x62, 0x64, 0x99, 
+	0x90, 0xea, 0x32, 0x50, 0x9, 00, 0xb6, 0x4c, 0xb0, 0x7d, 
+	00, 0xc8, 0x50, 0x54, 0x5, 0x70, 0x80, 0x82, 0xd7, 0x67, 
+	0xe0, 0x88, 0x6, 0xc6, 0x2a, 0xc6, 0x5e, 0x3, 0x13, 0x8d, 
+	0x6, 0xde, 0xaa, 0x31, 0x30, 0xd2, 0x68, 0x60, 0xaa, 0x9, 
+	0xa0, 0x2a, 0x3, 0x8d, 0x99, 0x2a, 0x8c, 0x25, 0x80, 0xae, 
+	0x78, 0x9, 0x4, 0x4f, 00, 0x2e, 0xf2, 0x5d, 0xd7, 0xf7, 
+	0x6e, 0xc3, 0x16, 00, 0x60, 0x50, 0x3d, 0x5f, 00, 0x5d, 
+	0x10, 0x40, 0xcf, 0x16, 0x40, 0x1f, 00, 0x74, 0x6c, 0x1, 
+	0xa8, 0xf0, 0x56, 0x1c, 0xb6, 0x55, 0xa8, 0xf3, 0xf5, 0x1f, 
+	0xbe, 0x99, 0x2, 0x38, 0x2c, 0xe2, 0xf7, 0x2a, 0xe9, 0xf7, 
+	0x8f, 0x3a, 0xd7, 0x79, 0xef, 0xfa, 0xd4, 0x8d, 0x75, 0x3d, 
+	0xe4, 0xcf, 0x62, 0xe0, 0x43, 0xd7, 0x63, 0xa0, 0xf, 0x1a, 
+	0x46, 0x32, 0x50, 0x29, 0x70, 0x1f, 0xaa, 0x12, 0x5, 0x8e, 
+	0x81, 0xde, 0x5, 0xdf, 0x1, 0xe8, 0x7a, 0xc8, 0x9f, 0xc6, 
+	0x80, 0xaa, 0x44, 0x41, 0x9, 00, 0xc5, 0x40, 0x2d, 0xd, 
+	0xa8, 0x4a, 0x14, 0x2c, 0xaa, 0xd0, 0x99, 0x1a, 0x50, 0x95, 
+	0x28, 0xf0, 0x22, 0x8e, 0x5f, 0x28, 0x6, 0xaa, 0x69, 0x40, 
+	0xdb, 0x3a, 0x1a, 0x50, 0xbe, 0xf6, 0xf8, 0x66, 0xf4, 0x54, 
+	0xd, 0x68, 0xf5, 0xa3, 0xe, 0x3, 0xe, 0xc1, 0xa0, 0x3a, 
+	0x7c, 0x47, 0xf6, 0x5e, 0xc7, 0x7e, 0x5b, 0xa7, 0x81, 0x1a, 
+	0x16, 0x86, 0x12, 0xa1, 0x2f, 0x83, 0xfc, 0x59, 0xc, 0x7c, 
+	0x7e, 0xd8, 0x4a, 0xc, 0xa8, 0x3e, 0xbe, 0xa5, 0x12, 0xdb, 
+	0xf, 0x34, 0x66, 0x30, 0x9c, 0xee, 00, 0x45, 0x7f, 0x32, 
+	0x3, 0xb5, 0xc, 0x44, 0xdc, 0xd, 0x7d, 0x8f, 0x1e, 0xb, 
+	0x51, 0x47, 0xfc, 0x96, 0x1, 0xff, 0x6e, 0xd5, 0xfe, 0x74, 
+	0xd, 0x54, 0x63, 0x60, 0xf0, 0xe1, 0xef, 0x3a, 0xec, 0xa4, 
+	0x9e, 0x3a, 0xe2, 0x6b, 0xb, 0xf3, 0x99, 0xd0, 0xc, 0xe1, 
+	0x18, 0xf8, 0x4b, 0x93, 0x5c, 0x5f, 0x35, 0x28, 0x84, 0x35, 
+	0xcb, 0x40, 0x2, 0x30, 0x8f, 0xff, 0x1f, 0x4, 0x40, 0x44, 
+	0xc0, 0xa7, 0x7, 00, 0x2f, 0x62, 0x4d, 00, 0x40, 0xb8, 
+	0xe1, 0x85, 0xc2, 0xca, 0xbf, 0x5b, 0x36, 0xee, 0x37, 0xcc, 
+	0x40, 0x3f, 0xc4, 0x77, 0xf8, 0xaa, 0xc4, 0x44, 0xd7, 0xdf, 
+	0xa6, 0x76, 0x35, 00, 0x4a, 0xcd, 0xaf, 0x27, 0xe, 0x77, 
+	0x22, 0x42, 0x3e, 0x2, 0x89, 0xfb, 0xed, 0x32, 0xe0, 0xdc, 
+	0x4f, 0xce, 0xa6, 0x39, 0x70, 0xc8, 0x47, 0x30, 0x71, 0xbf, 
+	0x7d, 0xd, 0xa4, 0x2a, 0x14, 0xdf, 0x92, 0x9c, 0xe7, 0x3, 
+	0x71, 0xbf, 0x59, 0x6, 0x30, 0x4d, 0x28, 0xae, 0x15, 0x6a, 
+	0xdc, 0x9a, 0x65, 00, 0x6b, 0xc2, 00, 0xb5, 0x9, 0x3, 
+	0xd4, 0x26, 0xc, 0x50, 0xdb, 0x37, 0x60, 0x60, 0x68, 0x3b, 
+	0xbd, 0x3e, 0x3, 0xe4, 0x21, 0xde, 0x49, 0xaf, 0xcf, 00, 
+	0x79, 0x88, 0x45, 0x3, 0xd4, 0x21, 0xfe, 0xf6, 0x1a, 0x18, 
+	0x1a, 0x37, 0x61, 0x80, 0xda, 0x84, 0x1, 0x6a, 0x13, 0x6, 
+	0xa8, 0x6d, 0x9f, 0x81, 0xa1, 0xed, 0xf4, 0xfa, 0xc, 0x90, 
+	0x87, 0x78, 0x27, 0xbd, 0x3e, 0x3, 0xe4, 0x21, 0x16, 0xd, 
+	0x50, 0x87, 0xf8, 0xdb, 0x6b, 0x80, 0x9b, 0x9, 00, 0x6a, 
+	0x13, 00, 0xd4, 0x26, 00, 0xa8, 0x4d, 00, 0x50, 0x9b, 
+	00, 0xa0, 0x36, 0x1, 0x40, 0x6d, 0x2, 0x80, 0xda, 0x4, 
+	00, 0xb5, 0x9, 00, 0x6a, 0x13, 00, 0xd4, 0x26, 00, 
+	0xa8, 0x4d, 00, 0x50, 0x9b, 00, 0xa0, 0x36, 0x1, 0x40, 
+	0x6d, 0x2, 0x80, 0xda, 0x4, 00, 0xb5, 0x9, 00, 0x6a, 
+	0x63, 0xf, 0xe0, 0x7f, 0xaa, 0x34, 0x79, 0xbd, 0xcc, 0x79, 
+	0xa3, 0xc, 00, 00, 00, 00, 0x49, 0x45, 0x4e, 0x44, 
+	0xae, 0x42, 0x60, 0x82, 0};
+
+static const unsigned char data_upload_html[] = {
+	/* /upload.html */
+	0x2f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x3c, 0x62, 0x6f, 
+	0x64, 0x79, 0x3e, 0xa, 0x3c, 0x66, 0x6f, 0x72, 0x6d, 0x20, 
+	0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x75, 0x70, 
+	0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 
+	0x20, 0x65, 0x6e, 0x63, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 
+	0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 
+	0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x22, 
+	0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x3d, 0x22, 0x70, 
+	0x6f, 0x73, 0x74, 0x22, 0x3e, 0xa, 0x3c, 0x69, 0x6e, 0x70, 
+	0x75, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x75, 
+	0x73, 0x65, 0x72, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x20, 0x74, 
+	0x79, 0x70, 0x65, 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x22, 
+	0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x22, 0x35, 0x30, 0x22, 
+	0x20, 0x2f, 0x3e, 0xa, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 
+	0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x22, 0x55, 0x70, 
+	0x6c, 0x6f, 0x61, 0x64, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, 
+	0x3d, 0x22, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x22, 0x20, 
+	0x2f, 0x3e, 0xa, 0x3c, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 
+	0xa, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, 
+	0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0};
+
+static const unsigned char data_404_html[] = {
+	/* /404.html */
+	0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x20, 0x20, 0x3c, 
+	0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, 
+	0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, 
+	0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x63, 0x65, 0x6e, 
+	0x74, 0x65, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 
+	0x20, 0x3c, 0x68, 0x31, 0x3e, 0x34, 0x30, 0x34, 0x20, 0x2d, 
+	0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 
+	0x66, 0x6f, 0x75, 0x6e, 0x64, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 
+	0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x68, 0x33, 
+	0x3e, 0x47, 0x6f, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 
+	0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, 
+	0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 
+	0x61, 0x64, 0x2e, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, 0x20, 
+	0x20, 0x20, 0x20, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 
+	0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 
+	0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 
+0};
+
+static const unsigned char data_style_css[] = {
+	/* /style.css */
+	0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0,
+	0x68, 0x31, 0x20, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x74, 0x65, 
+	0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 
+	0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x20, 0x20, 
+	0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 
+	0x31, 0x34, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 
+	0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 
+	0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 
+	0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0xa, 0x20, 0x20, 0x66, 
+	0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 
+	0x3a, 0x62, 0x6f, 0x6c, 0x64, 0x3b, 0xa, 0x20, 0x20, 0x70, 
+	0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x31, 0x30, 0x70, 
+	0x78, 0x3b, 0x20, 0xa, 0x7d, 0xa, 0xa, 0x62, 0x6f, 0x64, 
+	0x79, 0xa, 0x7b, 0xa, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, 
+	0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 
+	0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x65, 
+	0x65, 0x63, 0x3b, 0xa, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 
+	0x72, 0x3a, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x3b, 0xa, 0xa, 
+	0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 
+	0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 
+	0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 
+	0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 
+	0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0xa, 0x7d, 0xa, 
+	0xa, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x20, 0x7b, 0xa, 0x20, 
+	0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x39, 0x38, 
+	0x25, 0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 
+	0x6e, 0x3a, 0x20, 0x30, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b, 
+	0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 
+	0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x3b, 
+	0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 
+	0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 
+	0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 
+	0x3b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa, 
+	0x7d, 0xa, 0xa, 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6c, 
+	0x6f, 0x63, 0x6b, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x6d, 0x61, 
+	0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, 0x70, 0x78, 0x3b, 
+	0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x31, 
+	0x35, 0x25, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 
+	0x74, 0x3a, 0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0xa, 0x20, 
+	0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x31, 
+	0x30, 0x70, 0x78, 0x3b, 0xa, 0x9, 0xa, 0x20, 0x20, 0x62, 
+	0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x6f, 0x6c, 
+	0x69, 0x64, 0x20, 0x31, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 
+	0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 
+	0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 
+	0x66, 0x66, 0x63, 0x64, 0x32, 0x3b, 0xa, 0x20, 0x20, 0x74, 
+	0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 
+	0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0x20, 0x20, 0xa, 0x20, 
+	0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 
+	0x3a, 0x39, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 
+	0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 
+	0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 
+	0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0x20, 0x20, 0xa, 0x7d, 
+	0xa, 0xa, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 
+	0x62, 0x6c, 0x6f, 0x63, 0x6b, 0xa, 0x7b, 0x20, 0x20, 0xa, 
+	0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 
+	0x34, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 
+	0x74, 0x68, 0x3a, 0x35, 0x30, 0x25, 0x3b, 0xa, 0x20, 0x20, 
+	0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x6c, 0x65, 0x66, 0x74, 
+	0x3b, 0xa, 0xa, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 
+	0x6e, 0x67, 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0xa, 
+	0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 
+	0x31, 0x70, 0x78, 0x20, 0x64, 0x6f, 0x74, 0x74, 0x65, 0x64, 
+	0x3b, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 
+	0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 
+	0x3a, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x3b, 0xa, 0xa, 
+	0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 
+	0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 
+	0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 
+	0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 
+	0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0x20, 0x20, 0xa, 
+	0xa, 0x7d, 0xa, 0xa, 0x2e, 0x6e, 0x65, 0x77, 0x73, 0x62, 
+	0x6c, 0x6f, 0x63, 0x6b, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x6d, 
+	0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, 0x70, 0x78, 
+	0x3b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 
+	0x32, 0x34, 0x25, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6c, 0x6f, 
+	0x61, 0x74, 0x3a, 0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0xa, 
+	0xa, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 
+	0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0xa, 0x20, 0x20, 
+	0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x6f, 
+	0x6c, 0x69, 0x64, 0x20, 0x31, 0x70, 0x78, 0x3b, 0xa, 0x20, 
+	0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 
+	0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 
+	0x66, 0x66, 0x66, 0x63, 0x64, 0x32, 0x3b, 0xa, 0x20, 0x20, 
+	0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 
+	0x3a, 0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 
+	0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x38, 
+	0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 
+	0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, 
+	0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, 
+	0x69, 0x63, 0x61, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x2e, 0x70, 
+	0x72, 0x69, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0xa, 0x7b, 
+	0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 
+	0x20, 0x34, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x77, 0x69, 
+	0x64, 0x74, 0x68, 0x3a, 0x32, 0x34, 0x25, 0x3b, 0xa, 0x20, 
+	0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x6c, 0x65, 0x66, 
+	0x74, 0x3b, 0xa, 0xa, 0xa, 0x20, 0x20, 0x70, 0x61, 0x64, 
+	0x64, 0x69, 0x6e, 0x67, 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 
+	0xa, 0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 
+	0x3a, 0x20, 0x30, 0x3b, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, 
+	0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 
+	0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x65, 
+	0x65, 0x63, 0x3b, 0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 
+	0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x72, 0x69, 0x67, 
+	0x68, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 
+	0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 
+	0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 
+	0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 
+	0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 
+	0x3b, 0xa, 0x7d, 0xa, 0xa, 0x64, 0x69, 0x76, 0x2e, 0x72, 
+	0x66, 0x69, 0x67, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x62, 0x6f, 
+	0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x6f, 0x6c, 0x69, 
+	0x64, 0x20, 0x31, 0x70, 0x78, 0x3b, 0x20, 0xa, 0xa, 0x20, 
+	0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 
+	0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0xa, 
+	0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 
+	0x20, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x6d, 
+	0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x31, 0x30, 0x70, 0x78, 
+	0x3b, 0xa, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 
+	0x73, 0x69, 0x7a, 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0xa, 
+	0xa, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x72, 
+	0x69, 0x67, 0x68, 0x74, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x70, 
+	0x72, 0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 
+	0xa, 0x7b, 0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 
+	0x72, 0x3a, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20, 0x31, 
+	0x70, 0x78, 0x3b, 0x20, 0xa, 0x20, 0x20, 0x70, 0x61, 0x64, 
+	0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x31, 0x30, 0x70, 0x78, 
+	0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 
+	0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x74, 
+	0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 
+	0x20, 0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 
+	0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x38, 
+	0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 
+	0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, 
+	0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, 
+	0x69, 0x63, 0x61, 0x3b, 0xa, 0x20, 0x20, 0x77, 0x68, 0x69, 
+	0x74, 0x65, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x70, 
+	0x72, 0x65, 0x3b, 0x20, 0x20, 0xa, 0x7d, 0xa, 0xa, 0xa, 
+	0x70, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0xa, 0x7b, 0xa, 
+	0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x6c, 
+	0x65, 0x66, 0x74, 0x3a, 0x32, 0x30, 0x70, 0x78, 0x3b, 0xa, 
+	0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x72, 
+	0x69, 0x67, 0x68, 0x74, 0x3a, 0x32, 0x30, 0x70, 0x78, 0x3b, 
+	0xa, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 
+	0x69, 0x7a, 0x65, 0x3a, 0x31, 0x30, 0x70, 0x74, 0x3b, 0xa, 
+	0x2f, 0x2a, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 
+	0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x62, 0x6f, 0x6c, 0x64, 
+	0x3b, 0x20, 0x2a, 0x2f, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 
+	0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 
+	0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 
+	0x74, 0x69, 0x63, 0x61, 0x3b, 0x20, 0x20, 0xa, 0x7d, 0xa, 
+	0xa, 0x70, 0x2e, 0x63, 0x6c, 0x69, 0x6e, 0x6b, 0xa, 0x7b, 
+	0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 
+	0x7a, 0x65, 0x3a, 0x31, 0x32, 0x70, 0x74, 0x3b, 0xa, 0x20, 
+	0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 
+	0x6c, 0x79, 0x3a, 0x63, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 
+	0x2c, 0x6d, 0x6f, 0x6e, 0x6f, 0x73, 0x70, 0x61, 0x63, 0x65, 
+	0x3b, 0x20, 0x20, 0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 
+	0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x63, 0x65, 0x6e, 
+	0x74, 0x65, 0x72, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 
+	0x63, 0x6c, 0x69, 0x6e, 0x6b, 0x39, 0xa, 0x7b, 0xa, 0x20, 
+	0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 
+	0x3a, 0x39, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 
+	0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 
+	0x63, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x2c, 0x6d, 0x6f, 
+	0x6e, 0x6f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3b, 0x20, 0x20, 
+	0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 
+	0x69, 0x67, 0x6e, 0x3a, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 
+	0x3b, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x72, 0x65, 0x6c, 
+	0x61, 0x74, 0x65, 0x64, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x66, 
+	0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x31, 
+	0x30, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 
+	0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 
+	0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 
+	0x74, 0x69, 0x63, 0x61, 0x3b, 0x20, 0x20, 0xa, 0x20, 0x20, 
+	0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 
+	0x3a, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x7d, 
+	0xa, 0xa, 0xa, 0xa, 0x69, 0x6d, 0x67, 0x2e, 0x72, 0x69, 
+	0x67, 0x68, 0x74, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x66, 0x6c, 
+	0x6f, 0x61, 0x74, 0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3b, 
+	0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 
+	0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x69, 
+	0x6d, 0x67, 0x2e, 0x6c, 0x65, 0x66, 0x74, 0xa, 0x7b, 0xa, 
+	0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x6c, 0x65, 
+	0x66, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 
+	0x69, 0x6e, 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x7d, 
+	0xa, 0xa, 0x70, 0x2e, 0x66, 0x69, 0x67, 0xa, 0x7b, 0xa, 
+	0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 
+	0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20, 0x31, 0x70, 0x78, 0x3b, 
+	0x20, 0xa, 0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 
+	0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, 0x6e, 
+	0x74, 0x65, 0x72, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x70, 0x61, 
+	0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x31, 0x30, 0x70, 
+	0x78, 0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 
+	0x6e, 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0xa, 0x20, 
+	0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 
+	0x3a, 0x37, 0x70, 0x74, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x70, 
+	0x2e, 0x72, 0x66, 0x69, 0x67, 0xa, 0x7b, 0xa, 0x20, 0x20, 
+	0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x6f, 
+	0x6c, 0x69, 0x64, 0x20, 0x31, 0x70, 0x78, 0x3b, 0x20, 0xa, 
+	0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 
+	0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x65, 
+	0x72, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 
+	0x69, 0x6e, 0x67, 0x3a, 0x20, 0x31, 0x30, 0x70, 0x78, 0x3b, 
+	0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 
+	0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x66, 
+	0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x37, 
+	0x70, 0x74, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x66, 0x6c, 0x6f, 
+	0x61, 0x74, 0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3b, 0xa, 
+	0x7d, 0xa, 0xa, 0xa, 0x70, 0x2e, 0x6c, 0x66, 0x69, 0x67, 
+	0xa, 0x7b, 0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 
+	0x72, 0x3a, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20, 0x31, 
+	0x70, 0x78, 0x3b, 0x20, 0xa, 0xa, 0x20, 0x20, 0x74, 0x65, 
+	0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 
+	0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0xa, 0x20, 
+	0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 
+	0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, 
+	0x72, 0x67, 0x69, 0x6e, 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 
+	0xa, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 
+	0x69, 0x7a, 0x65, 0x3a, 0x37, 0x70, 0x74, 0x3b, 0xa, 0xa, 
+	0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x6c, 0x65, 
+	0x66, 0x74, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x70, 0xa, 0x7b, 
+	0xa, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 
+	0x2d, 0x6c, 0x65, 0x66, 0x74, 0x3a, 0x31, 0x30, 0x70, 0x78, 
+	0x3b, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x6d, 0x61, 0x69, 
+	0x6c, 0x61, 0x64, 0x64, 0x72, 0xa, 0x7b, 0xa, 0x20, 0x20, 
+	0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 
+	0x66, 0x74, 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x20, 
+	0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 
+	0x3a, 0x37, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 
+	0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 
+	0x63, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x2c, 0x74, 0x65, 
+	0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x3b, 0xa, 0x20, 0x20, 
+	0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 
+	0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3b, 0x20, 0xa, 0x7d, 
+	0xa, 0xa, 0x70, 0x2e, 0x72, 0x69, 0x67, 0x68, 0x74, 0xa, 
+	0x7b, 0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 
+	0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 
+	0x3b, 0x20, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x62, 0x6f, 
+	0x72, 0x64, 0x65, 0x72, 0x2d, 0x74, 0x69, 0x74, 0x6c, 0x65, 
+	0xa, 0x7b, 0xa, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 
+	0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x63, 0x65, 0x6e, 0x74, 
+	0x65, 0x72, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 
+	0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x31, 0x34, 0x70, 
+	0x74, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 
+	0x69, 0x6e, 0x67, 0x3a, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x20, 
+	0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x34, 0x70, 
+	0x78, 0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 
+	0x6e, 0x2d, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x3a, 0x31, 
+	0x30, 0x70, 0x78, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x63, 0x6f, 
+	0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x62, 0x6c, 0x63, 0x61, 0x6b, 
+	0x3b, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 
+	0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 
+	0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x63, 0x62, 0x61, 0x3b, 
+	0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 
+	0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20, 0x31, 0x70, 0x78, 
+	0x3b, 0xa, 0xa, 0x7d, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 
+0};
+
+static const unsigned char data_header_html[] = {
+	/* /header.html */
+	0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 
+	0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 
+	0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, 
+	0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, 
+	0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, 
+	0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 
+	0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 
+	0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, 
+	0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, 
+	0x22, 0x3e, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 
+	0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, 
+	0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 
+	0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, 
+	0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x69, 
+	0x6b, 0x69, 0x2d, 0x64, 0x65, 0x6d, 0x6f, 0x20, 0x73, 0x65, 
+	0x72, 0x76, 0x65, 0x72, 0x21, 0x3c, 0x2f, 0x74, 0x69, 0x74, 
+	0x6c, 0x65, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6c, 
+	0x69, 0x6e, 0x6b, 0x20, 0x72, 0x65, 0x6c, 0x3d, 0x22, 0x73, 
+	0x74, 0x79, 0x6c, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x22, 
+	0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 
+	0x74, 0x2f, 0x63, 0x73, 0x73, 0x22, 0x20, 0x68, 0x72, 0x65, 
+	0x66, 0x3d, 0x22, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 
+	0x63, 0x73, 0x73, 0x22, 0x3e, 0x20, 0x20, 0xa, 0x20, 0x20, 
+	0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, 0x20, 
+	0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 
+	0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x66, 0x66, 0x66, 0x65, 
+	0x65, 0x63, 0x22, 0x20, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x22, 
+	0x62, 0x6c, 0x61, 0x63, 0x6b, 0x22, 0x3e, 0xa, 0xa, 0x20, 
+	0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 
+	0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6c, 0x6f, 
+	0x63, 0x6b, 0x22, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 
+	0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 
+	0x6d, 0x65, 0x6e, 0x75, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 
+	0x70, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x62, 
+	0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x74, 0x69, 0x74, 0x6c, 
+	0x65, 0x22, 0x3e, 0x4d, 0x65, 0x6e, 0x75, 0x3c, 0x2f, 0x70, 
+	0x3e, 0xa, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x63, 0x6c, 0x61, 
+	0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x22, 0x3e, 
+	0xa, 0x20, 0x20, 0xa, 0x20, 0x20, 0x3c, 0x61, 0x20, 0x68, 
+	0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, 0x72, 
+	0x6f, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, 0x2f, 
+	0x61, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 
+	0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x69, 
+	0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 
+	0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 
+	0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 
+	0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x61, 0x20, 
+	0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, 0x2e, 
+	0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 
+	0x77, 0x6f, 0x72, 0x6b, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 
+	0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x61, 0x20, 
+	0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x70, 0x72, 0x6f, 0x63, 
+	0x65, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 
+	0x6c, 0x22, 0x3e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 
+	0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3c, 
+	0x2f, 0x61, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0xa, 0x20, 
+	0x20, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 
+	0x64, 0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x64, 
+	0x69, 0x76, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 
+	0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 
+	0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, 0x6f, 0x63, 
+	0x6b, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x63, 
+	0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x62, 0x6f, 0x72, 0x64, 
+	0x65, 0x72, 0x2d, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3e, 
+	0xa, 0x20, 0x20, 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 
+	0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x61, 
+	0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 
+	0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 
+	0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 
+	0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 
+	0x22, 0x3e, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x3c, 
+	0x2f, 0x61, 0x3e, 0x20, 0xa, 0x20, 0x20, 0x77, 0x65, 0x62, 
+	0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, 0xa, 0x20, 
+	0x20, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0};
+
+static const unsigned char data_index_html[] = {
+	/* /index.html */
+	0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 
+	0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 
+	0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, 
+	0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, 
+	0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 
+	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, 
+	0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 
+	0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 
+	0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, 
+	0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, 
+	0x22, 0x3e, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 
+	0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, 
+	0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 
+	0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, 
+	0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x69, 
+	0x6b, 0x69, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 
+	0x76, 0x65, 0x72, 0x21, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 
+	0x65, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x69, 
+	0x6e, 0x6b, 0x20, 0x72, 0x65, 0x6c, 0x3d, 0x22, 0x73, 0x74, 
+	0x79, 0x6c, 0x65, 0x73, 0x68, 0x65, 0x65, 0x74, 0x22, 0x20, 
+	0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 
+	0x2f, 0x63, 0x73, 0x73, 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 
+	0x3d, 0x22, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 
+	0x73, 0x73, 0x22, 0x3e, 0x20, 0x20, 0xa, 0x20, 0x20, 0x3c, 
+	0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, 0x20, 0x3c, 
+	0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, 
+	0x6f, 0x72, 0x3d, 0x22, 0x23, 0x66, 0x66, 0x66, 0x65, 0x65, 
+	0x63, 0x22, 0x20, 0x74, 0x65, 0x78, 0x74, 0x3d, 0x22, 0x62, 
+	0x6c, 0x61, 0x63, 0x6b, 0x22, 0x3e, 0xa, 0xa, 0x20, 0x20, 
+	0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 
+	0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6c, 0x6f, 0x63, 
+	0x6b, 0x22, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 
+	0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 
+	0x65, 0x6e, 0x75, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x70, 
+	0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x62, 0x6f, 
+	0x72, 0x64, 0x65, 0x72, 0x2d, 0x74, 0x69, 0x74, 0x6c, 0x65, 
+	0x22, 0x3e, 0x4d, 0x65, 0x6e, 0x75, 0x3c, 0x2f, 0x70, 0x3e, 
+	0xa, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x63, 0x6c, 0x61, 0x73, 
+	0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x22, 0x3e, 0xa, 
+	0x20, 0x20, 0xa, 0x20, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 
+	0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, 0x72, 0x6f, 
+	0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, 0x2f, 0x61, 
+	0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x61, 
+	0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x66, 0x69, 0x6c, 
+	0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 
+	0x46, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 
+	0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 
+	0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x61, 0x20, 0x68, 
+	0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, 0x2e, 0x73, 
+	0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x77, 
+	0x6f, 0x72, 0x6b, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 
+	0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 
+	0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x61, 0x20, 0x68, 
+	0x72, 0x65, 0x66, 0x3d, 0x22, 0x70, 0x72, 0x6f, 0x63, 0x65, 
+	0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 
+	0x22, 0x3e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x70, 
+	0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3c, 0x2f, 
+	0x61, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0xa, 0x20, 0x20, 
+	0x3c, 0x2f, 0x70, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x64, 
+	0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x69, 
+	0x76, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 
+	0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 0x6f, 
+	0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 
+	0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x63, 0x6c, 
+	0x61, 0x73, 0x73, 0x3d, 0x22, 0x62, 0x6f, 0x72, 0x64, 0x65, 
+	0x72, 0x2d, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3e, 0xa, 
+	0x20, 0x20, 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 
+	0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x61, 0x20, 
+	0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 
+	0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 
+	0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 
+	0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0x22, 
+	0x3e, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x3c, 0x2f, 
+	0x61, 0x3e, 0x20, 0xa, 0x20, 0x20, 0x77, 0x65, 0x62, 0x20, 
+	0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, 0xa, 0x20, 0x20, 
+	0x3c, 0x2f, 0x70, 0x3e, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, 
+	0x20, 0x20, 0xa, 0x9, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x63, 
+	0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x69, 0x6e, 0x74, 0x72, 
+	0x6f, 0x22, 0x3e, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, 0x54, 
+	0x68, 0x65, 0x20, 0x77, 0x65, 0x62, 0x20, 0x70, 0x61, 0x67, 
+	0x65, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x61, 0x72, 0x65, 
+	0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x20, 
+	0x61, 0x72, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 
+	0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x3c, 0x61, 0xa, 0x9, 
+	0x20, 0x20, 0x20, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 
+	0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 
+	0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 
+	0x61, 0x64, 0x61, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 
+	0x6b, 0x69, 0x2f, 0x61, 0x70, 0x70, 0x73, 0x2f, 0x77, 0x65, 
+	0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x68, 0x74, 
+	0x6d, 0x6c, 0x22, 0x3e, 0x77, 0x65, 0x62, 0xa, 0x9, 0x20, 
+	0x20, 0x20, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3c, 
+	0x2f, 0x61, 0x3e, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 
+	0x67, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 
+	0x65, 0x20, 0x3c, 0x61, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, 
+	0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 
+	0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 
+	0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 
+	0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2f, 0x22, 
+	0x3e, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x20, 0x6f, 
+	0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0xa, 0x9, 
+	0x20, 0x20, 0x20, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 
+	0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0xa, 0x9, 0x20, 0x20, 0x3c, 
+	0x2f, 0x70, 0x3e, 0xa, 0xa, 0x9, 0x20, 0x20, 0xa, 0x9, 
+	0x20, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 
+	0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0};
+
+static const unsigned char data_footer_html[] = {
+	/* /footer.html */
+	0x2f, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 
+	0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0};
+
+static const unsigned char data_files_shtml[] = {
+	/* /files.shtml */
+	0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 
+	0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x20, 0x3c, 0x68, 
+	0x31, 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 
+	0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x68, 
+	0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x74, 0x61, 0x62, 
+	0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 
+	0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0xa, 0x20, 0x3c, 0x74, 
+	0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 
+	0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x69, 0x6e, 0x64, 0x65, 
+	0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x69, 
+	0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 
+	0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x20, 
+	0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 
+	0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x69, 
+	0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 
+	0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 
+	0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 
+	0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x66, 
+	0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 
+	0x22, 0x3e, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 
+	0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 
+	0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 
+	0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 
+	0x73, 0x20, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 
+	0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 
+	0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 
+	0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 
+	0x66, 0x3d, 0x22, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, 0x68, 
+	0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x74, 0x63, 0x70, 0x2e, 
+	0x73, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 
+	0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x25, 
+	0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 
+	0x74, 0x73, 0x20, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, 0x68, 
+	0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 
+	0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 
+	0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 
+	0x3d, 0x22, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 
+	0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 
+	0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 
+	0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 
+	0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 
+	0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 
+	0x61, 0x74, 0x73, 0x20, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 
+	0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 
+	0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 
+	0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 
+	0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 
+	0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 
+	0x3e, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 
+	0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 
+	0xa, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 
+	0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 
+	0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x2e, 0x63, 0x73, 
+	0x73, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 
+	0x72, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 
+	0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 
+	0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 
+	0x3e, 0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 
+	0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 
+	0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 
+	0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x34, 
+	0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 
+	0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 
+	0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 
+	0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x69, 0x6d, 0x67, 
+	0x2f, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 
+	0x74, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x3e, 0x2f, 0x69, 0x6d, 
+	0x67, 0x2f, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 
+	0x6f, 0x74, 0x2e, 0x70, 0x6e, 0x67, 0x3c, 0x2f, 0x61, 0x3e, 
+	0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 
+	0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 
+	0x61, 0x74, 0x73, 0x20, 0x2f, 0x69, 0x6d, 0x67, 0x2f, 0x73, 
+	0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x2e, 
+	0x70, 0x6e, 0x67, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 
+	0x2f, 0x74, 0x72, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 
+	0x65, 0x3e, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, 0x6f, 
+	0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0};
+
+static const unsigned char data_processes_shtml[] = {
+	/* /processes.shtml */
+	0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 
+	0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, 
+	0x3e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x70, 0x72, 
+	0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3c, 0x2f, 0x68, 
+	0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x74, 0x61, 0x62, 
+	0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 
+	0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 
+	0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x49, 0x44, 0x3c, 0x2f, 0x74, 
+	0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4e, 0x61, 0x6d, 0x65, 
+	0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, 
+	0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x3c, 0x2f, 0x74, 
+	0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, 0x6f, 0x6c, 0x6c, 
+	0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x3c, 0x2f, 
+	0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x45, 0x76, 0x65, 
+	0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 
+	0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, 
+	0x72, 0x6f, 0x63, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3c, 0x2f, 
+	0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x25, 
+	0x21, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 
+	0x73, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, 0x6f, 0x6f, 
+	0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0};
+
+static const unsigned char data_tcp_shtml[] = {
+	/* /tcp.shtml */
+	0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 
+	0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, 
+	0x3e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x63, 
+	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 
+	0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 
+	0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 
+	0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0xa, 
+	0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4c, 0x6f, 
+	0x63, 0x61, 0x6c, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 
+	0x68, 0x3e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x3c, 0x2f, 
+	0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x53, 0x74, 0x61, 
+	0x74, 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 
+	0x3e, 0x52, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 
+	0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3c, 0x2f, 0x74, 0x68, 
+	0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x54, 0x69, 0x6d, 0x65, 0x72, 
+	0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x46, 
+	0x6c, 0x61, 0x67, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 
+	0x2f, 0x74, 0x72, 0x3e, 0xa, 0x25, 0x21, 0x20, 0x74, 0x63, 
+	0x70, 0x2d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 
+	0x6f, 0x6e, 0x73, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, 
+	0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 
+0};
+
+const struct httpd_fsdata_file file_img_screenshot_png[] = {{NULL, data_img_screenshot_png, data_img_screenshot_png + 20, sizeof(data_img_screenshot_png) - 20}};
+
+const struct httpd_fsdata_file file_upload_html[] = {{file_img_screenshot_png, data_upload_html, data_upload_html + 13, sizeof(data_upload_html) - 13}};
+
+const struct httpd_fsdata_file file_404_html[] = {{file_upload_html, data_404_html, data_404_html + 10, sizeof(data_404_html) - 10}};
+
+const struct httpd_fsdata_file file_style_css[] = {{file_404_html, data_style_css, data_style_css + 11, sizeof(data_style_css) - 11}};
+
+const struct httpd_fsdata_file file_header_html[] = {{file_style_css, data_header_html, data_header_html + 13, sizeof(data_header_html) - 13}};
+
+const struct httpd_fsdata_file file_index_html[] = {{file_header_html, data_index_html, data_index_html + 12, sizeof(data_index_html) - 12}};
+
+const struct httpd_fsdata_file file_footer_html[] = {{file_index_html, data_footer_html, data_footer_html + 13, sizeof(data_footer_html) - 13}};
+
+const struct httpd_fsdata_file file_files_shtml[] = {{file_footer_html, data_files_shtml, data_files_shtml + 13, sizeof(data_files_shtml) - 13}};
+
+const struct httpd_fsdata_file file_processes_shtml[] = {{file_files_shtml, data_processes_shtml, data_processes_shtml + 17, sizeof(data_processes_shtml) - 17}};
+
+const struct httpd_fsdata_file file_tcp_shtml[] = {{file_processes_shtml, data_tcp_shtml, data_tcp_shtml + 11, sizeof(data_tcp_shtml) - 11}};
+
+#define HTTPD_FS_ROOT file_tcp_shtml
+
+#define HTTPD_FS_NUMFILES 10
diff --git a/contiki/apps/httpd-fsdata.h b/contiki/apps/httpd-fsdata.h
new file mode 100644
index 0000000..61708ed
--- /dev/null
+++ b/contiki/apps/httpd-fsdata.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: httpd-fsdata.h,v 1.2 2004/06/06 05:59:21 adamdunkels Exp $
+ */
+#ifndef __HTTPD_FSDATA_H__
+#define __HTTPD_FSDATA_H__
+
+#include "uipopt.h"
+
+struct httpd_fsdata_file {
+  const struct httpd_fsdata_file *next;
+  const char *name;
+  const char *data;
+  const int len;
+#ifdef HTTPD_FS_STATISTICS
+#if HTTPD_FS_STATISTICS == 1
+  u16_t count;
+#endif /* HTTPD_FS_STATISTICS */
+#endif /* HTTPD_FS_STATISTICS */
+};
+
+struct httpd_fsdata_file_noconst {
+  struct httpd_fsdata_file *next;
+  char *name;
+  char *data;
+  int len;
+#ifdef HTTPD_FS_STATISTICS
+#if HTTPD_FS_STATISTICS == 1
+  u16_t count;
+#endif /* HTTPD_FS_STATISTICS */
+#endif /* HTTPD_FS_STATISTICS */
+};
+
+#endif /* __HTTPD_FSDATA_H__ */
diff --git a/contiki/apps/httpd.c b/contiki/apps/httpd.c
new file mode 100644
index 0000000..caadc02
--- /dev/null
+++ b/contiki/apps/httpd.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: httpd.c,v 1.10 2007/06/02 07:32:06 ryohji Exp $
+ */
+
+#include "contiki.h"
+#include "httpd.h"
+#include "httpd-fs.h"
+#include "httpd-cgi.h"
+#include "psock.h"
+#include "http-strings.h"
+
+#include <string.h>
+
+#define STATE_WAITING 0
+#define STATE_OUTPUT  1
+
+#define SEND_STRING(s, str) PSOCK_SEND(s, str, strlen(str)) 
+MEMB(conns, sizeof(struct httpd_state), 8);
+
+#define ISO_nl      0x0a
+#define ISO_space   0x20
+#define ISO_bang    0x21
+#define ISO_percent 0x25
+#define ISO_period  0x2e
+#define ISO_slash   0x2f
+#define ISO_colon   0x3a
+
+
+/*---------------------------------------------------------------------------*/
+static unsigned short
+generate(void *state)
+{
+  struct httpd_state *s = (struct httpd_state *)state;
+
+  if(s->file.len > uip_mss()) {
+    s->len = uip_mss();
+  } else {
+    s->len = s->file.len;
+  }
+  memcpy(uip_appdata, s->file.data, s->len);
+  
+  return s->len;
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(send_file(struct httpd_state *s))
+{
+  PSOCK_BEGIN(&s->sout);
+  
+  do {
+    PSOCK_GENERATOR_SEND(&s->sout, generate, s);
+    s->file.len -= s->len;
+    s->file.data += s->len;
+  } while(s->file.len > 0);
+      
+  PSOCK_END(&s->sout);  
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(send_part_of_file(struct httpd_state *s))
+{
+  PSOCK_BEGIN(&s->sout);
+
+  PSOCK_SEND(&s->sout, s->file.data, s->len);
+  
+  PSOCK_END(&s->sout);  
+}
+/*---------------------------------------------------------------------------*/
+static void
+next_scriptstate(struct httpd_state *s)
+{
+  char *p;
+  p = strchr(s->scriptptr, ISO_nl) + 1;
+  s->scriptlen -= (unsigned short)(p - s->scriptptr);
+  s->scriptptr = p;
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_script(struct httpd_state *s))
+{
+  char *ptr;
+  
+  PT_BEGIN(&s->scriptpt);
+
+
+  while(s->file.len > 0) {
+
+    /* Check if we should start executing a script. */
+    if(*s->file.data == ISO_percent &&
+       *(s->file.data + 1) == ISO_bang) {
+      s->scriptptr = s->file.data + 3;
+      s->scriptlen = s->file.len - 3;
+      if(*(s->scriptptr - 1) == ISO_colon) {
+	httpd_fs_open(s->scriptptr + 1, &s->file);
+	PT_WAIT_THREAD(&s->scriptpt, send_file(s));       
+      } else {
+	PT_WAIT_THREAD(&s->scriptpt,
+		       httpd_cgi(s->scriptptr)(s, s->scriptptr));
+      }
+      next_scriptstate(s);
+      
+      /* The script is over, so we reset the pointers and continue
+	 sending the rest of the file. */
+      s->file.data = s->scriptptr;
+      s->file.len = s->scriptlen;
+    } else {
+      /* See if we find the start of script marker in the block of HTML
+	 to be sent. */
+
+      if(s->file.len > uip_mss()) {
+	s->len = uip_mss();
+      } else {
+	s->len = s->file.len;
+      }
+
+      if(*s->file.data == ISO_percent) {
+	ptr = strchr(s->file.data + 1, ISO_percent);
+      } else {
+	ptr = strchr(s->file.data, ISO_percent);
+      }
+      if(ptr != NULL &&
+	 ptr != s->file.data) {
+	s->len = (int)(ptr - s->file.data);
+	if(s->len >= uip_mss()) {
+	  s->len = uip_mss();
+	}
+      }
+      PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s));
+      s->file.data += s->len;
+      s->file.len -= s->len;
+      
+    }
+  }
+  
+  PT_END(&s->scriptpt);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
+{
+  static char *ptr;
+
+  PSOCK_BEGIN(&s->sout);
+
+  SEND_STRING(&s->sout, statushdr);
+
+  ptr = strrchr(s->filename, ISO_period);
+  if(ptr == NULL) {
+    SEND_STRING(&s->sout, http_content_type_binary);
+  } else if(strncmp(http_html, ptr, 5) == 0 ||
+	    strncmp(http_shtml, ptr, 6) == 0) {
+    SEND_STRING(&s->sout, http_content_type_html);
+  } else if(strncmp(http_css, ptr, 4) == 0) {
+    SEND_STRING(&s->sout, http_content_type_css);
+  } else if(strncmp(http_png, ptr, 4) == 0) {
+    SEND_STRING(&s->sout, http_content_type_png);
+  } else if(strncmp(http_gif, ptr, 4) == 0) {
+    SEND_STRING(&s->sout, http_content_type_gif);
+  } else if(strncmp(http_jpg, ptr, 4) == 0) {
+    SEND_STRING(&s->sout, http_content_type_jpg);	
+  } else {
+    SEND_STRING(&s->sout, http_content_type_plain);
+  }
+  PSOCK_END(&s->sout);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_output(struct httpd_state *s))
+{
+  char *ptr;
+  
+  PT_BEGIN(&s->outputpt);
+ 
+  if(!httpd_fs_open(s->filename, &s->file)) {
+    httpd_fs_open(http_404_html, &s->file);
+    PT_WAIT_THREAD(&s->outputpt,
+		   send_headers(s,
+		   http_header_404));
+    PT_WAIT_THREAD(&s->outputpt,
+		   send_file(s));
+  } else {
+    PT_WAIT_THREAD(&s->outputpt,
+		   send_headers(s,
+		   http_header_200));
+    ptr = strchr(s->filename, ISO_period);
+    if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) {
+      PT_INIT(&s->scriptpt);
+      PT_WAIT_THREAD(&s->outputpt, handle_script(s));
+    } else {
+      PT_WAIT_THREAD(&s->outputpt,
+		     send_file(s));
+    }
+  }
+  PSOCK_CLOSE(&s->sout);    
+  PT_END(&s->outputpt);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_input(struct httpd_state *s))
+{
+  PSOCK_BEGIN(&s->sin);
+
+  PSOCK_READTO(&s->sin, ISO_space);
+
+  
+  if(strncmp(s->inputbuf, http_get, 4) != 0) {
+    PSOCK_CLOSE_EXIT(&s->sin);
+  }
+  PSOCK_READTO(&s->sin, ISO_space);
+
+  if(s->inputbuf[0] != ISO_slash) {
+    PSOCK_CLOSE_EXIT(&s->sin);
+  }
+
+  if(s->inputbuf[1] == ISO_space) {
+    strncpy(s->filename, http_index_html, sizeof(s->filename));
+  } else {
+    s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
+    strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
+  }
+
+  httpd_log_file(uip_conn->ripaddr, s->filename);
+  
+  s->state = STATE_OUTPUT;
+
+  while(1) {
+    PSOCK_READTO(&s->sin, ISO_nl);
+
+    if(strncmp(s->inputbuf, http_referer, 8) == 0) {
+      s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
+      httpd_log(&s->inputbuf[9]);
+    }
+  }
+  
+  PSOCK_END(&s->sin);
+}
+/*---------------------------------------------------------------------------*/
+static void
+handle_connection(struct httpd_state *s)
+{
+  handle_input(s);
+  if(s->state == STATE_OUTPUT) {
+    handle_output(s);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+httpd_appcall(void *state)
+{
+  struct httpd_state *s = (struct httpd_state *)state;
+
+  if(uip_closed() || uip_aborted() || uip_timedout()) {
+    if(s != NULL) {
+      memb_free(&conns, s);
+    }
+  } else if(uip_connected()) {
+    s = (struct httpd_state *)memb_alloc(&conns);
+    if(s == NULL) {
+      uip_abort();
+      return;
+    }
+    tcp_markconn(uip_conn, s);
+    PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
+    PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
+    PT_INIT(&s->outputpt);
+    s->state = STATE_WAITING;
+    timer_set(&s->timer, CLOCK_SECOND * 100);
+    handle_connection(s);
+  } else if(s != NULL) {
+    if(uip_poll()) {
+      
+      if(timer_expired(&s->timer)) {
+	uip_abort();
+	memb_free(&conns, s);
+      }
+    } 
+    timer_restart(&s->timer);
+    handle_connection(s);
+  } else {
+    uip_abort();
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+httpd_init(void)
+{
+  tcp_listen(HTONS(80));
+  memb_init(&conns);
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/httpd.h b/contiki/apps/httpd.h
new file mode 100644
index 0000000..d722e8e
--- /dev/null
+++ b/contiki/apps/httpd.h
@@ -0,0 +1,65 @@
+/*
+ * 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. 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: httpd.h,v 1.8 2005/02/27 09:33:51 adamdunkels Exp $
+ *
+ */
+
+#ifndef __HTTPD_H__
+#define __HTTPD_H__
+
+#include "contiki.h"
+
+#include "psock.h"
+#include "httpd-fs.h"
+
+struct httpd_state {
+  struct timer timer;
+  struct psock sin, sout;
+  struct pt outputpt, scriptpt;
+  char inputbuf[50];
+  char filename[20];
+  char state;
+  struct httpd_fs_file file;  
+  int len;
+  char *scriptptr;
+  int scriptlen;
+
+  unsigned short count;
+};
+
+
+void httpd_init(void);
+void httpd_appcall(void *state);
+
+void httpd_log(char *msg);
+void httpd_log_file(u16_t *requester, char *file);
+
+#endif /* __HTTPD_H__ */
diff --git a/contiki/apps/irc-dsc.c b/contiki/apps/irc-dsc.c
new file mode 100644
index 0000000..28d653e
--- /dev/null
+++ b/contiki/apps/irc-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: irc-dsc.c,v 1.3 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon irc_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(irc_dsc,
+    "Internet Relay Chat client",
+    "irc.prg",
+    irc_init,
+    &irc_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char irc_icon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char irc_icon_textmap[9] = {
+  'I', 'R', 'C',
+  '-', '-', '-',
+  'I', 'R', 'C'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon irc_icon =
+  {CTK_ICON("IRC client", irc_icon_bitmap, irc_icon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/irc-dsc.h b/contiki/apps/irc-dsc.h
new file mode 100644
index 0000000..3f993b9
--- /dev/null
+++ b/contiki/apps/irc-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: irc-dsc.h,v 1.1 2004/09/01 19:11:42 adamdunkels Exp $
+ *
+ */
+#ifndef __IRC_DSC_H__
+#define __IRC_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(irc_dsc);
+
+#endif /* __IRC_DSC_H__ */
diff --git a/contiki/apps/irc.c b/contiki/apps/irc.c
new file mode 100644
index 0000000..948c391
--- /dev/null
+++ b/contiki/apps/irc.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: irc.c,v 1.9 2005/05/05 23:32:01 oliverschmidt Exp $
+ */
+
+#include "irc-conf.h"
+#include "contiki.h"
+#include "ircc.h"
+
+#include "ctk.h"
+#include "ctk-textedit.h"
+
+#include "petsciiconv.h"
+
+#include "ctk-textentry-cmdline.h"
+
+#include <string.h>
+
+#define LOG_WIDTH IRC_CONF_WIDTH
+#define LOG_HEIGHT IRC_CONF_HEIGHT
+/*
+#define LOG_WIDTH 78
+#define LOG_HEIGHT 21
+*/
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "IRC client", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static struct ctk_window window;
+static char log[LOG_WIDTH * LOG_HEIGHT];
+static char line[LOG_WIDTH*2];
+static struct ctk_label loglabel =
+  {CTK_LABEL(0, 0, LOG_WIDTH, LOG_HEIGHT, log)};
+static struct ctk_textentry lineedit =
+  {CTK_TEXTENTRY_INPUT(0, LOG_HEIGHT, LOG_WIDTH - 2, 1, line, sizeof(line) - 1,
+		       ctk_textentry_cmdline_input)};
+
+static struct ctk_window setupwindow;
+#define SETUPWINDOW_WIDTH 18
+#define SETUPWINDOW_HEIGHT 9
+#define MAX_SERVERLEN 32
+#define MAX_NICKLEN 16
+static u16_t serveraddr[2];
+static char server[MAX_SERVERLEN + 1];
+static char nick[MAX_NICKLEN + 1];
+static struct ctk_label serverlabel =
+  {CTK_LABEL(1, 1, 11, 1, "IRC server: ")};
+static struct ctk_textentry serverentry =
+  {CTK_TEXTENTRY(0, 2, 16, 1, server, MAX_SERVERLEN)};
+
+static struct ctk_label nicklabel =
+  {CTK_LABEL(1, 4, 13, 1, "IRC nickname: ")};
+static struct ctk_textentry nickentry =
+  {CTK_TEXTENTRY(0, 5, 16, 1, nick, MAX_NICKLEN)};
+
+static struct ctk_button connectbutton =
+  {CTK_BUTTON(0, 7, 7, "Connect")};
+static struct ctk_button quitbutton =
+  {CTK_BUTTON(12, 7, 4, "Quit")};
+
+/*static char nick[] = "asdf";
+  static char server[] = "efnet.demon.co.uk";*/
+
+static struct ircc_state s;
+
+/*---------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(irc_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+quit(void)
+{
+  ctk_window_close(&window);
+  ctk_window_close(&setupwindow);
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_text_output(struct ircc_state *s, char *text1, char *text2)
+{
+  char *ptr;
+  int len;
+  
+  if(text1 == NULL) {
+    text1 = "";
+  }
+  
+  if(text2 == NULL) {
+    text2 = "";
+  }
+  
+  /* Scroll previous entries upwards */
+  memcpy(log, &log[LOG_WIDTH], LOG_WIDTH * (LOG_HEIGHT - 1));
+
+  ptr = &log[LOG_WIDTH * (LOG_HEIGHT - 1)];
+  len = strlen(text1);
+
+  memset(ptr, 0, LOG_WIDTH);
+  strncpy(ptr, text1, LOG_WIDTH);
+  if(len < LOG_WIDTH) {
+    ptr += len;
+    *ptr = ':';
+    ++len;
+    if(LOG_WIDTH - len > 0) {
+      strncpy(ptr + 1, text2, LOG_WIDTH - len);
+    }
+  } else {
+    len = 0;
+  }
+
+  if(strlen(text2) > LOG_WIDTH - len) {
+    memcpy(log, &log[LOG_WIDTH], LOG_WIDTH * (LOG_HEIGHT - 1));
+    strncpy(&log[LOG_WIDTH * (LOG_HEIGHT - 1)],
+	    text2 + LOG_WIDTH - len, LOG_WIDTH);
+  }
+  CTK_WIDGET_REDRAW(&loglabel);
+  
+}
+/*---------------------------------------------------------------------------*/
+static void
+parse_line(void)
+{
+  int i;
+  for(i = 0; i < strlen(line); ++i) {
+    line[i] &= 0x7f;
+  }
+  
+  
+  if(line[0] == '/') {
+    if(strncmp(&line[1], "join", 4) == 0) {
+      ircc_join(&s, &line[6]);
+      ircc_text_output(&s, "Join", &line[6]);
+    } else if(strncmp(&line[1], "list", 4) == 0) {
+      ircc_list(&s);
+      ircc_text_output(&s, "Channel list", "");
+    } else if(strncmp(&line[1], "part", 4) == 0) {
+      ircc_part(&s);
+      ircc_text_output(&s, "Leaving channel", "");
+    } else if(strncmp(&line[1], "quit", 4) == 0) {
+      ircc_quit(&s);
+    } else if(strncmp(&line[1], "me", 2) == 0) {
+      petsciiconv_toascii(&line[4], strlen(&line[4]));
+      ircc_actionmsg(&s, &line[4]);
+      ircc_text_output(&s, "*", &line[4]);
+    } else {
+      ircc_text_output(&s, &line[1], "Not implemented");
+      ircc_sent(&s);
+    }
+  } else {
+    petsciiconv_toascii(line, sizeof(line) - 1);
+    ircc_msg(&s, &line[0]);
+    ircc_text_output(&s, nick, line);
+  }
+	   
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_sent(struct ircc_state *s)
+{
+  /*  ctk_textedit_init(&lineedit);*/
+  CTK_TEXTENTRY_CLEAR(&lineedit);
+  CTK_WIDGET_REDRAW(&lineedit);
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  ctk_arch_key_t c;
+  u16_t *ipaddr;
+  
+  if(ev == EK_EVENT_INIT) {
+    /*    ctk_textedit_init(&lineedit);*/
+    CTK_TEXTENTRY_CLEAR(&lineedit);
+    memset(log, 0, sizeof(log));
+    ctk_window_new(&window, LOG_WIDTH, LOG_HEIGHT + 1, "IRC");
+    CTK_WIDGET_ADD(&window, &loglabel);
+    /*    ctk_textedit_add(&window, &lineedit);    */
+    CTK_WIDGET_ADD(&window, &lineedit);
+    CTK_WIDGET_FOCUS(&window, &lineedit);
+
+    ctk_window_new(&setupwindow, SETUPWINDOW_WIDTH, SETUPWINDOW_HEIGHT,
+		   "IRC setup");
+
+    CTK_WIDGET_ADD(&setupwindow, &serverlabel);
+    CTK_WIDGET_ADD(&setupwindow, &serverentry);
+    CTK_WIDGET_ADD(&setupwindow, &nicklabel);
+    CTK_WIDGET_ADD(&setupwindow, &nickentry);
+    CTK_WIDGET_ADD(&setupwindow, &connectbutton);
+    CTK_WIDGET_ADD(&setupwindow, &quitbutton);
+
+    CTK_WIDGET_FOCUS(&setupwindow, &serverentry);
+
+    ctk_window_open(&setupwindow);
+
+  } else if(ev == EK_EVENT_REQUEST_EXIT) {
+    quit();
+  } else if(ev == ctk_signal_window_close) {
+    quit();
+  } else if(ev == tcpip_event) {
+    ircc_appcall(data);
+  } else if(ev == ctk_signal_widget_activate) {
+    if(data == (ek_data_t)&lineedit) {
+      parse_line();
+    } else if(data == (ek_data_t)&quitbutton) {
+      quit();
+    } else if(data == (ek_data_t)&connectbutton) {
+      ctk_window_close(&setupwindow);
+      ctk_window_open(&window);
+      ipaddr = serveraddr;
+      if(uiplib_ipaddrconv(server, (u8_t *)serveraddr) == 0) {
+	ipaddr = resolv_lookup(server);
+	if(ipaddr == NULL) {
+	  resolv_query(server);
+	} else {
+	  uip_ipaddr_copy(serveraddr, ipaddr);
+	}
+      }
+      if(ipaddr != NULL) {
+	       
+	ircc_connect(&s, server, serveraddr, nick);
+      }
+    }
+  } else if(ev == resolv_event_found) {
+
+    ipaddr = resolv_lookup(server);
+    if(ipaddr == NULL) {
+      ircc_text_output(&s, server, "hostname not found");
+    } else {
+      uip_ipaddr_copy(serveraddr, ipaddr);
+      ircc_connect(&s, server, serveraddr, nick);
+    }
+	       
+  } else if(ev == ctk_signal_keypress) {
+    c = (ctk_arch_key_t)data;
+    if(c == CH_ENTER) {
+      parse_line();
+    } else {
+      /*      ctk_textedit_eventhandler(&lineedit, ev, data);*/
+      CTK_WIDGET_FOCUS(&window, &lineedit);
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_closed(struct ircc_state *s)
+{
+  ircc_text_output(s, server, "connection closed");
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_connected(struct ircc_state *s)
+{
+  ircc_text_output(s, server, "connected");
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/ircc-strings b/contiki/apps/ircc-strings
new file mode 100644
index 0000000..92254a4
--- /dev/null
+++ b/contiki/apps/ircc-strings
@@ -0,0 +1,17 @@
+ircc_strings_nick "NICK "
+ircc_strings_crnl_user "\r\nUSER "
+ircc_strings_contiki " contiki "
+ircc_strings_colon_contiki " :Contiki\r\n"
+ircc_strings_join "JOIN "
+ircc_strings_crnl "\r\n"
+ircc_strings_part "PART "
+ircc_strings_list "LIST "
+ircc_strings_privmsg "PRIVMSG "
+ircc_strings_colon " :"
+ircc_strings_ping "PING "
+ircc_strings_notice "NOTICE "
+ircc_strings_action "\01ACTION "
+ircc_strings_version "\01VERSION"
+ircc_strings_version_query "\01VERSION\01"
+ircc_strings_ctcpcrnl "\01\r\n"
+ircc_strings_version_string " Contiki 1.2 "
\ No newline at end of file
diff --git a/contiki/apps/ircc-strings.c b/contiki/apps/ircc-strings.c
new file mode 100644
index 0000000..f23c9b6
--- /dev/null
+++ b/contiki/apps/ircc-strings.c
@@ -0,0 +1,51 @@
+const char ircc_strings_nick[6] = 
+/* "NICK " */
+{0x4e, 0x49, 0x43, 0x4b, 0x20, };
+const char ircc_strings_crnl_user[8] = 
+/* "\r\nUSER " */
+{0xd, 0xa, 0x55, 0x53, 0x45, 0x52, 0x20, };
+const char ircc_strings_contiki[10] = 
+/* " contiki " */
+{0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x20, };
+const char ircc_strings_colon_contiki[12] = 
+/* " :Contiki\r\n" */
+{0x20, 0x3a, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0xd, 0xa, };
+const char ircc_strings_join[6] = 
+/* "JOIN " */
+{0x4a, 0x4f, 0x49, 0x4e, 0x20, };
+const char ircc_strings_crnl[3] = 
+/* "\r\n" */
+{0xd, 0xa, };
+const char ircc_strings_part[6] = 
+/* "PART " */
+{0x50, 0x41, 0x52, 0x54, 0x20, };
+const char ircc_strings_list[6] = 
+/* "LIST " */
+{0x4c, 0x49, 0x53, 0x54, 0x20, };
+const char ircc_strings_privmsg[9] = 
+/* "PRIVMSG " */
+{0x50, 0x52, 0x49, 0x56, 0x4d, 0x53, 0x47, 0x20, };
+const char ircc_strings_colon[3] = 
+/* " :" */
+{0x20, 0x3a, };
+const char ircc_strings_ping[6] = 
+/* "PING " */
+{0x50, 0x49, 0x4e, 0x47, 0x20, };
+const char ircc_strings_notice[8] = 
+/* "NOTICE " */
+{0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, 0x20, };
+const char ircc_strings_action[9] = 
+/* "\01ACTION " */
+{0x1, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x20, };
+const char ircc_strings_version[9] = 
+/* "\01VERSION" */
+{0x1, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, };
+const char ircc_strings_version_query[10] = 
+/* "\01VERSION\01" */
+{0x1, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x1, };
+const char ircc_strings_ctcpcrnl[4] = 
+/* "\01\r\n" */
+{0x1, 0xd, 0xa, };
+const char ircc_strings_version_string[14] = 
+/* " Contiki 1.2 " */
+{0x20, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6b, 0x69, 0x20, 0x31, 0x2e, 0x32, 0x20, };
diff --git a/contiki/apps/ircc-strings.h b/contiki/apps/ircc-strings.h
new file mode 100644
index 0000000..7274829
--- /dev/null
+++ b/contiki/apps/ircc-strings.h
@@ -0,0 +1,17 @@
+extern const char ircc_strings_nick[6];
+extern const char ircc_strings_crnl_user[8];
+extern const char ircc_strings_contiki[10];
+extern const char ircc_strings_colon_contiki[12];
+extern const char ircc_strings_join[6];
+extern const char ircc_strings_crnl[3];
+extern const char ircc_strings_part[6];
+extern const char ircc_strings_list[6];
+extern const char ircc_strings_privmsg[9];
+extern const char ircc_strings_colon[3];
+extern const char ircc_strings_ping[6];
+extern const char ircc_strings_notice[8];
+extern const char ircc_strings_action[9];
+extern const char ircc_strings_version[9];
+extern const char ircc_strings_version_query[10];
+extern const char ircc_strings_ctcpcrnl[4];
+extern const char ircc_strings_version_string[14];
diff --git a/contiki/apps/ircc.c b/contiki/apps/ircc.c
new file mode 100644
index 0000000..98ce659
--- /dev/null
+++ b/contiki/apps/ircc.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ircc.c,v 1.9 2005/02/22 22:23:08 adamdunkels Exp $
+ */
+
+#include "contiki.h"
+#include "ircc.h"
+
+#include "irc-conf.h"
+
+#include "ircc-strings.h"
+
+#include "petsciiconv.h"
+
+#include <string.h>
+
+#define PORT 6667
+
+#define SEND_STRING(s, str) PSOCK_SEND(s, str, strlen(str))
+
+#define ISO_space 0x20
+#define ISO_bang  0x21
+#define ISO_at    0x40
+#define ISO_cr    0x0d
+#define ISO_nl    0x0a
+#define ISO_colon 0x3a
+#define ISO_O     0x4f
+
+enum {
+  COMMAND_NONE,
+  COMMAND_JOIN,
+  COMMAND_PART,  
+  COMMAND_MSG,
+  COMMAND_ACTIONMSG,
+  COMMAND_LIST,
+  COMMAND_QUIT
+};
+
+/*---------------------------------------------------------------------------*/
+void
+ircc_init(void)
+{
+
+}
+/*---------------------------------------------------------------------------*/
+static char *
+copystr(char *dest, const char *src, int n)
+{
+  int len;
+
+  len = strlen(src);
+  strncpy(dest, src, n);
+
+  if(len > n) {
+    return dest + n;
+  } else {
+    return dest + len;
+  }
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(setup_connection(struct ircc_state *s))
+{
+  char *ptr;
+
+  
+  PSOCK_BEGIN(&s->s);
+  
+  ptr = s->outputbuf;
+  ptr = copystr(ptr, ircc_strings_nick, sizeof(s->outputbuf));
+  ptr = copystr(ptr, s->nick, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, ircc_strings_crnl_user, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, s->nick, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, ircc_strings_contiki, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, s->server, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, ircc_strings_colon_contiki, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+
+  SEND_STRING(&s->s, s->outputbuf);
+
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(join_channel(struct ircc_state *s))
+{
+  PSOCK_BEGIN(&s->s);
+  
+  SEND_STRING(&s->s, ircc_strings_join);
+  SEND_STRING(&s->s, s->channel);
+  SEND_STRING(&s->s, ircc_strings_crnl);
+
+  ircc_sent(s);
+  
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(part_channel(struct ircc_state *s))
+{
+  PSOCK_BEGIN(&s->s);
+
+  SEND_STRING(&s->s, ircc_strings_part);
+  SEND_STRING(&s->s, s->channel);
+  SEND_STRING(&s->s, ircc_strings_crnl);
+
+  ircc_sent(s);
+  
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(list_channel(struct ircc_state *s))
+{
+  PSOCK_BEGIN(&s->s);
+
+  SEND_STRING(&s->s, ircc_strings_list);
+  SEND_STRING(&s->s, s->channel);
+  SEND_STRING(&s->s, ircc_strings_crnl);
+
+  ircc_sent(s);
+  
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(send_message(struct ircc_state *s))
+{
+  char *ptr;
+  
+  PSOCK_BEGIN(&s->s);
+
+  ptr = s->outputbuf;
+  ptr = copystr(ptr, ircc_strings_privmsg, sizeof(s->outputbuf));
+  ptr = copystr(ptr, s->channel, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, ircc_strings_colon, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, s->msg, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, ircc_strings_crnl, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+
+  SEND_STRING(&s->s, s->outputbuf);
+
+  ircc_sent(s);
+  
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(send_actionmessage(struct ircc_state *s))
+{
+  char *ptr;
+  
+  PSOCK_BEGIN(&s->s);
+
+  ptr = s->outputbuf;
+  ptr = copystr(ptr, ircc_strings_privmsg, sizeof(s->outputbuf));
+  ptr = copystr(ptr, s->channel, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, ircc_strings_colon, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, ircc_strings_action, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  ptr = copystr(ptr, s->msg, sizeof(s->outputbuf) - (ptr - s->outputbuf)); 
+  ptr = copystr(ptr, ircc_strings_ctcpcrnl, sizeof(s->outputbuf) - (ptr - s->outputbuf));
+  
+
+  SEND_STRING(&s->s, s->outputbuf);
+
+  ircc_sent(s);
+  
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+struct parse_result {
+  char *msg;
+  
+  char *user;
+  char *host;
+  char *name;
+  char *command;
+  char *middle;
+  char *trailing;
+};
+static struct parse_result r;
+static void
+parse_whitespace(void)
+{
+  while(*r.msg == ISO_space) ++r.msg;
+}
+static void
+parse_word(void)
+{
+  char *ptr;
+  ptr = strchr(r.msg, ISO_space);
+  if(ptr != NULL) {
+    r.msg = ptr;
+  }  
+}
+static void
+parse_user(void)
+{
+  parse_whitespace();
+  r.user = r.msg;
+  parse_word();
+  *r.msg = 0;
+  ++r.msg;
+}
+static void
+parse_host(void)
+{
+  parse_whitespace();
+  r.host = r.msg;
+  parse_word();
+  *r.msg = 0;
+  ++r.msg;
+}
+
+static void
+parse_name(void)
+{
+  parse_whitespace();
+  r.name = r.msg;
+  parse_word();
+  *r.msg = 0;
+  ++r.msg;
+}
+
+static void
+parse_prefix(void)
+{
+  parse_name();
+  if(*r.msg == ISO_bang) {
+    ++r.msg;
+    parse_user();
+  }
+  if(*r.msg == ISO_at) {
+    ++r.msg;
+    parse_host();
+  }
+}
+
+static void
+parse_command(void)
+{
+  parse_whitespace();
+  r.command = r.msg;
+  parse_word();
+  *r.msg = 0;
+  ++r.msg;
+}
+
+/*static void
+parse_trailing(void)
+{
+  r.trailing = r.msg;
+  while(*r.msg != 0 && *r.msg != ISO_cr && *r.msg != ISO_nl) ++r.msg;
+  *r.msg = 0;
+  ++r.msg;
+}*/
+
+static void
+parse_params(void)
+{
+  char *ptr;
+
+  parse_whitespace();
+  ptr = strchr(r.msg, ISO_colon);
+  if(ptr != NULL) {
+    r.trailing = ptr + 1;
+    ptr = strchr(ptr, ISO_cr);
+    if(ptr != NULL) {
+      *ptr = 0;
+    }
+  }
+}
+
+static void
+parse(char *msg, struct parse_result *dummy)
+{
+  r.msg = msg;
+  if(*r.msg == ISO_cr || *r.msg == ISO_nl) {
+    return;
+  }
+  if(*r.msg == ISO_colon) {
+    ++r.msg;
+    parse_prefix();
+  }
+  
+  parse_command();
+  parse_params();
+
+  /*  printf("user %s host %s name %s command %s middle %s trailing %s\n",
+      r.user, r.host, r.name, r.command, r.middle, r.trailing);*/
+}
+
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_input(struct ircc_state *s))
+{
+  char *ptr;
+  /*  struct parse_result r;*/
+  
+  PSOCK_BEGIN(&s->s);
+  
+  PSOCK_READTO(&s->s, ISO_nl);
+  
+  if(PSOCK_DATALEN(&s->s) > 0) {
+    
+    s->inputbuf[PSOCK_DATALEN(&s->s)] = 0;
+
+    if(strncmp(s->inputbuf, ircc_strings_ping, 5) == 0) {
+      strncpy(s->outputbuf, s->inputbuf, sizeof(s->outputbuf));
+      
+      /* Turn "PING" into "PONG" */
+      s->outputbuf[1] = ISO_O;
+      SEND_STRING(&s->s, s->outputbuf);
+    } else {
+
+      memset(&r, 0, sizeof(r));
+
+      parse(s->inputbuf, &r);
+
+      if(r.name != NULL) {
+	ptr = strchr(r.name, ISO_bang);
+	if(ptr != NULL) {
+	  *ptr = 0;
+	}
+      }
+      
+      if(r.command != NULL && strncmp(r.command, ircc_strings_join, 4) == 0) {
+	ircc_text_output(s, "Joined channel", r.name);
+      } else if(r.command != NULL && strncmp(r.command, ircc_strings_part, 4) == 0) {
+	ircc_text_output(s, "Left channel", r.name);
+      } else if(r.trailing != NULL) {
+	if(strncmp(r.trailing, ircc_strings_action,
+		   strlen(ircc_strings_action)) == 0) {
+	  ptr = strchr(&r.trailing[1], 1);
+	  if(ptr != NULL) {
+	    *ptr = 0;
+	  }
+	  ptr = &r.trailing[strlen(ircc_strings_action)];
+	  petsciiconv_topetscii(r.name, strlen(r.name));
+	  petsciiconv_topetscii(ptr, strlen(ptr));
+	  ircc_text_output(s, r.name, ptr);
+	} else if(strncmp(r.trailing, ircc_strings_version_query,
+			  strlen(ircc_strings_version_query)) == 0) {
+	  if(r.name != NULL) {
+	    strncpy(s->outputbuf, r.name, sizeof(s->outputbuf));
+	    SEND_STRING(&s->s, ircc_strings_notice);
+	    /* user is temporarily stored in outputbuf. */
+	    SEND_STRING(&s->s, s->outputbuf); 
+	    SEND_STRING(&s->s, ircc_strings_colon);
+	    SEND_STRING(&s->s, ircc_strings_version);
+	    SEND_STRING(&s->s, ircc_strings_version_string);
+	    SEND_STRING(&s->s, IRC_CONF_SYSTEM_STRING);
+	    SEND_STRING(&s->s, ircc_strings_ctcpcrnl);
+	  }
+	} else {
+	  petsciiconv_topetscii(r.name, strlen(r.name));
+	  petsciiconv_topetscii(r.trailing, strlen(r.trailing));
+	  ircc_text_output(s, r.name, r.trailing);
+	}
+      }
+    }
+  }
+
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(data_or_command(struct ircc_state *s))
+{
+  PSOCK_BEGIN(&s->s);
+
+  PSOCK_WAIT_UNTIL(&s->s, PSOCK_NEWDATA(&s->s) ||
+		    (s->command != COMMAND_NONE));
+
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_connection(struct ircc_state *s))
+{
+  PT_BEGIN(&s->pt);
+
+  PSOCK_INIT(&s->s, s->inputbuf, sizeof(s->inputbuf) - 1);
+  
+  PT_WAIT_THREAD(&s->pt, setup_connection(s));
+
+  while(1) {
+
+    PT_WAIT_UNTIL(&s->pt, data_or_command(s));
+
+    if(PSOCK_NEWDATA(&s->s)) {
+      PT_WAIT_THREAD(&s->pt, handle_input(s));      
+    } 
+      
+    switch(s->command) {
+    case COMMAND_JOIN:
+      s->command = COMMAND_NONE;
+      PT_WAIT_THREAD(&s->pt, join_channel(s));
+      break;
+    case COMMAND_PART:
+      s->command = COMMAND_NONE;
+      PT_WAIT_THREAD(&s->pt, part_channel(s));
+      break;
+    case COMMAND_MSG:
+      s->command = COMMAND_NONE;
+      PT_WAIT_THREAD(&s->pt, send_message(s));
+      break;
+    case COMMAND_ACTIONMSG:
+      s->command = COMMAND_NONE;
+      PT_WAIT_THREAD(&s->pt, send_actionmessage(s));
+      break;
+    case COMMAND_LIST:
+      s->command = COMMAND_NONE;
+      PT_WAIT_THREAD(&s->pt, list_channel(s));
+      break;
+    case COMMAND_QUIT:
+      s->command = COMMAND_NONE;
+      tcp_markconn(uip_conn, NULL);
+      PSOCK_CLOSE(&s->s);
+      ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_REQUEST_EXIT, NULL);
+      PT_EXIT(&s->pt);
+      break;
+    default:
+      break;
+    }
+  }
+  
+  PT_END(&s->pt);
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_appcall(void *s)
+{
+  if(uip_closed() || uip_aborted() || uip_timedout()) {
+    ircc_closed(s);
+  } else if(uip_connected()) {
+    ircc_connected(s);
+    PT_INIT(&((struct ircc_state *)s)->pt);
+    memset(((struct ircc_state *)s)->channel, 0,
+	   sizeof(((struct ircc_state *)s)->channel));
+    ((struct ircc_state *)s)->command = COMMAND_NONE;
+    handle_connection(s);
+  } else if(s != NULL) {
+    handle_connection(s);
+  }
+}
+/*---------------------------------------------------------------------------*/
+struct ircc_state *
+ircc_connect(struct ircc_state *s, char *servername, u16_t *ipaddr,
+	     char *nick)
+{
+  s->conn = tcp_connect(ipaddr, HTONS(PORT), s);
+  if(s->conn == NULL) {
+    return NULL;
+  }
+  s->server = servername;  
+  s->nick = nick;
+  return s;
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_list(struct ircc_state *s)
+{
+  s->command = COMMAND_LIST;
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_join(struct ircc_state *s, char *channel)
+{
+  strncpy(s->channel, channel, sizeof(s->channel));
+  s->command = COMMAND_JOIN;
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_part(struct ircc_state *s)
+{
+  s->command = COMMAND_PART;
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_quit(struct ircc_state *s)
+{
+  s->command = COMMAND_QUIT;
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_msg(struct ircc_state *s, char *msg)
+{
+  s->msg = msg;
+  s->command = COMMAND_MSG;
+}
+/*---------------------------------------------------------------------------*/
+void
+ircc_actionmsg(struct ircc_state *s, char *msg)
+{
+  s->msg = msg;
+  s->command = COMMAND_ACTIONMSG;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/ircc.h b/contiki/apps/ircc.h
new file mode 100644
index 0000000..7517294
--- /dev/null
+++ b/contiki/apps/ircc.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ircc.h,v 1.5 2005/02/22 22:23:08 adamdunkels Exp $
+ */
+#ifndef __IRCC_H__
+#define __IRCC_H__
+
+#include "psock.h"
+
+struct ircc_state {
+  
+  struct pt pt;
+  struct psock s;
+
+  struct uip_conn *conn;
+  
+  unsigned char command;
+  
+  char *msg;
+  char channel[32];
+  char outputbuf[200];
+  char inputbuf[400];
+  char *nick;
+  char *server;
+};
+
+void ircc_init(void);
+
+void ircc_appcall(void *s);
+
+struct ircc_state *ircc_connect(struct ircc_state *s,
+				char *server, u16_t *ipaddr, char *nick);
+
+void ircc_join(struct ircc_state *s, char *channel);
+void ircc_part(struct ircc_state *s);
+void ircc_list(struct ircc_state *s);
+void ircc_msg(struct ircc_state *s, char *msg);
+void ircc_actionmsg(struct ircc_state *s, char *msg);
+
+void ircc_sent(struct ircc_state *s);
+
+void ircc_text_output(struct ircc_state *s, char *text1, char *text2);
+
+void ircc_connected(struct ircc_state *s);
+void ircc_closed(struct ircc_state *s);
+
+void ircc_quit(struct ircc_state *s);
+
+#endif /* __IRCC_H__ */
diff --git a/contiki/apps/makefsdata b/contiki/apps/makefsdata
new file mode 100755
index 0000000..0ea353b
--- /dev/null
+++ b/contiki/apps/makefsdata
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+
+open(OUTPUT, "> httpd-fsdata.c");
+
+chdir("httpd-fs");
+
+opendir(DIR, ".");
+@files =  grep { !/^\./ && !/(CVS|~)/ } readdir(DIR);
+closedir(DIR);
+
+foreach $file (@files) {  
+   
+    if(-d $file && $file !~ /^\./) {
+	print "Processing directory $file\n";
+	opendir(DIR, $file);
+	@newfiles =  grep { !/^\./ && !/(CVS|~)/ } readdir(DIR);
+	closedir(DIR);
+	printf "Adding files @newfiles\n";
+	@files = (@files, map { $_ = "$file/$_" } @newfiles);
+	next;
+    }
+}
+
+foreach $file (@files) {  
+    if(-f $file) {
+	
+	print "Adding file $file\n";
+	
+	open(FILE, $file) || die "Could not open file $file\n";
+
+	$file =~ s-^-/-;
+	$fvar = $file;
+	$fvar =~ s-/-_-g;
+	$fvar =~ s-\.-_-g;
+	print(OUTPUT "static const unsigned char data".$fvar."[] = {\n");
+	print(OUTPUT "\t/* $file */\n\t");
+	for($j = 0; $j < length($file); $j++) {
+	    printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1)));
+	}
+	printf(OUTPUT "0,\n");
+	
+	
+	$i = 0;        
+	while(read(FILE, $data, 1)) {
+	    if($i == 0) {
+		print(OUTPUT "\t");
+	    }
+	    printf(OUTPUT "%#02x, ", unpack("C", $data));
+	    $i++;
+	    if($i == 10) {
+		print(OUTPUT "\n");
+		$i = 0;
+	    }
+	}
+	print(OUTPUT "0};\n\n");
+	close(FILE);
+	push(@fvars, $fvar);
+	push(@pfiles, $file);
+    }
+}
+
+for($i = 0; $i < @fvars; $i++) {
+    $file = $pfiles[$i];
+    $fvar = $fvars[$i];
+
+    if($i == 0) {
+        $prevfile = "NULL";
+    } else {
+        $prevfile = "file" . $fvars[$i - 1];
+    }
+    print(OUTPUT "const struct httpd_fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, ");
+    print(OUTPUT "data$fvar + ". (length($file) + 1) .", ");
+    print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n");
+}
+
+print(OUTPUT "#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n");
+print(OUTPUT "#define HTTPD_FS_NUMFILES $i\n");
diff --git a/contiki/apps/makestrings b/contiki/apps/makestrings
new file mode 100755
index 0000000..3c2ef1c
--- /dev/null
+++ b/contiki/apps/makestrings
@@ -0,0 +1,45 @@
+#!/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/\\01/\01/g;      
+      $datan =~ s/\\0/\0/g;
+      
+      printf(OUTPUTC "const 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 const char $var\[%d];\n", length($datan) + 1);
+      
+    }
+  }
+  close(OUTPUTC);
+  close(OUTPUTH);
+}
+stringify("http-strings");
+stringify("http-user-agent-string");
+stringify("smtp-strings");
+stringify("html-strings");
+stringify("ircc-strings");
+stringify("popc-strings");
+
+exit 0;
+
diff --git a/contiki/apps/netconf-dsc.c b/contiki/apps/netconf-dsc.c
new file mode 100644
index 0000000..b0eb087
--- /dev/null
+++ b/contiki/apps/netconf-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: netconf-dsc.c,v 1.4 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon netconf_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(netconf_dsc,
+    "Network configuration",
+    "netconf.prg",
+    netconf_init,
+    &netconf_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char tcpipconficon_textmap[9] = {
+  'T', 'C', 'P',
+  '/', 'I', 'P',
+  'C', 'f', 'g'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon netconf_icon =
+  {CTK_ICON("Network setup", tcpipconficon_bitmap, tcpipconficon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/netconf-dsc.h b/contiki/apps/netconf-dsc.h
new file mode 100644
index 0000000..86f17cc
--- /dev/null
+++ b/contiki/apps/netconf-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: netconf-dsc.h,v 1.1 2003/04/17 19:00:00 adamdunkels Exp $
+ *
+ */
+#ifndef __NETCONF_DSC_H__
+#define __NETCONF_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(netconf_dsc);
+
+#endif /* __NETCONF_DSC_H__ */
diff --git a/contiki/apps/netconf.c b/contiki/apps/netconf.c
new file mode 100644
index 0000000..5a0795e
--- /dev/null
+++ b/contiki/apps/netconf.c
@@ -0,0 +1,265 @@
+/*
+ * 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. 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: netconf.c,v 1.13 2004/07/04 11:35:07 adamdunkels Exp $
+ *
+ */
+
+#include "ek.h"
+#include "uip.h"
+#include "uiplib.h"
+#include "uip_arp.h"
+#include "resolv.h"
+#include "ctk.h"
+#include "ctk-draw.h"
+
+#include "loader.h"
+
+/* 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")};
+
+EK_EVENTHANDLER(netconf_eventhandler, ev, data);
+EK_PROCESS(p, "Network configuration", EK_PRIO_NORMAL,
+	   netconf_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*static DISPATCHER_SIGHANDLER(netconf_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Network config", NULL, netconf_sighandler, NULL)};
+  static ek_id_t id;*/
+
+
+static void makestrings(void);
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(netconf_init, arg)
+{
+  arg_free(arg);
+    
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static char *
+makebyte(u8_t byte, char *str)
+{
+  if(byte >= 100) {
+    *str++ = (byte / 100 ) % 10 + '0';
+  }
+  if(byte >= 10) {
+    *str++ = (byte / 10) % 10 + '0';
+  }
+  *str++ = (byte % 10) + '0';
+
+  return str;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+makeaddr(u16_t *addr, char *str)
+{
+  str = makebyte(HTONS(addr[0]) >> 8, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[0]) & 0xff, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[1]) >> 8, str);
+  *str++ = '.';
+  str = makebyte(HTONS(addr[1]) & 0xff, str);
+  *str++ = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+makestrings(void)
+{
+  u16_t addr[2], *addrptr;
+
+#ifdef WITH_UIP
+  uip_gethostaddr(addr);
+  makeaddr(addr, ipaddr);
+  
+#ifdef WITH_ETHERNET  
+  uip_getnetmask(addr);
+  makeaddr(addr, netmask);
+  
+  uip_getdraddr(addr);
+  makeaddr(addr, gateway);
+#endif /* WITH_ETHERNET */
+
+  addrptr = resolv_getserver();
+  if(addrptr != NULL) {
+    makeaddr(addrptr, dnsserver);
+  }
+  
+#endif /* WITH_UIP */
+
+}
+/*-----------------------------------------------------------------------------------*/
+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(uiplib_ipaddrconv(ipaddr, (unsigned char *)addr)) {
+    uip_sethostaddr(addr);
+  }
+  
+#ifdef WITH_ETHERNET
+  nullterminate(netmask);
+  if(uiplib_ipaddrconv(netmask, (unsigned char *)addr)) {
+    uip_setnetmask(addr);
+  }
+
+  nullterminate(gateway);
+  if(uiplib_ipaddrconv(gateway, (unsigned char *)addr)) {
+    uip_setdraddr(addr);
+  }
+#endif /* WITH_ETHERNET */
+  
+  nullterminate(dnsserver);
+  if(uiplib_ipaddrconv(dnsserver, (unsigned char *)addr)) {
+    resolv_conf(addr);
+  }
+#endif /* WITH_UIP */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+netconf_quit(void)
+{
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(netconf_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    /* Create TCP/IP configuration window. */
+    ctk_window_new(&tcpipwindow, 30, 10, "TCP/IP config");
+    /*    if(ctk_desktop_width(tcpipwindow.desktop) < 30) {
+      ctk_window_move(&tcpipwindow, 0,
+		      (ctk_desktop_height(tcpipwindow.desktop) - 10) / 2 - 2);
+    } else {
+      ctk_window_move(&tcpipwindow,
+		      (ctk_desktop_width(tcpipwindow.desktop) - 30) / 2,
+		      (ctk_desktop_height(tcpipwindow.desktop) - 10) / 2 - 2);
+		      }*/
+    
+#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);  
+
+    /* Fill the configuration strings with values from the current
+       configuration */
+    makestrings();
+    
+    /*    dispatcher_listen(ctk_signal_button_activate);
+	  dispatcher_listen(ctk_signal_window_close);*/
+    ctk_window_open(&tcpipwindow);
+  } else if(ev == ctk_signal_button_activate) {   
+    if(data == (ek_data_t)&tcpipclosebutton) {
+      apply_tcpipconfig();
+      ctk_window_close(&tcpipwindow);
+      netconf_quit();
+      /*      ctk_desktop_redraw(tcpipwindow.desktop);*/
+    }
+  } else if(ev == ctk_signal_window_close ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    ctk_window_close(&tcpipwindow);
+    netconf_quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/popc-strings b/contiki/apps/popc-strings
new file mode 100644
index 0000000..1a299f5
--- /dev/null
+++ b/contiki/apps/popc-strings
@@ -0,0 +1,5 @@
+popc_strings_user "USER "
+popc_strings_pass "PASS "
+popc_strings_retr "RETR "
+popc_strings_stat "STAT\r\n"
+popc_strings_crnl "\r\n"
\ No newline at end of file
diff --git a/contiki/apps/popc-strings.c b/contiki/apps/popc-strings.c
new file mode 100644
index 0000000..d05f1c1
--- /dev/null
+++ b/contiki/apps/popc-strings.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: popc-strings.c,v 1.2 2004/09/12 20:24:54 adamdunkels Exp $
+ */
+const char popc_strings_user[6] = 
+/* "USER " */
+{0x55, 0x53, 0x45, 0x52, 0x20, };
+const char popc_strings_pass[6] = 
+/* "PASS " */
+{0x50, 0x41, 0x53, 0x53, 0x20, };
+const char popc_strings_retr[6] = 
+/* "RETR " */
+{0x52, 0x45, 0x54, 0x52, 0x20, };
+const char popc_strings_stat[7] = 
+/* "STAT\r\n" */
+{0x53, 0x54, 0x41, 0x54, 0xd, 0xa, };
+const char popc_strings_crnl[3] = 
+/* "\r\n" */
+{0xd, 0xa, };
diff --git a/contiki/apps/popc-strings.h b/contiki/apps/popc-strings.h
new file mode 100644
index 0000000..e679bfb
--- /dev/null
+++ b/contiki/apps/popc-strings.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: popc-strings.h,v 1.2 2004/09/12 20:24:54 adamdunkels Exp $
+ */
+extern const char popc_strings_user[6];
+extern const char popc_strings_pass[6];
+extern const char popc_strings_retr[6];
+extern const char popc_strings_stat[7];
+extern const char popc_strings_crnl[3];
diff --git a/contiki/apps/popc.c b/contiki/apps/popc.c
new file mode 100644
index 0000000..d1ac150
--- /dev/null
+++ b/contiki/apps/popc.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: popc.c,v 1.3 2005/02/22 22:23:08 adamdunkels Exp $
+ */
+
+#include "contiki.h"
+#include "popc.h"
+#include "popc-strings.h"
+
+#define SEND_STRING(s, str) PSOCK_SEND(s, str, strlen(str))
+
+enum {
+  COMMAND_NONE,
+  COMMAND_RETR,
+  COMMAND_TOP,  
+  COMMAND_QUIT
+};
+
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(init_connection(struct popc_state *s))
+{
+  PSOCK_BEGIN(&s->s);
+
+  PSOCK_READTO(&s->s, '\n');
+  if(s->inputbuf[0] != '+') {
+    PSOCK_CLOSE_EXIT(&s->s);    
+  }
+
+  SEND_STRING(&s->s, popc_strings_user);
+  SEND_STRING(&s->s, s->user);
+  SEND_STRING(&s->s, popc_strings_crnl);
+  
+  PSOCK_READTO(&s->s, '\n');
+  if(s->inputbuf[0] != '+') {
+    PSOCK_CLOSE_EXIT(&s->s);    
+  }
+
+  SEND_STRING(&s->s, popc_strings_pass);
+  SEND_STRING(&s->s, s->pass);
+  SEND_STRING(&s->s, popc_strings_crnl);
+  
+  PSOCK_READTO(&s->s, '\n');
+  if(s->inputbuf[0] != '+') {
+    PSOCK_CLOSE_EXIT(&s->s);    
+  }
+
+  popc_connected(s);
+
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(stat(struct popc_state *s))
+{
+  unsigned short num;
+  unsigned long size;
+  char *ptr;
+  
+  PSOCK_BEGIN(&s->s);
+  
+  SEND_STRING(&s->s, popc_strings_stat);
+  
+  PSOCK_READTO(&s->s, '\n');
+  if(s->inputbuf[0] != '+') {
+    PSOCK_CLOSE_EXIT(&s->s);    
+  }
+
+  num = 0;
+  for(ptr = &s->inputbuf[4]; *ptr >= '0' && *ptr <= '9'; ++ptr) {
+    num *= 10;
+    num += *ptr - '0';
+  }
+
+  size = 0;
+  for(ptr = ptr + 1; *ptr >= '0' && *ptr <= '9'; ++ptr) {
+    size *= 10;
+    size += *ptr - '0';
+  }
+
+  popc_messages(s, num, size);
+
+  PSOCK_END(&s->s);
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(retr(struct popc_state *s))
+{
+  PSOCK_BEGIN(&s->s);
+
+  SEND_STRING(&s->s, popc_strings_retr);
+  snprintf(s->outputbuf, sizeof(s->outputbuf), "%d", s->num);
+  SEND_STRING(&s->s, s->outputbuf);
+  SEND_STRING(&s->s, popc_strings_crnl);
+  
+  PSOCK_READTO(&s->s, '\n');
+  if(s->inputbuf[0] != '+') {
+    PSOCK_CLOSE_EXIT(&s->s);    
+  }
+
+  popc_msgbegin(s);
+  while(s->inputbuf[0] != '.') {
+    PSOCK_READTO(&s->s, '\n');
+    if(s->inputbuf[0] != '.') {
+      s->inputbuf[PSOCK_DATALEN(&s->s)] = 0;
+      popc_msgline(s, s->inputbuf, PSOCK_DATALEN(&s->s));
+    }
+  }
+  popc_msgend(s);
+  
+  PSOCK_END(&s->s);
+
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_connection(struct popc_state *s))
+{
+  PT_BEGIN(&s->pt);
+
+  PSOCK_INIT(&s->s, s->inputbuf, sizeof(s->inputbuf) - 1);
+
+  PT_WAIT_UNTIL(&s->pt, init_connection(s));
+  PT_WAIT_UNTIL(&s->pt, stat(s));  
+
+  timer_set(&s->timer, CLOCK_SECOND * 30);
+	
+  while(1) {
+    PT_WAIT_UNTIL(&s->pt, s->command != COMMAND_NONE ||
+		  timer_expired(&s->timer));
+
+    if(timer_expired(&s->timer)) {
+      PT_WAIT_UNTIL(&s->pt, stat(s));
+      timer_set(&s->timer, CLOCK_SECOND * 30);
+    }
+
+    switch(s->command) {
+    case COMMAND_RETR:
+      PT_WAIT_UNTIL(&s->pt, retr(s));
+      break;
+    case COMMAND_QUIT:
+      tcp_markconn(uip_conn, NULL);
+      PSOCK_CLOSE(&s->s);
+      PT_EXIT(&s->pt);
+      break;
+    default:
+      break;
+    }
+    s->command = COMMAND_NONE;
+    
+  }
+  PT_END(&s->pt);
+}
+/*---------------------------------------------------------------------------*/
+void
+popc_appcall(void *state)
+{
+  struct popc_state *s = (struct popc_state *)state;
+  
+  if(uip_closed() || uip_aborted() || uip_timedout()) {
+    popc_closed(s);
+  } else if(uip_connected()) {
+    PT_INIT(&s->pt);
+    handle_connection(s);
+  } else if(s != NULL) {
+    handle_connection(s);
+  }
+
+}
+/*---------------------------------------------------------------------------*/
+void *
+popc_connect(struct popc_state *s, u16_t *addr,
+	     char *user, char *pass)
+{
+  strncpy(s->user, user, sizeof(s->user));
+  strncpy(s->pass, pass, sizeof(s->pass));
+  s->conn = tcp_connect(addr, HTONS(110), s);
+  return s->conn;
+}
+/*---------------------------------------------------------------------------*/
+void
+popc_retr(struct popc_state *s, unsigned short num)
+{
+  s->command = COMMAND_RETR;
+  s->num = num;
+}
+/*---------------------------------------------------------------------------*/
+void
+popc_top(struct popc_state *s, unsigned short num, unsigned short lines)
+{
+  s->command = COMMAND_TOP;
+  s->num = num;
+  s->lines = lines;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/apps/popc.h b/contiki/apps/popc.h
new file mode 100644
index 0000000..42e59af
--- /dev/null
+++ b/contiki/apps/popc.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: popc.h,v 1.3 2005/02/22 22:23:08 adamdunkels Exp $
+ */
+#ifndef __POPC_H__
+#define __POPC_H__
+
+#include "psock.h"
+
+
+struct popc_state {
+  struct pt pt;
+  struct psock s;
+  struct uip_conn *conn;
+
+  struct timer timer;
+  
+  char inputbuf[100];
+  char outputbuf[10];
+  
+  char user[32], pass[32];
+
+  char command;
+  unsigned short num;
+  unsigned short lines;
+};
+
+void popc_appcall(void *state);
+void popc_init(void);
+void *popc_connect(struct popc_state *s, u16_t *ipaddr, 
+		  char *user, char *passwd);
+
+void popc_retr(struct popc_state *s, unsigned short msg);
+void popc_top(struct popc_state *s, unsigned short msg,
+	      unsigned short numlines);
+
+
+void popc_connected(struct popc_state *s);
+void popc_messages(struct popc_state *s,
+		   unsigned short num, unsigned long size);
+void popc_msgbegin(struct popc_state *s);
+void popc_msgline(struct popc_state *s, char *line, int len);
+void popc_msgend(struct popc_state *s);
+
+
+#endif /* __POPC_H__ */
diff --git a/contiki/apps/processes-dsc.c b/contiki/apps/processes-dsc.c
new file mode 100644
index 0000000..7315828
--- /dev/null
+++ b/contiki/apps/processes-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: processes-dsc.c,v 1.5 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon processes_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(processes_dsc,
+    "Process information",
+    "processes.prg",
+    processes_init,
+    &processes_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char processesicon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char processesicon_textmap[9] = {
+  '0', '1', ' ',
+  ' ', '0', '1',
+  '1', '0', '/'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon processes_icon =
+  {CTK_ICON("Processes", processesicon_bitmap, processesicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/processes-dsc.h b/contiki/apps/processes-dsc.h
new file mode 100644
index 0000000..a00c0d8
--- /dev/null
+++ b/contiki/apps/processes-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: processes-dsc.h,v 1.1 2003/04/17 19:00:00 adamdunkels Exp $
+ *
+ */
+#ifndef __PROCESSES_DSC_H__
+#define __PROCESSES_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(processes_dsc);
+
+#endif /* __PROCESSES_DSC_H__ */
diff --git a/contiki/apps/processes.c b/contiki/apps/processes.c
new file mode 100644
index 0000000..a5fe420
--- /dev/null
+++ b/contiki/apps/processes.c
@@ -0,0 +1,207 @@
+/*
+ * 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. 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: processes.c,v 1.14 2005/03/13 22:14:43 oliverschmidt Exp $
+ *
+ */
+
+#include "ek.h"
+#include "ctk.h"
+#include "loader.h"
+
+#include <string.h>
+
+#define MAX_PROCESSLABELS 13
+static struct ctk_window processwindow;
+static unsigned char ids[MAX_PROCESSLABELS][4];
+static struct ctk_label processidlabels[MAX_PROCESSLABELS];
+static struct ctk_label processnamelabels[MAX_PROCESSLABELS];
+
+static struct ctk_label killlabel =
+  {CTK_LABEL(0, 14, 12, 1, "Kill process")};
+static char killprocnum[4];
+static struct ctk_textentry killtextentry =
+  {CTK_TEXTENTRY(13, 14, 3, 1, killprocnum, 3)};
+static struct ctk_button killbutton =
+  {CTK_BUTTON(19, 14, 2, "Ok")};
+static struct ctk_button processupdatebutton =
+  {CTK_BUTTON(0, 15, 6, "Update")};
+static struct ctk_button processclosebutton =
+  {CTK_BUTTON(19, 15, 5, "Close")};
+
+/*static DISPATCHER_SIGHANDLER(processes_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Process listing", NULL, processes_sighandler, NULL)};
+  static ek_id_t id;*/
+EK_EVENTHANDLER(processes_eventhandler, ev, data);
+EK_PROCESS(p, "Process listing", EK_PRIO_NORMAL,
+	   processes_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+enum {
+  EVENT_UPDATE
+};
+
+/*-----------------------------------------------------------------------------------*/
+static void
+update_processwindow(void)
+{
+  unsigned char i, j, *idsptr;
+  struct ek_proc *p;
+
+  /* Step through each possible process ID and see if there is a
+     matching process. */
+  j = 0;
+  for(p = EK_PROCS(); p != NULL && j < MAX_PROCESSLABELS; p = p->next) {
+    idsptr = ids[j];
+    i = p->id;
+    idsptr[0] = '0' + i / 100;
+    if(idsptr[0] == '0') {
+      idsptr[0] = ' ';
+    }
+    idsptr[1] = '0' + (i / 10) % 10;
+    idsptr[2] = '0' + i % 10;
+    idsptr[3] = 0;
+    CTK_LABEL_NEW(&processidlabels[j],
+		  0, j + 1, 3, 1, idsptr);
+    CTK_WIDGET_ADD(&processwindow, &processidlabels[j]);
+    
+    CTK_LABEL_NEW(&processnamelabels[j],
+		  4, j + 1, 22, 1, (char *)p->name);
+    CTK_WIDGET_ADD(&processwindow, &processnamelabels[j]);
+
+    ++j;
+  }
+
+  CTK_WIDGET_ADD(&processwindow, &killlabel);
+
+  CTK_WIDGET_ADD(&processwindow, &killtextentry);
+  CTK_WIDGET_ADD(&processwindow, &killbutton);  
+  
+  CTK_WIDGET_ADD(&processwindow, &processupdatebutton);
+  CTK_WIDGET_ADD(&processwindow, &processclosebutton);
+  CTK_WIDGET_FOCUS(&processwindow, &processupdatebutton);
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(processes_init, arg)
+{
+  arg_free(arg);
+    
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }    
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+processes_quit(void)
+{
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+killproc(void)
+{
+  int procnum;
+  unsigned char i, j;
+  struct ek_proc *p;
+  
+  /* Find first zero char in killprocnum string. */
+  for(i = 0; killprocnum[i] != 0 &&
+	i < sizeof(killprocnum); ++i);
+
+  if(i == 0) {
+    return;
+  }
+  
+  procnum = 0;
+  
+  for(j = 0; j < i; ++j) {
+    procnum = procnum * 10 + (killprocnum[j] - '0');
+    killprocnum[j] = 0;
+  }
+
+  /* Make sure the process ID exists. */
+  for(p = EK_PROCS(); p != NULL; p = p->next) {
+    if(EK_PROC_ID(p) == procnum) {
+      break;
+    }
+  }
+
+  if(p != NULL) {
+    ek_post(procnum, EK_EVENT_REQUEST_EXIT, NULL);
+    ek_post(id, EVENT_UPDATE, NULL);
+    CTK_TEXTENTRY_CLEAR(&killtextentry);
+    CTK_WIDGET_REDRAW(&killtextentry);
+    CTK_WIDGET_FOCUS(&processwindow, &processupdatebutton);
+    CTK_WIDGET_REDRAW(&killbutton);
+    CTK_WIDGET_REDRAW(&processupdatebutton);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/*static
+  DISPATCHER_SIGHANDLER(processes_sighandler, s, data)*/
+EK_EVENTHANDLER(processes_eventhandler, ev, data)
+{
+/*  DISPATCHER_SIGHANDLER_ARGS(s, data);*/
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&processwindow, 26, 16, "Processes");
+    update_processwindow();
+    
+    ctk_window_open(&processwindow);
+  } else if(ev == EVENT_UPDATE) {
+    ctk_window_clear(&processwindow);
+    update_processwindow();
+    ctk_window_open(&processwindow);
+  } else if(ev == ctk_signal_button_activate) {
+    if(data == (ek_data_t)&processupdatebutton) {
+      ctk_window_clear(&processwindow);
+      update_processwindow();
+      ctk_window_open(&processwindow);
+    } else if(data == (ek_data_t)&processclosebutton) {
+      ctk_window_close(&processwindow);
+      processes_quit();
+      /*      ctk_desktop_redraw(processwindow.desktop);      */
+    } else if(data == (ek_data_t)&killbutton) {
+      killproc();
+    }
+  } else if(ev == EK_EVENT_REQUEST_EXIT ||
+	    (ev == ctk_signal_window_close &&
+	     data == (ek_data_t)&processwindow)) {
+    ctk_window_close(&processwindow);
+    processes_quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/program-handler.c b/contiki/apps/program-handler.c
new file mode 100644
index 0000000..9d15e23
--- /dev/null
+++ b/contiki/apps/program-handler.c
@@ -0,0 +1,450 @@
+/**
+ * \file
+ * The program handler, used for loading programs and starting the
+ * screensaver. 
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * The Contiki program handler is responsible for the Contiki menu and
+ * the desktop icons, as well as for loading programs and displaying a
+ * dialog with a message telling which program that is loading.
+ *
+ * The program handler also is responsible for starting the
+ * screensaver when the CTK detects that it should be started.
+ */
+ 
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: program-handler.c,v 1.32 2006/05/14 23:23:30 oliverschmidt Exp $
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "ek.h"
+#include "petsciiconv.h"
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ctk-conf.h"
+
+#include "log.h"
+
+#include "loader.h"
+
+#include "program-handler.h"
+
+#include "program-handler-conf.h"
+
+/* Menus */
+static struct ctk_menu contikimenu;
+
+#ifndef PROGRAM_HANDLER_CONF_MAX_NUMDSCS
+#define MAX_NUMDSCS 10
+#else /* PROGRAM_HANDLER_CONF_MAX_NUMDSCS */
+#define MAX_NUMDSCS PROGRAM_HANDLER_CONF_MAX_NUMDSCS
+#endif /* PROGRAM_HANDLER_CONF_MAX_NUMDSCS */
+
+static struct dsc *contikidsc[MAX_NUMDSCS];
+static unsigned char contikidsclast = 0;
+
+#ifndef PROGRAM_HANDLER_CONF_QUIT_MENU
+#define QUIT_MENU 0
+#else /* PROGRAM_HANDLER_CONF_QUIT_MENU */
+#define QUIT_MENU PROGRAM_HANDLER_CONF_QUIT_MENU
+#endif /* PROGRAM_HANDLER_CONF_QUIT_MENU */
+
+#if QUIT_MENU
+
+static unsigned char quitmenuitem;
+
+/* "Quit" dialog */
+static struct ctk_window quitdialog;
+static struct ctk_label quitdialoglabel =
+  {CTK_LABEL(2, 1, 20, 1, "Really quit Contiki?")};
+static struct ctk_button quityesbutton =
+  {CTK_BUTTON(4, 3, 3, "Yes")};
+static struct ctk_button quitnobutton =
+  {CTK_BUTTON(16, 3, 2, "No")};
+
+#endif /* QUIT_MENU */
+
+#if WITH_LOADER_ARCH
+
+/* "Run..." window */
+static struct ctk_window runwindow;
+static unsigned char runmenuitem;
+static struct ctk_label namelabel =
+  {CTK_LABEL(0, 0, 13, 1, "Program name:")};
+static char name[31];
+static struct ctk_textentry nameentry =
+  {CTK_TEXTENTRY(0, 1, 14, 1, name, 30)};
+static struct ctk_button loadbutton =
+  {CTK_BUTTON(10, 2, 4, "Load")};
+
+static struct ctk_window loadingdialog;
+static struct ctk_label loadingmsg =
+  {CTK_LABEL(0, 0, 8, 1, "Starting")};
+static struct ctk_label loadingname =
+  {CTK_LABEL(9, 0, 16, 1, name)};
+
+static struct ctk_window errordialog;
+static struct ctk_label errormsg =
+  {CTK_LABEL(0, 1, 22, 1, "Error loading program:")};
+static char errorfilename[22];
+static struct ctk_label errorfilelabel =
+  {CTK_LABEL(0, 3, 22, 1, errorfilename)};
+static struct ctk_label errortype =
+  {CTK_LABEL(4, 5, 16, 1, "")};
+static struct ctk_button errorokbutton =
+  {CTK_BUTTON(9, 7, 2, "Ok")};
+
+#endif /* WITH_LOADER_ARCH */
+
+/*static DISPATCHER_SIGHANDLER(program_handler_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Program handler", NULL, program_handler_sighandler, NULL)};
+  static ek_id_t id;*/
+EK_EVENTHANDLER(program_handler_eventhandler, ev, data);
+EK_PROCESS(p, "Program handler", EK_PRIO_NORMAL,
+	   program_handler_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static const char * const errormsgs[] = {
+  "Ok",
+  "Read error",
+  "Header error",
+  "OS error",
+  "Data format error",
+  "Out of memory",
+  "File not found",
+  "No loader"
+};
+
+#define LOADER_EVENT_LOAD 1
+#define LOADER_EVENT_DISPLAY_NAME 2
+
+static char *displayname;
+
+#if CTK_CONF_SCREENSAVER
+char program_handler_screensaver[20];
+#endif /* CTK_CONF_SCREENSAVER */
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Add a program to the program handler.
+ *
+ * \param dsc The DSC description structure for the program to be added.
+ *
+ * \param menuname The name that the program should have in the
+ * Contiki menu.
+ *
+ * \param desktop Flag which specifies if the program should show up
+ * as an icon on the desktop or not.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+program_handler_add(struct dsc *dsc, char *menuname,
+		    unsigned char desktop)
+{
+  contikidsc[contikidsclast++] = dsc;
+  ctk_menuitem_add(&contikimenu, menuname);
+  if(desktop) {
+    CTK_ICON_ADD(dsc->icon, id);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Initializes the program handler.
+ *
+ * Is called by the initialization before any programs have been added
+ * with program_handler_add().
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+program_handler_init(void)     
+{
+  id = ek_start(&p);
+  ctk_menu_new(&contikimenu, "Contiki");  
+}
+/*-----------------------------------------------------------------------------------*/
+#ifdef WITH_LOADER_ARCH
+#define NUM_PNARGS 6
+#define NAMELEN 16
+struct pnarg {
+  char name[NAMELEN];
+  char *arg;
+};
+static struct pnarg pnargs[NUM_PNARGS];
+static struct pnarg *
+pnarg_copy(char *name, char *arg)
+{
+  char i;
+  struct pnarg *pnargsptr;
+
+  pnargsptr = pnargs;
+  /* Allocate a place in the loadernames table. */
+  for(i = 0; i < NUM_PNARGS; ++i) {
+    if(*(pnargsptr->name) == 0) {
+      strncpy(pnargsptr->name, name, NAMELEN);
+      pnargsptr->arg = arg;
+      return pnargsptr;
+    }
+    ++pnargsptr;
+  }
+  return NULL;
+}
+
+static void
+pnarg_free(struct pnarg *pn)
+{
+  *(pn->name) = 0;
+}
+#endif /* WITH_LOADER_ARCH */
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Loads a program and displays a dialog telling the user about it.
+ *
+ * \param name The name of the program to be loaded.
+ *
+ * \param arg An argument which is passed to the new process when it
+ * is loaded.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+program_handler_load(char *name, char *arg)
+{
+#ifdef WITH_LOADER_ARCH
+  struct pnarg *pnarg;
+  
+  pnarg = pnarg_copy(name, arg);
+  if(pnarg != NULL) {
+    ek_post(id, LOADER_EVENT_DISPLAY_NAME, pnarg);
+  } else {
+    ctk_label_set_text(&errortype, "Out of memory");
+    ctk_dialog_open(&errordialog);
+  }
+  /*  ctk_redraw(); */
+  /*  ctk_window_redraw(&loadingdialog);*/
+#endif /* WITH_LOADER_ARCH */
+}
+
+#ifdef WITH_LOADER_ARCH
+#define RUN(prg, name, arg) program_handler_load(prg, arg)
+#else /* WITH_LOADER_ARCH */
+#define RUN(prg, initfunc, arg) initfunc(arg)
+#endif /* WITH_LOADER_ARCH */
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Configures the name of the screensaver to be loaded when
+ * appropriate.
+ *
+ * \param name The name of the screensaver or NULL if no screensaver
+ * should be used.
+ */
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_SCREENSAVER
+void
+program_handler_setscreensaver(char *name)
+{
+  if(name == NULL) {
+    program_handler_screensaver[0] = 0;
+  } else {
+    strncpy(program_handler_screensaver, name, sizeof(program_handler_screensaver));
+  }
+}
+#endif /* CTK_CONF_SCREENSAVER */
+/*-----------------------------------------------------------------------------------*/
+static void
+make_windows(void)
+{
+#ifdef WITH_LOADER_ARCH
+  ctk_window_new(&runwindow, 16, 3, "Run");
+  
+  CTK_WIDGET_ADD(&runwindow, &namelabel);
+  CTK_WIDGET_ADD(&runwindow, &nameentry);
+  CTK_WIDGET_ADD(&runwindow, &loadbutton);
+  
+  CTK_WIDGET_FOCUS(&runwindow, &nameentry);
+  
+  ctk_dialog_new(&loadingdialog, 25, 1);
+  CTK_WIDGET_ADD(&loadingdialog, &loadingmsg);
+  CTK_WIDGET_ADD(&loadingdialog, &loadingname);
+  
+  ctk_dialog_new(&errordialog, 22, 8);
+  CTK_WIDGET_ADD(&errordialog, &errormsg);
+  CTK_WIDGET_ADD(&errordialog, &errorfilelabel);
+  CTK_WIDGET_ADD(&errordialog, &errortype);
+  CTK_WIDGET_ADD(&errordialog, &errorokbutton);
+  CTK_WIDGET_FOCUS(&errordialog, &errorokbutton);
+#endif /* WITH_LOADER_ARCH */
+}
+/*-----------------------------------------------------------------------------------*/
+/*static
+  DISPATCHER_SIGHANDLER(program_handler_sighandler, s, data)*/
+EK_EVENTHANDLER(program_handler_eventhandler, ev, data)
+{
+#ifdef WITH_LOADER_ARCH
+  unsigned char err;
+  struct dsc *dsc;
+#endif /* WITH_LOADER_ARCH */
+  unsigned char i;
+  struct dsc **dscp;
+  /*  DISPATCHER_SIGHANDLER_ARGS(s, data);*/
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    /* Create the menus */
+    ctk_menu_add(&contikimenu);
+#if WITH_LOADER_ARCH
+    runmenuitem = ctk_menuitem_add(&contikimenu, "Run program...");
+
+    make_windows();
+#endif /* WITH_LOADER_ARCH */
+#if QUIT_MENU
+    quitmenuitem = ctk_menuitem_add(&contikimenu, "Quit");
+#endif /* QUIT_MENU */
+    
+    displayname = NULL;
+
+#if CTK_CONF_SCREENSAVER
+    program_handler_screensaver[0] = 0;
+#endif /* CTK_CONF_SCREENSAVER */
+
+  } else if(ev == ctk_signal_button_activate) {
+#ifdef WITH_LOADER_ARCH
+    if(data == (ek_data_t)&loadbutton) {
+      ctk_window_close(&runwindow);
+      program_handler_load(name, NULL);
+    } else if(data == (ek_data_t)&errorokbutton) {
+      ctk_dialog_close();
+    }
+#endif /* WITH_LOADER_ARCH */
+#if QUIT_MENU
+    if(data == (ek_data_t)&quityesbutton) {
+      ctk_draw_init();
+      exit(EXIT_SUCCESS);
+    } else if(data == (ek_data_t)&quitnobutton) {
+      ctk_dialog_close();
+    }
+#endif /* QUIT_MENU */
+    dscp = &contikidsc[0];
+    for(i = 0; i < CTK_CONF_MAXMENUITEMS; ++i) {    
+      if(*dscp != NULL &&
+	 data == (ek_data_t)(*dscp)->icon) {
+	RUN((*dscp)->prgname, (*dscp)->init, NULL);
+	break;
+      }
+      ++dscp;
+    }
+  } else if(ev == ctk_signal_menu_activate) {
+    if((struct ctk_menu *)data == &contikimenu) {
+#if WITH_LOADER_ARCH
+      dsc = contikidsc[contikimenu.active];
+      if(dsc != NULL) {
+	RUN(dsc->prgname, dsc->init, NULL);
+      } else if(contikimenu.active == runmenuitem) {
+	make_windows();
+	ctk_window_close(&runwindow);
+	ctk_window_open(&runwindow);
+	CTK_WIDGET_FOCUS(&runwindow, &nameentry);
+      }
+#else /* WITH_LOADER_ARCH */
+      if(contikidsc[contikimenu.active] != NULL) {
+	RUN(contikidsc[contikimenu.active]->prgname,
+	    contikidsc[contikimenu.active]->init,
+	    NULL);
+      }
+#endif /* WITH_LOADER_ARCH */
+#if QUIT_MENU
+      if(contikimenu.active == quitmenuitem) {
+	ctk_dialog_new(&quitdialog, 24, 5);
+	CTK_WIDGET_ADD(&quitdialog, &quitdialoglabel);
+	CTK_WIDGET_ADD(&quitdialog, &quityesbutton);
+	CTK_WIDGET_ADD(&quitdialog, &quitnobutton);
+	CTK_WIDGET_FOCUS(&quitdialog, &quitnobutton);
+	ctk_dialog_open(&quitdialog);      
+      }
+#endif /* QUIT_MENU */
+    }
+#if CTK_CONF_SCREENSAVER
+  } else if(ev == ctk_signal_screensaver_start) {
+#if WITH_LOADER_ARCH
+    if(program_handler_screensaver[0] != 0) {
+      program_handler_load(program_handler_screensaver, NULL);
+    }
+#endif /* WITH_LOADER_ARCH */
+#endif /* CTK_CONF_SCREENSAVER */
+  } else if(ev == LOADER_EVENT_DISPLAY_NAME) {
+#if WITH_LOADER_ARCH
+    if(displayname == NULL) {
+      make_windows();
+
+      ctk_label_set_text(&loadingname, ((struct pnarg *)data)->name);
+      ctk_dialog_open(&loadingdialog);
+      /*      dispatcher_emit(loader_signal_load, data, id);*/
+      ek_post(id, LOADER_EVENT_LOAD, data);
+      displayname = data;
+    } else {
+      /* Try again. */
+      /*      dispatcher_emit(loader_signal_display_name, data, id);*/
+      ek_post(id, LOADER_EVENT_DISPLAY_NAME, data);
+    }
+#endif /* WITH_LOADER_ARCH */
+  } else if(ev == LOADER_EVENT_LOAD) {
+#if WITH_LOADER_ARCH
+    if(displayname == data) {
+      ctk_dialog_close();
+      displayname = NULL;
+      log_message("Loading ", ((struct pnarg *)data)->name);
+      err = LOADER_LOAD(((struct pnarg *)data)->name,
+			((struct pnarg *)data)->arg);
+      if(err != LOADER_OK) {
+	make_windows();
+	errorfilename[0] = '"';
+	strncpy(errorfilename + 1, ((struct pnarg *)data)->name,
+		sizeof(errorfilename) - 2);
+	errorfilename[1 + strlen(((struct pnarg *)data)->name)] = '"';
+	ctk_label_set_text(&errortype, (char *)errormsgs[err]);
+	ctk_dialog_open(&errordialog);
+	log_message((char *)errormsgs[err], errorfilename);
+      }
+      pnarg_free(data);
+    } else {
+      /* Try again. */
+/*      dispatcher_emit(loader_signal_display_name, data, id);*/
+      ek_post(id, LOADER_EVENT_DISPLAY_NAME, data);
+    }
+#endif /* WITH_LOADEER_ARCH */
+  } 
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/program-handler.h b/contiki/apps/program-handler.h
new file mode 100644
index 0000000..9cf1d56
--- /dev/null
+++ b/contiki/apps/program-handler.h
@@ -0,0 +1,51 @@
+/*
+ * 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. 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: program-handler.h,v 1.8 2005/05/12 23:55:18 oliverschmidt Exp $
+ *
+ */
+#ifndef __PROGRAM_HANDLER_H__
+#define __PROGRAM_HANDLER_H__
+
+#include "dsc.h"
+
+#define program_handler_getscreensaver() program_handler_screensaver
+
+extern char program_handler_screensaver[];
+
+void program_handler_init(void);
+void program_handler_load(char *name, char *arg);
+void program_handler_setscreensaver(char *name);
+
+void program_handler_add(struct dsc *dsc, char *menuname,
+			 unsigned char desktop);
+
+#endif /* __PROGRAM_HANDLER_H__ */
diff --git a/contiki/apps/shell-dsc.c b/contiki/apps/shell-dsc.c
new file mode 100644
index 0000000..6996cb0
--- /dev/null
+++ b/contiki/apps/shell-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: shell-dsc.c,v 1.4 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon shell_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(shell_dsc,
+    "The Contiki command shell",
+    "shell.prg",
+    shell_gui_init,
+    &shell_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char shellicon_bitmap[3*3*8] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char shellicon_textmap[9] = {
+  'C', 'o', 'n',
+  't', 'i', 'k',
+  'i', 'S', 'h'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon shell_icon =
+  {CTK_ICON("Command shell", shellicon_bitmap, shellicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/shell-dsc.h b/contiki/apps/shell-dsc.h
new file mode 100644
index 0000000..f0bde2a
--- /dev/null
+++ b/contiki/apps/shell-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: shell-dsc.h,v 1.1 2004/07/04 17:47:46 adamdunkels Exp $
+ *
+ */
+#ifndef __SHELL_DSC_H__
+#define __SHELL_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(shell_dsc);
+
+#endif /* __SHELL_DSC_H__ */
diff --git a/contiki/apps/shell-gui.c b/contiki/apps/shell-gui.c
new file mode 100644
index 0000000..d810bd9
--- /dev/null
+++ b/contiki/apps/shell-gui.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS.
+ *
+ * $Id: shell-gui.c,v 1.13 2005/05/05 23:32:01 oliverschmidt Exp $
+ *
+ */
+
+#include "ek.h"
+
+#include "program-handler.h"
+#include "loader.h"
+
+#include "uip.h"
+#include "uip_arp.h"
+#include "resolv.h"
+
+#include "shell.h"
+
+#include "ctk-textentry-cmdline.h"
+
+#include "shell-gui-conf.h"
+
+#include <string.h>
+
+
+static struct ctk_window window;
+static char log[SHELL_GUI_CONF_XSIZE * SHELL_GUI_CONF_YSIZE];
+static struct ctk_label loglabel =
+  {CTK_LABEL(0, 0, SHELL_GUI_CONF_XSIZE, SHELL_GUI_CONF_YSIZE, log)};
+static char command[SHELL_GUI_CONF_XSIZE - 1];
+static struct ctk_textentry commandentry =
+  {CTK_TEXTENTRY_INPUT(0, SHELL_GUI_CONF_YSIZE, SHELL_GUI_CONF_XSIZE - 2, 1, command,
+		       SHELL_GUI_CONF_XSIZE - 2, ctk_textentry_cmdline_input)};
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "Command shell", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*static DISPATCHER_SIGHANDLER(sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Command shell", shell_idle, sighandler,
+		   NULL)};
+		   static ek_id_t id;*/
+
+/*-----------------------------------------------------------------------------------*/
+void
+shell_quit(char *str)
+{
+  ctk_window_close(&window);
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_output(char *str1, char *str2)
+{
+  static unsigned char i, len;
+  
+  for(i = 1; i < SHELL_GUI_CONF_YSIZE; ++i) {
+    memcpy(&log[(i - 1) * SHELL_GUI_CONF_XSIZE],
+	   &log[i * SHELL_GUI_CONF_XSIZE], SHELL_GUI_CONF_XSIZE);
+  }
+  memset(&log[(SHELL_GUI_CONF_YSIZE - 1) * SHELL_GUI_CONF_XSIZE],
+	 0, SHELL_GUI_CONF_XSIZE);
+
+  len = strlen(str1);
+
+  strncpy(&log[(SHELL_GUI_CONF_YSIZE - 1) * SHELL_GUI_CONF_XSIZE],
+	  str1, SHELL_GUI_CONF_XSIZE);
+  if(len < SHELL_GUI_CONF_XSIZE) {
+    strncpy(&log[(SHELL_GUI_CONF_YSIZE - 1) * SHELL_GUI_CONF_XSIZE] + len,
+	    str2, SHELL_GUI_CONF_XSIZE - len);
+  }
+
+  CTK_WIDGET_REDRAW(&loglabel);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_prompt(char *str)
+{
+  
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(shell_gui_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+  
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&window, SHELL_GUI_CONF_XSIZE,
+		   SHELL_GUI_CONF_YSIZE + 1, "Command shell");
+    CTK_WIDGET_ADD(&window, &loglabel);
+    /*    CTK_WIDGET_SET_FLAG(&loglabel, CTK_WIDGET_FLAG_MONOSPACE);*/
+    CTK_WIDGET_ADD(&window, &commandentry);
+    /*    CTK_WIDGET_SET_FLAG(&commandentry, CTK_WIDGET_FLAG_MONOSPACE);*/
+    CTK_WIDGET_FOCUS(&window, &commandentry);
+    memset(log, 0, sizeof(log));
+    
+    shell_init();
+    ctk_window_open(&window);
+    shell_start();
+  } else if(ev == ctk_signal_widget_activate &&
+     data == (ek_data_t)&commandentry) {
+    shell_output("> ", command);
+    shell_input(command);
+    CTK_TEXTENTRY_CLEAR(&commandentry);
+    CTK_WIDGET_REDRAW(&commandentry);
+  } else if(ev == ctk_signal_window_close ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    shell_quit(NULL);
+  } else {
+    shell_eventhandler(ev, data);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/shell.c b/contiki/apps/shell.c
new file mode 100644
index 0000000..2b8adb4
--- /dev/null
+++ b/contiki/apps/shell.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS.
+ *
+ * $Id: shell.c,v 1.3 2005/05/08 10:39:08 oliverschmidt Exp $
+ *
+ */
+
+#include "program-handler.h"
+#include "loader.h"
+#include "cfs.h"
+#include "uip.h"
+#include "uip_arp.h"
+#include "resolv.h"
+
+#include "shell.h"
+
+#include <string.h>
+
+static char showingdir = 0;
+static struct cfs_dir dir;
+static unsigned int totsize;
+
+struct ptentry {
+  char c1;
+  char c2;
+  void (* pfunc)(char *str);
+};
+
+/*-----------------------------------------------------------------------------------*/
+static void
+parse(register char *str, struct ptentry *t)
+{
+  register struct ptentry *p;
+  char *sstr;
+
+  sstr = str;
+  
+  /* Loop over the parse table entries in t in order to find one that
+     matches the first character in str. */
+  for(p = t; p->c1 != 0; ++p) {
+    if(*str == p->c1 || *str == p->c2) {
+      /* Skip rest of the characters up to the first space. */
+      while(*str != ' ') {
+	++str;
+      }
+
+      /* Skip all spaces.*/
+      while(*str == ' ') {
+	++str;
+      }
+
+      /* Call parse table entry function and return. */
+      p->pfunc(str);
+      return;
+    }
+  }
+
+  /* Did not find matching entry in parse table. We just call the
+     default handler supplied by the caller and return. */
+  p->pfunc(str);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+inttostr(register char *str, unsigned int i)
+{
+  str[0] = '0' + i / 100;
+  if(str[0] == '0') {
+    str[0] = ' ';
+  }
+  str[1] = '0' + (i / 10) % 10;
+  if(str[0] == ' ' && str[1] == '0') {
+    str[1] = ' ';
+  }
+  str[2] = '0' + i % 10;
+  str[3] = ' ';
+  str[4] = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+processes(char *str)
+{
+  static char idstr[5];
+  struct ek_proc *p;
+
+  shell_output("Processes:", "");
+  /* Step through each possible process ID and see if there is a
+     matching process. */
+  for(p = EK_PROCS(); p != NULL; p = p->next) {
+    inttostr(idstr, p->id);
+    shell_output(idstr, (char *)p->name);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static char *
+nullterminate(char *str)
+{
+  char *nt;
+
+  /* Nullterminate string. Start with finding newline character. */
+  for(nt = str; *nt != '\r' &&
+	*nt != '\n'; ++nt);
+
+  /* Replace newline with a null char. */
+  *nt = 0;
+
+  /* Remove trailing spaces. */
+  while(nt > str && *(nt - 1) == ' ') {
+    *(nt - 1) = 0;
+    --nt;
+  }
+  
+  /* Return pointer to null char. */
+  return nt;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+runfile(char *str)
+{
+  nullterminate(str);
+
+  if(strlen(str) > 0) {
+    /* Call loader function. */
+    program_handler_load(str, NULL);
+    shell_output("Starting program ", str);  
+  } else {
+    shell_output("Must supply a program name", "");  
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+execfile(char *str)
+{
+  runfile(str);
+  shell_quit(NULL);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+killproc(char *str)
+{
+  char procnum, j, c;
+  char procstr[5];
+
+  nullterminate(str);
+  
+  procnum = 0;
+  
+  for(j = 0; j < 4; ++j) {
+    c = str[j];
+    if(c >= '0' && c <= '9') {
+      procnum = procnum * 10 + (str[j] - '0');
+    } else {
+      break;
+    }
+  }
+  if(procnum != 0) {
+    inttostr(procstr, procnum);
+    shell_output("Killing process ", procstr);
+    ek_post(procnum, EK_EVENT_REQUEST_EXIT, NULL);
+  } else {
+    shell_output("Invalid process number", "");
+  }
+  
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+help(char *str)
+{
+  shell_output("Available commands:", "");
+  shell_output("run  - start program", "");
+  shell_output("exec - start program & exit shell", "");  
+  shell_output("ps   - show processes", "");
+  shell_output("kill - kill process", "");
+  shell_output("ls   - display directory", "");
+  shell_output("quit - quit shell", "");
+  shell_output("?    - show this help", "");      
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+directory(char *str)
+{
+  if(cfs_opendir(&dir, ".") != 0) {
+    shell_output("Cannot open directory", "");
+    showingdir = 0;
+  } else {
+    shell_output("Disk directory:", "");
+    showingdir = 1;
+    totsize = 0;
+    ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, NULL);
+  }
+  
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+none(char *str)
+{
+}
+/*-----------------------------------------------------------------------------------*/
+static struct ptentry configparsetab[] =
+  {{'e', 'E', execfile},
+   {'r', 'R', runfile},
+   {'k', 'K', killproc},   
+   {'p', 'P', processes},
+   {'l', 'L', directory},
+   {'q', 'Q', shell_quit},
+   {'h', '?', help},
+
+   /* Default action */
+   {0,   0,   none}};
+/*-----------------------------------------------------------------------------------*/
+void
+shell_init(void)
+{
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_start(void)
+{
+  showingdir = 0;
+  shell_output("Contiki command shell", "");
+  shell_output("Type '?' and return for help", "");  
+  shell_prompt("contiki> "); 
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_input(char *cmd)
+{
+  if(showingdir != 0) {
+    showingdir = 0;
+    shell_output("Directory stopped", "");
+    cfs_closedir(&dir);
+  }
+  parse(cmd, configparsetab);
+  if(showingdir == 0) {
+    shell_prompt("contiki> ");
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_eventhandler(ek_event_t ev, ek_data_t data)
+{
+  static struct cfs_dirent dirent;
+  static char size[10];
+
+  if(ev == EK_EVENT_CONTINUE) {
+    if(showingdir != 0) {
+      if(cfs_readdir(&dir, &dirent) != 0) {
+	cfs_closedir(&dir);
+	showingdir = 0;
+	inttostr(size, totsize);
+	shell_output("Total number of blocks: ", size);
+	shell_prompt("contiki> ");
+      } else {
+	totsize += dirent.size;
+	inttostr(size, dirent.size);
+	shell_output(size, dirent.name);
+	ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, NULL);
+      }
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/shell.h b/contiki/apps/shell.h
new file mode 100644
index 0000000..92fd22e
--- /dev/null
+++ b/contiki/apps/shell.h
@@ -0,0 +1,114 @@
+/**
+ * \file
+ * Interface for the Contiki shell.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * Some of the functions declared in this file must be implemented as
+ * a shell back-end in the architecture specific files of a Contiki
+ * port.
+ */
+
+
+/*
+ * Copyright (c) 2003, 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. 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 OS.
+ *
+ * $Id: shell.h,v 1.4 2004/08/20 21:37:39 adamdunkels Exp $
+ *
+ */
+#ifndef __SHELL_H__
+#define __SHELL_H__
+
+/**
+ * Initialize the shell.
+ *
+ * Called when the shell front-end process starts. This function may
+ * be used to start listening for signals.
+ */
+void shell_init(void);
+
+/**
+ * Start the shell back-end.
+ *
+ * Called by the front-end when a new shell is started.
+ */
+void shell_start(void);
+
+/**
+ * The shell event handler.
+ *
+ * This function will be called when an event is received.
+ */
+void shell_eventhandler(ek_event_t ev, ek_data_t data);
+
+/**
+ * Process a shell command.
+ *
+ * This function will be called by the shell GUI / telnet server whan
+ * a command has been entered that should be processed by the shell
+ * back-end.
+ *
+ * \param command The command to be processed.
+ */
+void shell_input(char *command);
+
+/**
+ * Quit the shell.
+ *
+ */
+void shell_quit(char *);
+
+
+/**
+ * Print a string to the shell window.
+ *
+ * This function is implemented by the shell GUI / telnet server and
+ * can be called by the shell back-end to output a string in the
+ * shell window. The string is automatically appended with a linebreak.
+ *
+ * \param str1 The first half of the string to be output.
+ * \param str2 The second half of the string to be output.
+ */
+void shell_output(char *str1, char *str2);
+
+/**
+ * Print a prompt to the shell window.
+ *
+ * This function can be used by the shell back-end to print out a
+ * prompt to the shell window.
+ *
+ * \param prompt The prompt to be printed.
+ *
+ */
+void shell_prompt(char *prompt);
+
+#endif /* __SHELL_H__ */
+
+
+
diff --git a/contiki/apps/simpletelnet.c b/contiki/apps/simpletelnet.c
new file mode 100644
index 0000000..5ba57e8
--- /dev/null
+++ b/contiki/apps/simpletelnet.c
@@ -0,0 +1,333 @@
+/*
+ * 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. 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.14 2005/04/16 14:17:32 oliverschmidt Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "ek.h"
+#include "petsciiconv.h"
+#include "uiplib.h"
+#include "uip.h"
+#include "ctk.h"
+#include "resolv.h"
+#include "telnet.h"
+#include "simpletelnet.h"
+#include "loader.h"
+#include "tcpip.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 char sendline[31+2];
+
+EK_EVENTHANDLER(simpletelnet_eventhandler, ev, data);
+EK_PROCESS(p, "Telnet client", EK_PRIO_NORMAL,
+	   simpletelnet_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+/*
+static DISPATCHER_SIGHANDLER(simpletelnet_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Simple telnet", NULL, simpletelnet_sighandler,
+		   telnet_app)};
+		   static ek_id_t id;*/
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(simpletelnet_init, arg)
+{
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+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 if(*text >= ' ') {
+      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(uiplib_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 = tcp_connect(addrptr, htons(port), &ts_appstate);
+  if(conn == NULL) {
+    show("Out of memory error");
+    return;
+  }
+
+  show("Connecting...");
+
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(simpletelnet_eventhandler, ev, data)
+{
+  struct ctk_widget *w;
+  int sendlen;
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    /* Create Telnet window. */
+    ctk_window_new(&telnetwindow, 38, 20, "Simple telnet");
+
+    strcpy(telnetport, "23");
+    
+    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(ctk_signal_window_close);
+    dispatcher_listen(resolv_signal_found);*/
+    
+    ctk_window_open(&telnetwindow);
+
+  } else if(ev == ctk_signal_button_activate) {
+    
+    w = (struct ctk_widget *)data;
+    if(w == (struct ctk_widget *)&telnetsendbutton) {
+      strcpy(sendline, telnetline);
+      sendlen = strlen(sendline);
+      petsciiconv_toascii(sendline, sendlen);
+      sendline[sendlen++] = ISO_CR;
+      sendline[sendlen++] = ISO_NL;
+      if(telnet_send(&ts_appstate, sendline, sendlen)) {
+	/* 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(ev == resolv_event_found) {
+    if(strcmp(data, telnethost) == 0) {
+      if(resolv_lookup(telnethost) != NULL) {
+	connect();
+      } else {
+	show("Host not found");
+      }
+    }
+  } else if(ev == ctk_signal_window_close ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    ek_exit();
+    ctk_window_close(&telnetwindow);
+    id = EK_ID_NONE;
+    LOADER_UNLOAD();
+  } else if(ev == tcpip_event) {
+    telnet_app(data);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+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(sendline, sizeof(sendline));
+  scrollup();
+  add_text(sendline);
+  CTK_TEXTENTRY_CLEAR(&telnetlinetextentry);
+  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..b3d9b20
--- /dev/null
+++ b/contiki/apps/simpletelnet.h
@@ -0,0 +1,40 @@
+/*
+ * 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. 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.3 2004/06/06 05:59:21 adamdunkels Exp $
+ *
+ */
+#ifndef __SIMPLETELNET_H__
+#define __SIMPLETELNET_H__
+
+void simpletelnet_init(char *arg);
+
+#endif /* __SIMPLETELNET_H__ */
diff --git a/contiki/apps/smtp-socket.c b/contiki/apps/smtp-socket.c
new file mode 100644
index 0000000..09d9b1d
--- /dev/null
+++ b/contiki/apps/smtp-socket.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: smtp-socket.c,v 1.6 2005/05/05 23:02:01 oliverschmidt Exp $
+ */
+#include "smtp.h"
+
+#include "smtp-strings.h"
+#include "psock.h"
+
+#include <string.h>
+
+struct smtp_state {
+
+  char connected;
+  
+  struct psock psock;
+
+  char inputbuffer[4];
+  
+  char *to;
+  char *cc;
+  char *from;
+  char *subject;
+  char *msg;
+  u8_t msgwidth;
+  u8_t msgheight;
+  u8_t line;
+};
+
+static struct smtp_state s;
+
+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
+
+
+#define SEND_STRING(s, str) PSOCK_SEND(s, str, strlen(str))
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(smtp_thread(void))
+{
+  PSOCK_BEGIN(&s.psock);
+
+  PSOCK_READTO(&s.psock, ISO_nl);
+   
+  if(strncmp(s.inputbuffer, smtp_220, 3) != 0) {
+    PSOCK_CLOSE(&s.psock);
+    smtp_done(2);
+    PSOCK_EXIT(&s.psock);
+  }
+  
+  SEND_STRING(&s.psock, (char *)smtp_helo);
+  SEND_STRING(&s.psock, localhostname);
+  SEND_STRING(&s.psock, (char *)smtp_crnl);
+
+  PSOCK_READTO(&s.psock, ISO_nl);
+  
+  if(s.inputbuffer[0] != ISO_2) {
+    PSOCK_CLOSE(&s.psock);
+    smtp_done(3);
+    PSOCK_EXIT(&s.psock);
+  }  
+
+  SEND_STRING(&s.psock, (char *)smtp_mail_from);
+  SEND_STRING(&s.psock, s.from);
+  SEND_STRING(&s.psock, (char *)smtp_crnl);
+
+  PSOCK_READTO(&s.psock, ISO_nl);
+  
+  if(s.inputbuffer[0] != ISO_2) {
+    PSOCK_CLOSE(&s.psock);
+    smtp_done(4);
+    PSOCK_EXIT(&s.psock);
+  }
+
+  SEND_STRING(&s.psock, (char *)smtp_rcpt_to);
+  SEND_STRING(&s.psock, s.to);
+  SEND_STRING(&s.psock, (char *)smtp_crnl);
+
+  PSOCK_READTO(&s.psock, ISO_nl);
+  
+  if(s.inputbuffer[0] != ISO_2) {
+    PSOCK_CLOSE(&s.psock);
+    smtp_done(5);
+    PSOCK_EXIT(&s.psock);
+  }
+  
+  if(*s.cc != 0) {
+    SEND_STRING(&s.psock, (char *)smtp_rcpt_to);
+    SEND_STRING(&s.psock, s.cc);
+    SEND_STRING(&s.psock, (char *)smtp_crnl);
+
+    PSOCK_READTO(&s.psock, ISO_nl);
+  
+    if(s.inputbuffer[0] != ISO_2) {
+      PSOCK_CLOSE(&s.psock);
+      smtp_done(6);
+      PSOCK_EXIT(&s.psock);
+    }
+  }
+  
+  SEND_STRING(&s.psock, (char *)smtp_data);
+  
+  PSOCK_READTO(&s.psock, ISO_nl);
+  
+  if(s.inputbuffer[0] != ISO_3) {
+    PSOCK_CLOSE(&s.psock);
+    smtp_done(7);
+    PSOCK_EXIT(&s.psock);
+  }
+
+  SEND_STRING(&s.psock, (char *)smtp_to);
+  SEND_STRING(&s.psock, s.to);
+  SEND_STRING(&s.psock, (char *)smtp_crnl);
+  
+  if(*s.cc != 0) {
+    SEND_STRING(&s.psock, (char *)smtp_cc);
+    SEND_STRING(&s.psock, s.cc);
+    SEND_STRING(&s.psock, (char *)smtp_crnl);
+  }
+  
+  SEND_STRING(&s.psock, (char *)smtp_from);
+  SEND_STRING(&s.psock, s.from);
+  SEND_STRING(&s.psock, (char *)smtp_crnl);
+  
+  SEND_STRING(&s.psock, (char *)smtp_subject);
+  SEND_STRING(&s.psock, s.subject);
+  SEND_STRING(&s.psock, (char *)smtp_crnl);
+
+  for(s.line = 0; s.line < s.msgheight; ++s.line) {
+    SEND_STRING(&s.psock, (char *)smtp_crnl);
+    SEND_STRING(&s.psock, &s.msg[s.line * s.msgwidth]);
+  }
+  
+  SEND_STRING(&s.psock, (char *)smtp_crnlperiodcrnl);
+
+  PSOCK_READTO(&s.psock, ISO_nl);
+  if(s.inputbuffer[0] != ISO_2) {
+    PSOCK_CLOSE(&s.psock);
+    smtp_done(8);
+    PSOCK_EXIT(&s.psock);
+  }
+
+  SEND_STRING(&s.psock, (char *)smtp_quit);
+  smtp_done(SMTP_ERR_OK);
+  PSOCK_END(&s.psock);
+}
+/*---------------------------------------------------------------------------*/
+void
+smtp_appcall(void *state)
+{
+  if(uip_closed()) {
+    s.connected = 0;
+    return;
+  }
+  if(uip_aborted() || uip_timedout()) {
+    s.connected = 0;
+    smtp_done(1);
+    return;
+  }
+  smtp_thread();
+}
+/*---------------------------------------------------------------------------*/
+void
+smtp_configure(char *lhostname, u16_t *server)
+{
+  localhostname = lhostname;
+  smtpserver[0] = server[0];
+  smtpserver[1] = server[1];
+}
+/*---------------------------------------------------------------------------*/
+unsigned char
+smtp_send(char *to, char *cc, char *from, char *subject,
+	  char *msg, u8_t msgwidth, u8_t msgheight)
+{
+  struct uip_conn *conn;
+
+  conn = tcp_connect(smtpserver, HTONS(25), NULL);
+  if(conn == NULL) {
+    return 0;
+  }
+  s.connected = 1;
+  s.to = to;
+  s.cc = cc;
+  s.from = from;
+  s.subject = subject;
+  s.msg = msg;
+  s.msgwidth = msgwidth;
+  s.msgheight = msgheight;
+
+  PSOCK_INIT(&s.psock, s.inputbuffer, sizeof(s.inputbuffer));
+  
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
+void
+smtp_init(void)
+{
+  s.connected = 0;
+}
+/*---------------------------------------------------------------------------*/
+
diff --git a/contiki/apps/smtp-strings b/contiki/apps/smtp-strings
new file mode 100644
index 0000000..359ceef
--- /dev/null
+++ b/contiki/apps/smtp-strings
@@ -0,0 +1,12 @@
+smtp_220 "220"
+smtp_helo "HELO "
+smtp_mail_from "MAIL FROM: "
+smtp_rcpt_to "RCPT TO: "
+smtp_data "DATA\r\n"
+smtp_to "To: "
+smtp_to "Cc: "
+smtp_from "From: "
+smtp_subject "Subject: "
+smtp_quit "QUIT\r\n"
+smtp_crnl "\r\n"
+smtp_crnlperiodcrnl "\r\n.\r\n"
\ 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..4076424
--- /dev/null
+++ b/contiki/apps/smtp-strings.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: smtp-strings.c,v 1.6 2005/05/05 23:02:02 oliverschmidt Exp $
+ */
+const char smtp_220[4] = 
+/* "220" */
+{0x32, 0x32, 0x30, };
+const char smtp_helo[6] = 
+/* "HELO " */
+{0x48, 0x45, 0x4c, 0x4f, 0x20, };
+const char smtp_mail_from[12] = 
+/* "MAIL FROM: " */
+{0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x20, };
+const char smtp_rcpt_to[10] = 
+/* "RCPT TO: " */
+{0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x20, };
+const char smtp_data[7] = 
+/* "DATA\r\n" */
+{0x44, 0x41, 0x54, 0x41, 0xd, 0xa, };
+const char smtp_to[5] = 
+/* "To: " */
+{0x54, 0x6f, 0x3a, 0x20, };
+const char smtp_cc[5] = 
+/* "Cc: " */
+{0x43, 0x63, 0x3a, 0x20, };
+const char smtp_from[7] = 
+/* "From: " */
+{0x46, 0x72, 0x6f, 0x6d, 0x3a, 0x20, };
+const char smtp_subject[10] = 
+/* "Subject: " */
+{0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, };
+const char smtp_quit[7] = 
+/* "QUIT\r\n" */
+{0x51, 0x55, 0x49, 0x54, 0xd, 0xa, };
+const char smtp_crnl[3] = 
+/* "\r\n" */
+{0xd, 0xa, };
+const char smtp_crnlperiodcrnl[6] = 
+/* "\r\n.\r\n" */
+{0xd, 0xa, 0x2e, 0xd, 0xa, };
diff --git a/contiki/apps/smtp-strings.h b/contiki/apps/smtp-strings.h
new file mode 100644
index 0000000..7f638d3
--- /dev/null
+++ b/contiki/apps/smtp-strings.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: smtp-strings.h,v 1.5 2005/04/28 22:36:07 oliverschmidt Exp $
+ */
+extern const char smtp_220[4];
+extern const char smtp_helo[6];
+extern const char smtp_mail_from[12];
+extern const char smtp_rcpt_to[10];
+extern const char smtp_data[7];
+extern const char smtp_to[5];
+extern const char smtp_cc[5];
+extern const char smtp_from[7];
+extern const char smtp_subject[10];
+extern const char smtp_quit[7];
+extern const char smtp_crnl[3];
+extern const char smtp_crnlperiodcrnl[6];
diff --git a/contiki/apps/smtp.c b/contiki/apps/smtp.c
new file mode 100644
index 0000000..9efacdf
--- /dev/null
+++ b/contiki/apps/smtp.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. 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.6 2004/07/04 11:35:08 adamdunkels Exp $
+ *
+ */
+
+#include "uip.h"
+#include "smtp.h"
+
+#include "smtp-strings.h"
+
+#include "tcpip.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;
+  
+  if(s.textlen - s.sendptr > uip_mss()) {
+    s.sentlen = uip_mss();
+  } else {
+    s.sentlen = s.textlen - s.sendptr;
+  }
+
+  /*  textptr[s.sentlen] = 0;
+      printf("Senidng '%s'\n", textptr);*/
+  
+  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;
+      s.sendptr = s.textlen = 0;
+      break;
+    case STATE_SEND_DATA_MESSAGE:
+      s.state = STATE_SEND_DATA_END;
+      s.sendptr = s.textlen = 0;
+      break;
+    case STATE_SEND_DATA_END:
+      s.state = STATE_SEND_QUIT;
+      s.sendptr = s.textlen = 0;
+      break;
+    case STATE_SEND_QUIT:
+      s.state = STATE_SEND_DONE;
+      smtp_done(SMTP_ERR_OK);
+      uip_close();
+      break;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+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("Newdata(): SEND_NONE, got 220, towards SEND_HELO\n");*/
+      s.state = STATE_SEND_HELO;
+      s.sendptr = 0;
+    }
+    break;
+  case STATE_SEND_HELO:
+    if(*(char *)uip_appdata == ISO_2) {
+      /*      printf("Newdata(): SEND_HELO, got 2*, towards SEND_MAIL_FROM\n");*/
+      s.state = STATE_SEND_MAIL_FROM;
+      s.sendptr = 0;
+    }    
+    break;
+  case STATE_SEND_MAIL_FROM:
+    if(*(char *)uip_appdata == ISO_2) {
+      /*      printf("Newdata(): SEND_MAIL_FROM, got 2*, towards SEND_RCPT_TO\n");      */
+      /*      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;
+  }
+    
+}
+/*-----------------------------------------------------------------------------------*/
+/*DISPATCHER_UIPCALL(smtp_appcall, state)*/
+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 = tcp_connect(smtpserver, HTONS(25), NULL);
+  if(conn == NULL) {
+    return 0;
+  }
+  
+  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..e10a6de
--- /dev/null
+++ b/contiki/apps/smtp.h
@@ -0,0 +1,63 @@
+/*
+ * 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. 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.5 2005/05/04 23:51:09 oliverschmidt Exp $
+ *
+ */
+#ifndef __SMTP_H__
+#define __SMTP_H__
+
+#include "uip.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 *cc, char *from,
+			char *subject, char *msg,
+			u8_t msgwidth, u8_t msgheight);
+
+/*DISPATCHER_UIPCALL(smtp_appcall, state);*/
+
+void smtp_appcall(void *state);
+
+
+#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-dsc.c b/contiki/apps/telnet-dsc.c
new file mode 100644
index 0000000..54c8452
--- /dev/null
+++ b/contiki/apps/telnet-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: telnet-dsc.c,v 1.7 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon telnet_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(telnet_dsc,
+    "A simple Telnet client",
+    "telnet.prg",
+    simpletelnet_init,
+    &telnet_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char telneticon_textmap[9] = {
+  't', 'e', 'l',
+  'n', 'e', 't',
+  '-', '-', '-'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon telnet_icon =
+  {CTK_ICON("Telnet", telneticon_bitmap, telneticon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/telnet-dsc.h b/contiki/apps/telnet-dsc.h
new file mode 100644
index 0000000..6275654
--- /dev/null
+++ b/contiki/apps/telnet-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: telnet-dsc.h,v 1.1 2003/04/17 19:00:01 adamdunkels Exp $
+ *
+ */
+#ifndef __TELNET_DSC_H__
+#define __TELNET_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(telnet_dsc);
+
+#endif /* __TELNET_DSC_H__ */
diff --git a/contiki/apps/telnet.c b/contiki/apps/telnet.c
new file mode 100644
index 0000000..df7bf2f
--- /dev/null
+++ b/contiki/apps/telnet.c
@@ -0,0 +1,152 @@
+/*
+ * 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. 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.5 2004/07/04 11:35:08 adamdunkels Exp $
+ *
+ */
+
+#include "tcpip.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(void *ts)
+{
+  struct telnet_state *s = (struct telnet_state *)ts;
+    
+  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..57bf23a
--- /dev/null
+++ b/contiki/apps/telnet.h
@@ -0,0 +1,59 @@
+/*
+ * 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. 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.4 2004/07/04 17:50:39 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;
+};
+
+/*DISPATCHER_UIPCALL(telnet_app, s);*/
+void telnet_app(void *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/telnetd-dsc.c b/contiki/apps/telnetd-dsc.c
new file mode 100644
index 0000000..9e02a57
--- /dev/null
+++ b/contiki/apps/telnetd-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: telnetd-dsc.c,v 1.5 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon telnetd_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(telnetd_dsc,
+    "Telnet shell server",
+    "telnetd.prg",
+    telnetd_init,
+    &telnetd_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char telnetdicon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char telnetdicon_textmap[9] = {
+  't', 'e', 'l',
+  'n', 'e', 't',
+  's', 'r', 'v'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon telnetd_icon =
+  {CTK_ICON("Telnet server", telnetdicon_bitmap, telnetdicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/telnetd-dsc.h b/contiki/apps/telnetd-dsc.h
new file mode 100644
index 0000000..36cf3c5
--- /dev/null
+++ b/contiki/apps/telnetd-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: telnetd-dsc.h,v 1.1 2003/08/21 22:24:19 adamdunkels Exp $
+ *
+ */
+#ifndef __TELNETD_DSC_H__
+#define __TELNETD_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(telnetd_dsc);
+
+#endif /* __TELNETD_DSC_H__ */
diff --git a/contiki/apps/telnetd-gui.c b/contiki/apps/telnetd-gui.c
new file mode 100644
index 0000000..3384855
--- /dev/null
+++ b/contiki/apps/telnetd-gui.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS.
+ *
+ * $Id: telnetd-gui.c,v 1.5 2005/04/28 21:16:37 oliverschmidt Exp $
+ *
+ */
+
+#include "program-handler.h"
+#include "loader.h"
+#include "uip.h"
+#include "petsciiconv.h"
+#include "uip_arp.h"
+#include "resolv.h"
+#include "telnetd.h"
+#include "memb.h"
+
+#include "shell.h"
+
+#include "telnetd.h"
+
+#include <string.h>
+
+#define ISO_nl       0x0a
+#define ISO_cr       0x0d
+
+#define XSIZE 36
+#define YSIZE 12
+
+static struct ctk_window window;
+static char log[XSIZE * YSIZE];
+static struct ctk_label loglabel =
+  {CTK_LABEL(0, 0, XSIZE, YSIZE, log)};
+
+/*-----------------------------------------------------------------------------------*/
+void
+telnetd_gui_output(char *str1, char *str2)
+{
+  static unsigned int len, i;
+  
+  for(i = 1; i < YSIZE; ++i) {
+    memcpy(&log[(i - 1) * XSIZE], &log[i * XSIZE], XSIZE);
+  }
+  memset(&log[(YSIZE - 1) * XSIZE], 0, XSIZE);
+
+  len = strlen(str1);
+
+  strncpy(&log[(YSIZE - 1) * XSIZE], str1, XSIZE);
+  if(len < XSIZE) {
+    strncpy(&log[(YSIZE - 1) * XSIZE] + len, str2, XSIZE - len);
+  }
+  
+  CTK_WIDGET_REDRAW(&loglabel);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+telnetd_gui_quit(void)
+{
+  ctk_window_close(&window);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+telnetd_gui_init(void)
+{
+  ctk_window_new(&window, XSIZE, YSIZE, "Shell server");
+  CTK_WIDGET_ADD(&window, &loglabel);
+  memset(log, 0, sizeof(log));
+  ctk_window_open(&window);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+telnetd_gui_eventhandler(ek_event_t ev, ek_data_t data)
+{
+  if(ev == ctk_signal_window_close) {
+    telnetd_quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/telnetd.c b/contiki/apps/telnetd.c
new file mode 100644
index 0000000..ddcf77d
--- /dev/null
+++ b/contiki/apps/telnetd.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS.
+ *
+ * $Id: telnetd.c,v 1.10 2004/09/12 07:25:26 adamdunkels Exp $
+ *
+ */
+
+#include "loader.h"
+#include "uip.h"
+#include "petsciiconv.h"
+#include "uip_arp.h"
+#include "resolv.h"
+
+#include "memb.h"
+
+#include "shell.h"
+
+#include "telnetd.h"
+
+#include "telnetd-conf.h"
+
+#include <string.h>
+
+#define ISO_nl       0x0a
+#define ISO_cr       0x0d
+
+#define XSIZE 36
+#define YSIZE 12
+
+/*static DISPATCHER_SIGHANDLER(sighandler, s, data);
+
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Shell server", shell_idle, sighandler,
+		   telnetd_appcall)};
+		   static ek_id_t id = EK_ID_NONE;*/
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "Shell server", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+MEMB(linemem, TELNETD_CONF_LINELEN, TELNETD_CONF_NUMLINES);
+
+
+struct telnetd_state {
+  char *lines[TELNETD_CONF_NUMLINES];
+  char buf[TELNETD_CONF_LINELEN];
+  char bufptr;
+  u8_t numsent;
+  u8_t state;
+#define STATE_NORMAL 0
+#define STATE_IAC    1
+#define STATE_WILL   2
+#define STATE_WONT   3
+#define STATE_DO     4  
+#define STATE_DONT   5
+  
+#define STATE_CLOSE  6
+};
+static struct telnetd_state s;
+
+#define TELNET_IAC   255
+#define TELNET_WILL  251
+#define TELNET_WONT  252
+#define TELNET_DO    253
+#define TELNET_DONT  254
+/*-----------------------------------------------------------------------------------*/
+static char *
+alloc_line(void)
+{  
+  return memb_alloc(&linemem);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+dealloc_line(char *line)
+{
+  memb_free(&linemem, line);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_quit(char *str)
+{
+  s.state = STATE_CLOSE;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+telnetd_quit(void)
+{
+#if TELNETD_CONF_GUI
+  telnetd_gui_quit();
+#endif /* TELNETD_CONF_GUI */
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sendline(char *line)
+{
+  static unsigned int i;
+  
+  for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
+    if(s.lines[i] == NULL) {
+      s.lines[i] = line;
+      break;
+    }
+  }
+  if(i == TELNETD_CONF_NUMLINES) {
+    dealloc_line(line);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_prompt(char *str)
+{
+  char *line;
+  line = alloc_line();
+  if(line != NULL) {
+    strncpy(line, str, TELNETD_CONF_LINELEN);
+    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);
+    sendline(line);
+  }         
+}
+/*-----------------------------------------------------------------------------------*/
+void
+shell_output(char *str1, char *str2)
+{
+  static unsigned len;
+  char *line;
+
+  line = alloc_line();
+  if(line != NULL) {
+    len = strlen(str1);
+    strncpy(line, str1, TELNETD_CONF_LINELEN);
+    if(len < TELNETD_CONF_LINELEN) {
+      strncpy(line + len, str2, TELNETD_CONF_LINELEN - len);
+    }
+    len = strlen(line);
+    if(len < TELNETD_CONF_LINELEN - 2) {
+      line[len] = ISO_cr;
+      line[len+1] = ISO_nl;
+      line[len+2] = 0;
+    }
+    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);
+    sendline(line);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(telnetd_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {    
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    tcp_listen(HTONS(23));
+    memb_init(&linemem);
+    shell_init();
+  } else if(ev == tcpip_event) {
+    telnetd_appcall(data);
+  } else if(ev == EK_EVENT_REQUEST_EXIT) {
+    telnetd_quit();
+  } else {
+#if TELNETD_CONF_GUI    
+    telnetd_gui_eventhandler(ev, data);
+#endif /* TELNETD_CONF_GUI */
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+acked(void)     
+{
+  static unsigned int i;
+  
+  while(s.numsent > 0) {
+    dealloc_line(s.lines[0]);
+    for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) {
+      s.lines[i - 1] = s.lines[i];    
+    }
+    s.lines[TELNETD_CONF_NUMLINES - 1] = NULL;
+    --s.numsent;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+senddata(void)    
+{
+  static char *bufptr, *lineptr;
+  static int buflen, linelen;
+  
+  bufptr = uip_appdata;
+  buflen = 0;
+  for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES &&
+	s.lines[s.numsent] != NULL ; ++s.numsent) {    
+    lineptr = s.lines[s.numsent];
+    linelen = strlen(lineptr);
+    if(linelen > TELNETD_CONF_LINELEN) {
+      linelen = TELNETD_CONF_LINELEN;
+    }
+    if(buflen + linelen < uip_mss()) {
+      memcpy(bufptr, lineptr, linelen);
+      bufptr += linelen;
+      buflen += linelen;
+    } else {
+      break;
+    }
+  }
+  uip_send(uip_appdata, buflen);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+closed(void)
+{
+  static unsigned int i;
+  
+  for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
+    if(s.lines[i] != NULL) {
+      dealloc_line(s.lines[i]);
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+getchar(u8_t c)
+{
+  if(c == ISO_cr) {
+    return;
+  }
+  
+  s.buf[(int)s.bufptr] = c;  
+  if(s.buf[(int)s.bufptr] == ISO_nl ||
+     s.bufptr == sizeof(s.buf) - 1) {    
+    if(s.bufptr > 0) {
+      s.buf[(int)s.bufptr] = 0;
+      petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);
+    }
+    shell_input(s.buf);
+    s.bufptr = 0;
+  } else {
+    ++s.bufptr;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+sendopt(u8_t option, u8_t value)
+{
+  char *line;
+  line = alloc_line();
+  if(line != NULL) {
+    line[0] = TELNET_IAC;
+    line[1] = option;
+    line[2] = value;
+    line[3] = 0;
+    sendline(line);
+  }       
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+newdata(void)
+{
+  u16_t len;
+  u8_t c;
+    
+  
+  len = uip_datalen();
+  
+  while(len > 0 && s.bufptr < sizeof(s.buf)) {
+    c = *uip_appdata;
+    ++uip_appdata;
+    --len;
+    switch(s.state) {
+    case STATE_IAC:
+      if(c == TELNET_IAC) {
+	getchar(c);
+	s.state = STATE_NORMAL;
+      } else {
+	switch(c) {
+	case TELNET_WILL:
+	  s.state = STATE_WILL;
+	  break;
+	case TELNET_WONT:
+	  s.state = STATE_WONT;
+	  break;
+	case TELNET_DO:
+	  s.state = STATE_DO;
+	  break;
+	case TELNET_DONT:
+	  s.state = STATE_DONT;
+	  break;
+	default:
+	  s.state = STATE_NORMAL;
+	  break;
+	}
+      }
+      break;
+    case STATE_WILL:
+      /* Reply with a DONT */
+      sendopt(TELNET_DONT, c);
+      s.state = STATE_NORMAL;
+      break;
+      
+    case STATE_WONT:
+      /* Reply with a DONT */
+      sendopt(TELNET_DONT, c);
+      s.state = STATE_NORMAL;
+      break;
+    case STATE_DO:
+      /* Reply with a WONT */
+      sendopt(TELNET_WONT, c);
+      s.state = STATE_NORMAL;
+      break;
+    case STATE_DONT:
+      /* Reply with a WONT */
+      sendopt(TELNET_WONT, c);
+      s.state = STATE_NORMAL;
+      break;
+    case STATE_NORMAL:
+      if(c == TELNET_IAC) {
+	s.state = STATE_IAC;
+      } else {
+	getchar(c);
+      }      
+      break;
+    } 
+
+    
+  }  
+  
+}
+/*-----------------------------------------------------------------------------------*/
+void
+telnetd_appcall(void *ts)
+{
+  static unsigned int i;
+  if(uip_connected()) {
+    tcp_markconn(uip_conn, &s);
+    for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
+      s.lines[i] = NULL;
+    }
+    s.bufptr = 0;
+    s.state = STATE_NORMAL;
+
+    shell_start();
+  }
+
+  if(s.state == STATE_CLOSE) {
+    s.state = STATE_NORMAL;
+    uip_close();
+    return;
+  }
+  
+  if(uip_closed() ||
+     uip_aborted() ||
+     uip_timedout()) {
+    closed();
+  }  
+  
+  if(uip_acked()) {
+    acked();
+  }
+  
+  if(uip_newdata()) {
+    newdata();
+  }
+  
+  if(uip_rexmit() ||
+     uip_newdata() ||
+     uip_acked() ||
+     uip_connected() ||
+     uip_poll()) {
+    senddata();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/telnetd.h b/contiki/apps/telnetd.h
new file mode 100644
index 0000000..38c92f4
--- /dev/null
+++ b/contiki/apps/telnetd.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003, 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. 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: telnetd.h,v 1.2 2004/07/04 11:35:08 adamdunkels Exp $
+ *
+ */
+#ifndef __TELNETD_H__
+#define __TELNETD_H__
+
+#include "contiki.h"
+
+LOADER_INIT_FUNC(telnetd_init, arg);
+/*DISPATCHER_UIPCALL(telnetd_appcall, s);
+  DISPATCHER_SIGHANDLER(telnetd_gui_sighandler, s, data);*/
+void telnetd_gui_eventhandler(ek_event_t ev, ek_data_t data);
+void telnetd_appcall(void *data);
+void telnetd_gui_output(char *str1, char *str2);
+void telnetd_gui_quit(void);
+void telnetd_quit(void);
+
+#endif /* __TELNETD_H__ */
diff --git a/contiki/apps/vnc-draw.h b/contiki/apps/vnc-draw.h
new file mode 100644
index 0000000..724db43
--- /dev/null
+++ b/contiki/apps/vnc-draw.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. 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 VNC client.
+ *
+ * $Id: vnc-draw.h,v 1.2 2004/06/06 06:03:03 adamdunkels Exp $
+ *
+ */
+
+#ifndef __VNC_DRAW_H__
+#define __VNC_DRAW_H__
+
+#include "uip_arch.h"
+
+/* Pointer to the bitmap area in memory. */
+extern u8_t vnc_draw_bitmap[];
+
+/* Initialize the vnc-draw module. */
+void vnc_draw_init(void);
+
+/* Draw one line of pixels starting at point (x, y). The pixel data is
+   given by the "data" argument and the length of data is given by the
+   "datalen" argument. The data format is one pixel per byte in bgr233
+   format (bbgggrrr). */
+void vnc_draw_pixelline(u16_t x, u16_t y,
+			u8_t *data, u16_t datalen);
+
+/* The following functions should return the x and y coordinates and
+   the width and height of the viewport. */
+u16_t vnc_draw_viewport_x(void);
+u16_t vnc_draw_viewport_y(void);
+u16_t vnc_draw_viewport_w(void);
+u16_t vnc_draw_viewport_h(void);
+
+#endif /* __VNC_DRAW_H__ */
diff --git a/contiki/apps/vnc-dsc.c b/contiki/apps/vnc-dsc.c
new file mode 100644
index 0000000..ad88987
--- /dev/null
+++ b/contiki/apps/vnc-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: vnc-dsc.c,v 1.6 2005/04/19 22:00:54 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon vnc_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(vnc_dsc,
+    "Remote control your PC using Contiki",
+    "vnc.prg",
+    vnc_init,
+    &vnc_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+static unsigned char vncicon_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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char vncicon_textmap[9] = {
+  'V', 'N', 'C',
+  'c', 'l', 'i',
+  'e', 'n', 't'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon vnc_icon =
+  {CTK_ICON("VNC viewer", vncicon_bitmap, vncicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/vnc-dsc.h b/contiki/apps/vnc-dsc.h
new file mode 100644
index 0000000..f9f5241
--- /dev/null
+++ b/contiki/apps/vnc-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: vnc-dsc.h,v 1.1 2003/07/31 23:48:29 adamdunkels Exp $
+ *
+ */
+#ifndef __VNC_DSC_H__
+#define __VNC_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(vnc_dsc);
+
+#endif /* __VNC_DSC_H__ */
diff --git a/contiki/apps/vnc-viewer.c b/contiki/apps/vnc-viewer.c
new file mode 100644
index 0000000..8deb6bb
--- /dev/null
+++ b/contiki/apps/vnc-viewer.c
@@ -0,0 +1,755 @@
+/*
+ * 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. 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: vnc-viewer.c,v 1.9 2004/09/12 07:32:05 adamdunkels Exp $
+ *
+ */
+
+/* A micro implementation of a VNC client. VNC is a protocol for
+   remote network displays. See http://www.uk.research.att.com/vnc/
+   for information about VNC.
+*/
+
+#include "vnc-draw.h"
+#include "uip.h"
+#include "vnc-viewer.h"
+
+#include <string.h> /* XXX for memcpy */
+#include <stdio.h>  /* XXX for printf */
+
+/* RFB server initial handshaking string. */
+#define RFB_SERVER_VERSION_STRING rfb_server_version_string
+
+/* "RFB 003.003" */
+static u8_t rfb_server_version_string[12] =
+  {82,70,66,32,48,48,51,46,48,48,51,10};
+
+#if 0
+#define PRINTF(x)
+#else
+#define PRINTF(x) printf x
+#endif
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+static struct vnc_viewer_state vnc_viewer_state;
+#define vs (&vnc_viewer_state)
+
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_viewer_init(void)
+{
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_viewer_close(void)
+{
+  vs->close = 1;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_viewer_connect(u16_t *server, u8_t display)
+{
+  struct uip_conn *conn;
+
+  vnc_draw_init();
+
+  memset(vs, 0, sizeof(struct vnc_viewer_state));
+  conn = uip_connect(server, htons(5900 + display));
+  if(conn == NULL) {
+    return;
+  }
+  tcp_markconn(conn, NULL);
+
+  vs->close = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+senddata(void)
+{
+  register u8_t *dataptr;
+  u16_t dataleft;
+
+  dataptr = (u8_t *)uip_appdata;
+    
+  switch(vs->sendmsg) {
+  case VNC_SEND_VERSION:
+    PRINTF(("Sending VERSION_STRING\n"));
+    uip_send(RFB_SERVER_VERSION_STRING, sizeof(RFB_SERVER_VERSION_STRING));
+    break;
+  case VNC_SEND_AUTH:
+    /* Send 16 bytes of encrypted challange response. */
+    /* XXX: not implemented. */
+    PRINTF(("Sending AUTH\n"));
+    uip_send(uip_appdata, 16);
+    break;
+  case VNC_SEND_CINIT:
+    PRINTF(("Sending CINIT\n"));
+    /* Send one byte of client init. */
+    *(u8_t *)dataptr = 1;
+    uip_send(uip_appdata, 1);
+    break;
+  case VNC_SEND_PFMT:
+    PRINTF(("Sending PFMT\n"));
+    ((struct rfb_set_pixel_format *)dataptr)->type = RFB_SET_PIXEL_FORMAT;
+
+    /* Set to BGR233 pixel format. */
+    ((struct rfb_set_pixel_format *)dataptr)->format.bps = 8;
+    ((struct rfb_set_pixel_format *)dataptr)->format.depth = 8;
+    ((struct rfb_set_pixel_format *)dataptr)->format.endian = 1;
+    ((struct rfb_set_pixel_format *)dataptr)->format.truecolor = 1;
+    ((struct rfb_set_pixel_format *)dataptr)->format.red_max = htons(7);
+    ((struct rfb_set_pixel_format *)dataptr)->format.green_max = htons(7);
+    ((struct rfb_set_pixel_format *)dataptr)->format.blue_max = htons(3);
+    ((struct rfb_set_pixel_format *)dataptr)->format.red_shift = 0;
+    ((struct rfb_set_pixel_format *)dataptr)->format.green_shift = 3;
+    ((struct rfb_set_pixel_format *)dataptr)->format.blue_shift = 6;
+
+    uip_send(uip_appdata, sizeof(struct rfb_set_pixel_format));
+    
+    break;
+  case VNC_SEND_ENCODINGS:
+    PRINTF(("Sending ENCODINGS\n"));
+    ((struct rfb_set_encodings *)dataptr)->type = RFB_SET_ENCODINGS;
+    ((struct rfb_set_encodings *)dataptr)->encodings = htons(1);
+    dataptr += sizeof(struct rfb_set_encodings);
+    dataptr[0] = dataptr[1] = dataptr[2] = 0;
+    dataptr[3] = RFB_ENC_RAW;
+    /*    ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[4] =
+      ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[5] =
+      ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[6] = 0;
+      ((u8_t *)dataptr + sizeof(struct rfb_set_encodings))[7] = RFB_ENC_RRE;*/
+    uip_send(uip_appdata, sizeof(struct rfb_set_encodings) + 4);
+    break;
+  case VNC_SEND_UPDATERQ:
+    ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ;
+    ((struct rfb_fb_update_request *)dataptr)->incremental = 0;
+    ((struct rfb_fb_update_request *)dataptr)->x = htons(vnc_draw_viewport_x());
+    ((struct rfb_fb_update_request *)dataptr)->y = htons(vnc_draw_viewport_y());
+    ((struct rfb_fb_update_request *)dataptr)->w = htons(vnc_draw_viewport_w());
+    ((struct rfb_fb_update_request *)dataptr)->h = htons(vnc_draw_viewport_h());
+    uip_send(uip_appdata, sizeof(struct rfb_fb_update_request));    
+    break;
+  case VNC_SEND_UPDATERQ_INC:
+    ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ;
+    ((struct rfb_fb_update_request *)dataptr)->incremental = 1;
+    ((struct rfb_fb_update_request *)dataptr)->x = htons(vnc_draw_viewport_x());
+    ((struct rfb_fb_update_request *)dataptr)->y = htons(vnc_draw_viewport_y());
+    ((struct rfb_fb_update_request *)dataptr)->w = htons(vnc_draw_viewport_w());
+    ((struct rfb_fb_update_request *)dataptr)->h = htons(vnc_draw_viewport_h());
+    uip_send(uip_appdata, sizeof(struct rfb_fb_update_request));    
+    break;
+
+  case VNC_SEND_EVENTS:
+
+    dataleft = uip_mss();
+
+    vs->eventptr_unacked = vs->eventptr_acked;
+    while(vs->eventptr_unacked != vs->eventptr_next &&
+	  dataleft > sizeof(struct rfb_key_event)) {
+      switch(vs->event_queue[vs->eventptr_unacked].type) {
+      case VNC_POINTER_EVENT:
+	((struct rfb_pointer_event *)dataptr)->type = RFB_POINTER_EVENT;
+	((struct rfb_pointer_event *)dataptr)->buttonmask =
+	  vs->event_queue[vs->eventptr_unacked].ev.ptr.buttonmask;
+	((struct rfb_pointer_event *)dataptr)->x =
+	  htons(vs->event_queue[vs->eventptr_unacked].ev.ptr.x);
+	((struct rfb_pointer_event *)dataptr)->y =
+	  htons(vs->event_queue[vs->eventptr_unacked].ev.ptr.y);
+	/*	uip_send(uip_appdata, sizeof(struct rfb_pointer_event));*/
+	dataptr += sizeof(struct rfb_pointer_event);
+	dataleft -= sizeof(struct rfb_pointer_event);
+      break;
+      case VNC_KEY_EVENT:
+	PRINTF(("Send key event.\n"));
+	((struct rfb_key_event *)dataptr)->type = RFB_KEY_EVENT;
+	((struct rfb_key_event *)dataptr)->down =
+	  vs->event_queue[vs->eventptr_unacked].ev.key.down;
+	((struct rfb_key_event *)dataptr)->key[0] =
+	  ((struct rfb_key_event *)dataptr)->key[1];
+	((struct rfb_key_event *)dataptr)->key[2] =
+	  vs->event_queue[vs->eventptr_unacked].ev.key.key >> 8;
+	
+	((struct rfb_key_event *)dataptr)->key[3] =
+	  vs->event_queue[vs->eventptr_unacked].ev.key.key & 0xff;
+	/*	uip_send(uip_appdata, sizeof(struct rfb_key_event));*/
+	dataptr += sizeof(struct rfb_key_event);
+	dataleft -= sizeof(struct rfb_key_event);
+	break;
+      case VNC_UPDATERQ_EVENT:
+	((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ;
+	((struct rfb_fb_update_request *)dataptr)->incremental = 0;
+	((struct rfb_fb_update_request *)dataptr)->x =
+	  htons(vs->event_queue[vs->eventptr_unacked].ev.urq.x);
+	((struct rfb_fb_update_request *)dataptr)->y =
+	  htons(vs->event_queue[vs->eventptr_unacked].ev.urq.y);
+	((struct rfb_fb_update_request *)dataptr)->w =
+	  htons(vs->event_queue[vs->eventptr_unacked].ev.urq.w);
+	((struct rfb_fb_update_request *)dataptr)->h =
+	  htons(vs->event_queue[vs->eventptr_unacked].ev.urq.h);
+	/*	uip_send(uip_appdata, sizeof(struct rfb_fb_update_request));    */
+	dataptr += sizeof(struct rfb_fb_update_request);
+	dataleft -= sizeof(struct rfb_fb_update_request);
+	break;
+      }
+      vs->eventptr_unacked = (vs->eventptr_unacked + 1) % VNC_EVENTQUEUE_SIZE;
+    }
+
+    uip_send(uip_appdata, uip_mss() - dataleft);
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+buffer_data(u8_t *data, u16_t datalen)
+{
+  PRINTF(("Buffering %d bytes of data\n", datalen));
+
+  if(vs->buffersize + datalen > VNC_BUFFERSIZE) {
+    PRINTF(("Out of buffer space!\n"));
+    vs->buffersize = 0;
+    return;
+  }
+  
+  memcpy(&(vs->buffer[vs->buffersize]), data, datalen);
+
+  vs->buffersize += datalen;
+  vs->bufferleft -= datalen;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+clearbuffer(void)
+{
+  PRINTF(("Clearing buffer\n"));
+  vs->buffersize = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/* Returns: the amount of bytes actually read. */
+static u16_t
+recv_rectstate(u8_t *dataptr, u16_t datalen)
+{
+  u16_t pixels;
+  u16_t pixelsleft;
+  
+  switch(vs->rectstate) {
+  case VNC_RECTSTATE_RAW:
+    
+    if(vs->rectstateleft > datalen) {
+      pixels = datalen;
+      vs->rectstateleft -= datalen;
+    } else {
+      pixels = vs->rectstateleft;
+      datalen = datalen - vs->rectstateleft;
+      vs->rectstateleft = 0;
+      vs->rectstate = VNC_RECTSTATE_NONE;
+      vs->sendmsg = VNC_SEND_NONE;
+      vs->waitmsg = VNC_WAIT_NONE;
+      vnc_viewer_refresh();
+    }
+
+
+    pixelsleft = pixels;
+    while(pixelsleft > 0) {
+      if(pixelsleft >= vs->rectstatex2 - vs->rectstatex) {
+	vnc_draw_pixelline(vs->rectstatex, vs->rectstatey,
+			   dataptr,
+			   vs->rectstatex2 - vs->rectstatex);
+	dataptr += vs->rectstatex2 - vs->rectstatex;
+	pixelsleft -= vs->rectstatex2 - vs->rectstatex;
+	vs->rectstatex = vs->rectstatex0;
+	++vs->rectstatey;
+	vnc_viewer_refresh();
+      } else {
+	vnc_draw_pixelline(vs->rectstatex, vs->rectstatey,
+			   dataptr,
+			   pixelsleft);
+	vs->rectstatex += pixelsleft;
+	pixelsleft = 0;
+      }
+      
+    }
+        
+    break;
+  case VNC_RECTSTATE_RRE:
+    break;
+  }
+  return pixels;
+}
+/*-----------------------------------------------------------------------------------*/
+/* Returns: the amount of bytes that needs to be buffered before the
+   rect can be drawn. */ 
+static unsigned short
+recv_update_rect(register struct rfb_fb_update_rect_hdr *rhdr,
+		 u16_t dataleft)
+{
+  struct rfb_rre_hdr *rrehdr;			       
+
+
+  if((rhdr->encoding[0] |
+      rhdr->encoding[1] |
+      rhdr->encoding[2]) == 0) {
+    switch(rhdr->encoding[3]) {
+    case RFB_ENC_RAW:
+      vs->rectstateleft = (u32_t)htons(rhdr->rect.w) * (u32_t)htons(rhdr->rect.h);
+      vs->rectstate = VNC_RECTSTATE_RAW;
+      vs->rectstatex0 = vs->rectstatex = htons(rhdr->rect.x);
+      vs->rectstatey0 = vs->rectstatey = htons(rhdr->rect.y);
+      vs->rectstatew = htons(rhdr->rect.w);
+      vs->rectstateh = htons(rhdr->rect.h);
+      vs->rectstatex2 = vs->rectstatex0 + vs->rectstatew;
+      vs->rectstatey2 = vs->rectstatey0 + vs->rectstateh;
+      break;
+
+    case RFB_ENC_RRE:
+      rrehdr = (struct rfb_rre_hdr *)((u8_t *)rhdr +
+				      sizeof(struct rfb_fb_update_rect_hdr));
+      PRINTF(("Received RRE subrects %d (%d)\n",
+	     (htons(rrehdr->subrects[1]) << 16) +
+	     htons(rrehdr->subrects[0]),
+	     rrehdr->bgpixel));
+      vs->rectstateleft = ((u32_t)(htons(rrehdr->subrects[1]) << 16) + 
+			(u32_t)htons(rrehdr->subrects[0]));
+      vs->rectstate = VNC_RECTSTATE_RRE;
+
+      break;
+
+    default:
+      PRINTF(("Bad encoding %02x%02x%02x%02x\n", rhdr->encoding[0],
+	      rhdr->encoding[1],rhdr->encoding[2],rhdr->encoding[3]));
+      break;
+    }
+
+  }
+
+  return 0;
+	
+  PRINTF(("recv_update_rect: returning%d\n", vs->rectstateleft));
+  return sizeof(struct rfb_fb_update_rect_hdr) + vs->rectstateleft;
+}
+/*-----------------------------------------------------------------------------------*/
+/* identify_data():
+ *
+ * This function looks at the state of the connection (i.e., if it is
+ * handshaking or in steady-state) as well as on the contents of the
+ * incoming message and returns the number of bytes of data that is to
+ * be expected.
+ */ 
+static u16_t
+identify_data(register u8_t *data, u16_t datalen)
+{
+  switch(vs->waitmsg) {
+  case VNC_WAIT_VERSION:
+    /* Expecting version string (12 bytes). */
+    return 12;
+    break;
+  case VNC_WAIT_AUTH:
+    return 4;
+    break;
+  case VNC_WAIT_AUTH_RESPONSE:
+    return 1;
+    break;
+  case VNC_WAIT_SINIT:
+    /* XXX: We should check that the entire message header is
+       received, otherwise we should buffer it. */
+    return sizeof(struct rfb_server_init) +
+      ((struct rfb_server_init *)uip_appdata)->namelength[3] +
+      ((struct rfb_server_init *)uip_appdata)->namelength[2]; 
+    
+  case VNC_WAIT_UPDATE:
+  case VNC_WAIT_NONE:
+    switch(*data) {
+    case RFB_FB_UPDATE:
+      PRINTF(("RFB FB UPDATE received\n"));
+      return sizeof(struct rfb_fb_update);
+      
+    case RFB_BELL:
+      return 1;
+
+    case RFB_SERVER_CUT_TEXT:
+      PRINTF(("Cut text received, unhandled\n"));      
+      return 8 + (data[6] << 8) + data[7];
+
+    case RFB_SET_COLORMAP_ENTRIES:
+      uip_abort();
+      PRINTF(("Set colormap entries received, unhandled\n"));
+      return 0;
+      
+    default:
+      uip_abort();
+      PRINTF(("Weird message type received (%d)\n", *(u8_t *)uip_appdata));
+      return 0;
+    }
+    break;
+    
+  case VNC_WAIT_UPDATE_RECT:   
+    return sizeof(struct rfb_fb_update_rect_hdr);
+
+  default:
+    PRINTF(("identify: bad waitmsg %d\n", vs->waitmsg));
+  }
+  
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/* handle_data():
+ *
+ * Handles the data.
+ */
+static unsigned short
+handle_data(register u8_t *data, u16_t datalen)
+{
+  
+  switch(vs->waitmsg) {
+  case VNC_WAIT_VERSION:
+    /* Make sure we get the right version string from the server. */
+    /* XXX: not implemented. */
+    PRINTF(("Got version, waiting for auth, sending version\n"));
+    vs->waitmsg = VNC_WAIT_AUTH;
+    vs->sendmsg = VNC_SEND_VERSION;
+    break;
+  case VNC_WAIT_AUTH:
+    switch(data[3]) {
+    case RFB_AUTH_FAILED:
+      PRINTF(("Connection failed.\n"));
+      uip_abort();
+      return 0;
+      
+    case RFB_AUTH_NONE:
+      vs->sendmsg = VNC_SEND_CINIT;
+      vs->waitmsg = VNC_WAIT_SINIT;
+      PRINTF(("No authentication needed.\n"));
+      break;
+    case RFB_AUTH_VNC:
+      vs->sendmsg = VNC_SEND_AUTH;
+      vs->waitmsg = VNC_WAIT_AUTH_RESPONSE;
+      PRINTF(("VNC authentication needed.\n"));
+      break;
+    }
+    break;
+  case VNC_WAIT_SINIT:
+    /*    PRINTF(("Server init: w %d h %d, bps %d, d %d, name '%s'\n",
+	   htons(((struct rfb_server_init *)data)->width),
+	   htons(((struct rfb_server_init *)data)->height),
+	   ((struct rfb_server_init *)data)->format.bps,
+	   ((struct rfb_server_init *)data)->format.depth,
+	   ((u8_t *)data + sizeof(struct rfb_server_init))));*/
+    vs->w = htons(((struct rfb_server_init *)data)->width);
+    vs->h = htons(((struct rfb_server_init *)data)->height);
+    vs->sendmsg = VNC_SEND_PFMT;
+    vs->waitmsg = VNC_WAIT_NONE;
+    break;
+
+  case VNC_WAIT_UPDATE:
+  case VNC_WAIT_NONE:
+    switch(*data) {
+    case RFB_FB_UPDATE:
+      vs->waitmsg = VNC_WAIT_UPDATE_RECT;
+      vs->rectsleft = htons(((struct rfb_fb_update *)data)->rects);
+      PRINTF(("Handling RFB FB UPDATE for %d rects\n", vs->rectsleft));
+      break;
+      
+    case RFB_BELL:
+      PRINTF(("BELL\n"));
+      break;
+
+    case RFB_SERVER_CUT_TEXT:
+      PRINTF(("Cut text received, unhandled\n"));      
+      break;
+
+    case RFB_SET_COLORMAP_ENTRIES:
+      PRINTF(("Set colormap entries received, unhandled\n"));
+      break;
+      
+    default:
+      PRINTF(("Weird message type received (%d)\n", *(u8_t *)data));
+      break;
+    }
+    break;
+    
+  case VNC_WAIT_UPDATE_RECT:
+    PRINTF(("Handling data in WAIT_UPDATE_RECT, %d rects left (%d bytes)\n", vs->rectsleft, datalen));
+    --vs->rectsleft;
+    if(vs->rectsleft > 0) {
+      vs->waitmsg = VNC_WAIT_UPDATE_RECT;
+    } else {
+      vs->waitmsg = VNC_WAIT_NONE;
+      vs->sendmsg = VNC_SEND_NONE;
+      vs->rectstate = VNC_RECTSTATE_NONE;
+    }
+    return recv_update_rect((struct rfb_fb_update_rect_hdr *)data, datalen);
+    break;
+  }
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/* newdata():
+ *
+ * Called whenever new data arrives.
+ *
+ * First, checks if data needs to be buffered before a previously
+ * identified request can be fulfilled. If so, the incoming data is
+ * buffered and the data handler is called. If no data needs to be
+ * buffered, the code proceeds to identify the incoming request. If
+ * the incoming request can be processed immediately (i.e., all data
+ * is contained in this message) the data handler is invoked. If data
+ * has to be buffered to fulfill the request, this is noted and taken
+ * care of the next time this function is invoked (i.e., for the next
+ * incoming data chunk).
+ */
+static u8_t
+newdata(void)
+{
+  u16_t datalen;
+  u16_t readlen;
+  u8_t *dataptr;
+  
+  datalen = uip_datalen();
+  dataptr = (u8_t *)uip_appdata;
+
+  PRINTF(("newdata: %d bytes\n", datalen));
+  
+  /* If we are in a "rectstate", meaning that the incoming data is
+     part of a rectangle that is being incrementaly drawn on the
+     screen, we handle that first. */
+  if(vs->rectstate != VNC_RECTSTATE_NONE) {
+    readlen = recv_rectstate(dataptr, datalen);
+    PRINTF(("newdata: vs->rectstate %d, datalen %d, readlen %d\n",
+	    vs->rectstate, datalen, readlen));
+    datalen -= readlen;
+    dataptr += readlen;
+  }
+
+  /* Next, check if we are supposed to buffer data from the incoming
+     segment. */
+  while(vs->bufferleft > 0 && datalen > 0) {
+    if(datalen >= vs->bufferleft) {
+      /* There is more data in the incoming chunk than we need to
+	 buffer, so we buffer as much as we can and handle the
+	 buffered data, and repeat the (identify->buffer->handle)
+	 sequence for the data that is left in the incoming chunk. */
+      datalen -= vs->bufferleft;
+      dataptr += vs->bufferleft;
+      buffer_data((u8_t *)uip_appdata, vs->bufferleft);
+      handle_data(vs->buffer, vs->buffersize);
+      clearbuffer();
+    } else { /* datalen < vs->bufferleft */
+      /* We need to buffer more data than was received with this
+         chunk, so we buffer the avaliable data and return. */
+      buffer_data(dataptr, datalen);      
+      return 0;
+    }
+  }
+
+  /* Finally, if there is data left in the segment, we handle it. */
+  while(datalen > 0) {
+
+    if(vs->rectstate != VNC_RECTSTATE_NONE) {
+      readlen = recv_rectstate(dataptr, datalen);
+      PRINTF(("newdata (2): vs->rectstate %d, datalen %d, readlen %d\n",
+	      vs->rectstate, datalen, readlen));
+      datalen -= readlen;
+      dataptr += readlen;
+    } else {
+ 
+      /* We get here if there is data to be identified in the incoming
+	 chunk. */    
+      readlen = identify_data(dataptr, datalen);
+
+      if(readlen == 0) {
+	PRINTF(("Identify returned 0\n"));
+	return 0;
+      }
+
+      PRINTF(("Reading %d bytes more\n", readlen));
+      /* The data has been identified and the amount of data that
+	 needs to be read to be able to process the data is in the
+	 "readlen" variable. If the incoming chunk contains enough
+	 data, we handle it directly, otherwise we buffer the incoming
+	 data and set the state so that we know that there is more
+	 data to be buffered. */
+      if(readlen > datalen) {
+	clearbuffer(); /* Should not be needed, but just in case... */
+	vs->bufferleft = readlen;      
+	buffer_data(dataptr, datalen);
+	return 0;
+      }      
+      if(readlen <= datalen) {
+	PRINTF(("Before handle_data %d\n", readlen));
+	readlen += handle_data(dataptr, readlen);
+	PRINTF(("After handle_data %d\n", readlen));
+	datalen -= readlen;
+	dataptr += readlen;
+      }
+
+    }
+    if(datalen > 0) {
+      PRINTF(("newdata: there is more data left after first iteration... %d\n", datalen));
+    }
+    
+  }
+  
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/* Called when there is nothing else to do - checks for any pending
+   events (mouse movements or keypresses). If no events are found, it
+   makes sure that we send out an incremental update request. */
+static void
+check_events(void)
+{
+  if(vs->sendmsg == VNC_SEND_NONE &&
+     vs->eventptr_next != vs->eventptr_acked &&
+     vs->eventptr_acked == vs->eventptr_unacked) {
+    vs->sendmsg = VNC_SEND_EVENTS;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+request_update(void)
+{
+  if(vs->sendmsg == VNC_SEND_NONE) {
+    vs->sendmsg = VNC_SEND_UPDATERQ_INC;
+    vs->waitmsg = VNC_WAIT_UPDATE;
+    PRINTF(("request_update: requesting\n"));
+  } else {
+    PRINTF(("request_update: not requesting\n"));
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+acked(void)
+{
+  switch(vs->sendmsg) {
+  case VNC_SEND_PFMT:
+    vs->sendmsg = VNC_SEND_ENCODINGS;    
+    break;
+  case VNC_SEND_ENCODINGS:
+    vs->sendmsg = VNC_SEND_UPDATERQ;
+    vs->waitmsg = VNC_WAIT_UPDATE;
+    clearbuffer();
+    break;
+  case VNC_SEND_EVENTS:
+    vs->eventptr_acked = vs->eventptr_unacked;
+    vs->sendmsg = VNC_SEND_NONE;
+    check_events();
+    break;
+  default:
+    vs->sendmsg = VNC_SEND_NONE;
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_viewer_appcall(void * nullptr)
+{
+  if(vs->close == 1) {
+    uip_close();
+    return;
+  }
+  
+  if(uip_connected()) {
+    vs->sendmsg = VNC_SEND_NONE;
+    vs->waitmsg = VNC_WAIT_VERSION;
+    return;
+  }
+  
+  if(uip_acked()) {
+    acked();
+  }
+
+  if(uip_newdata()) {
+    newdata();
+  }
+
+  if(vs->sendmsg == VNC_SEND_NONE &&
+     vs->waitmsg == VNC_WAIT_NONE &&
+     vs->rectstate == VNC_RECTSTATE_NONE) {
+    check_events();
+    request_update();
+  }
+  PRINTF(("vs->sendmsg %d, vs->waitmsg %d, vs->rectstate %d\n",
+	  vs->sendmsg, vs->waitmsg, vs->rectstate));
+  
+  if(uip_rexmit() ||
+     uip_newdata() ||
+     uip_acked()) {
+    senddata();
+  } else if(uip_poll()) {
+    check_events();
+    senddata();
+  }  
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_viewer_post_event(u8_t type,
+		      u16_t data1, u16_t data2,
+		      u16_t data3, u16_t data4)
+{
+  register struct vnc_event *ev;
+  struct vnc_event *ev0;
+
+  ev0 = &(vs->event_queue[(vs->eventptr_next - 1) % VNC_EVENTQUEUE_SIZE]);
+    
+  ev = &(vs->event_queue[vs->eventptr_next]);
+  switch(type) {
+  case VNC_POINTER_EVENT:
+    if(0 && vs->eventptr_next != vs->eventptr_acked &&
+       ev0->type == VNC_POINTER_EVENT &&
+       data1 == ev0->ev.ptr.buttonmask) {
+      ev0->ev.ptr.x = data2;
+      ev0->ev.ptr.y = data3;
+      return;
+    } else {
+      ev->type = type;
+      ev->ev.ptr.buttonmask = data1;
+      ev->ev.ptr.x = data2;
+      ev->ev.ptr.y = data3;
+    }
+    break;
+  case VNC_KEY_EVENT:
+    PRINTF(("Key event posted\n"));
+    ev->type = type;
+    ev->ev.key.down = data1;
+    ev->ev.key.key = data2;
+    break;
+  case VNC_UPDATERQ_EVENT:
+    PRINTF(("Update request event posted\n"));
+    ev->type = type;
+    ev->ev.urq.x = data1;
+    ev->ev.urq.y = data2;
+    ev->ev.urq.w = data3;
+    ev->ev.urq.h = data4;
+    break;
+  }
+  vs->eventptr_next = (vs->eventptr_next + 1) % VNC_EVENTQUEUE_SIZE;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/vnc-viewer.h b/contiki/apps/vnc-viewer.h
new file mode 100644
index 0000000..e331f76
--- /dev/null
+++ b/contiki/apps/vnc-viewer.h
@@ -0,0 +1,328 @@
+/*
+ * 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. 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 VNC client.
+ *
+ * $Id: vnc-viewer.h,v 1.8 2004/09/12 07:33:26 adamdunkels Exp $
+ *
+ */
+
+#ifndef __VNC_VIEWER_H__
+#define __VNC_VIEWER_H__
+
+#include "ek.h"
+
+struct vnc_viewer_state;
+
+typedef unsigned long u32_t;
+
+void vnc_viewer_init(void);
+void vnc_viewer_appcall(void *nullptr);
+
+void vnc_viewer_connect(u16_t *server, u8_t display);
+void vnc_viewer_close(void);
+
+/* Callback: redraws the VNC viewer bitmap area. */
+void vnc_viewer_refresh(void);
+
+#define VNC_POINTER_EVENT RFB_POINTER_EVENT
+#define VNC_KEY_EVENT     RFB_KEY_EVENT
+#define VNC_UPDATERQ_EVENT 7
+
+#define VNC_VIEWER_POST_POINTER_EVENT(x, y, button) \
+        vnc_viewer_post_event(VNC_POINTER_EVENT, button, x, y, 0)
+
+#define VNC_VIEWER_POST_KEY_EVENT(key) \
+        vnc_viewer_post_event(VNC_KEY_EVENT, key, 0, 0, 0)
+
+#define VNC_VIEWER_POST_UPDATERQ_EVENT(x1,y1,x2,y2) \
+        vnc_viewer_post_event(VNC_UPDATERQ_EVENT, x1, y1, x2, y2)
+
+void vnc_viewer_post_event(u8_t event,
+			   u16_t data1, u16_t data2,
+			   u16_t data3, u16_t data4);
+
+/* UIP_APPCALL: the name of the application function. This function
+   must return void and take no arguments (i.e., C type "void
+   appfunc(void)"). */
+#ifndef UIP_APPCALL
+#define UIP_APPCALL     vnc_viewer_app
+#endif 
+
+struct vnc_key_event {
+  u8_t down;
+  u16_t key;  
+};
+
+struct vnc_pointer_event {
+  u8_t buttonmask;
+  u16_t x, y;
+};
+
+struct vnc_updaterq_event {
+  u16_t x, y;
+  u16_t w, h;
+};
+
+struct vnc_event {
+  u8_t type;
+  union {
+    struct vnc_key_event key;
+    struct vnc_pointer_event ptr;
+    struct vnc_updaterq_event urq;
+  } ev;
+};
+
+enum vnc_sendmsg {
+  VNC_SEND_NONE,
+  
+  VNC_SEND_VERSION,
+  VNC_SEND_AUTH,
+  VNC_SEND_CINIT,
+  VNC_SEND_PFMT,
+  VNC_SEND_ENCODINGS,
+  
+  VNC_SEND_UPDATERQ,
+  VNC_SEND_UPDATERQ_INC,
+  VNC_SEND_EVENTS,
+};
+
+enum vnc_waitmsg {
+  VNC_WAIT_NONE,
+  
+  VNC_WAIT_VERSION,
+  VNC_WAIT_AUTH,
+  VNC_WAIT_AUTH_RESPONSE,
+  VNC_WAIT_SINIT,
+  
+  VNC_WAIT_UPDATE,
+  VNC_WAIT_UPDATE_RECT,  
+  
+};
+
+
+enum vnc_rectstate {
+  VNC_RECTSTATE_NONE,
+  VNC_RECTSTATE_RAW,
+  VNC_RECTSTATE_RRE,
+};
+
+struct vnc_viewer_state {
+  u8_t close;
+  u16_t w, h;
+  
+  u8_t sendmsg;
+
+  u8_t waitmsg;
+  
+  u16_t rectsleft;
+  
+  u8_t rectstate;  
+  u32_t rectstateleft;
+  u16_t rectstatex, rectstatey;
+  u16_t rectstateh, rectstatew;
+  u16_t rectstatex0, rectstatey0;
+  u16_t rectstatex2, rectstatey2;
+
+  
+  u16_t eventptr_acked;
+  u16_t eventptr_unacked;
+  u16_t eventptr_next;
+#define VNC_EVENTQUEUE_SIZE 32
+  struct vnc_event event_queue[VNC_EVENTQUEUE_SIZE];
+  
+  
+  u16_t bufferleft;
+  u16_t buffersize;
+#define VNC_BUFFERSIZE 64
+  u8_t buffer[VNC_BUFFERSIZE];
+};
+
+extern struct vnc_viewer_state vnc_viewer_state;
+
+/* Definitions of the RFB (Remote Frame Buffer) protocol
+   structures and constants. */
+
+#include "uipopt.h"
+
+
+/* Generic rectangle - x, y coordinates, width and height. */
+struct rfb_rect {
+  u16_t x;
+  u16_t y;
+  u16_t w;
+  u16_t h;
+};
+
+/* Pixel format definition. */
+struct rfb_pixel_format {
+  u8_t bps;       /* Bits per pixel: 8, 16 or 32. */
+  u8_t depth;     /* Color depth: 8-32 */
+  u8_t endian;    /* 1 - big endian (motorola), 0 - little endian
+		     (x86) */
+  u8_t truecolor; /* 1 - true color is used, 0 - true color is not used. */
+
+  /* The following fields are only used if true color is used. */
+  u16_t red_max, green_max, blue_max;
+  u8_t red_shift, green_shift, blue_shift;
+  u8_t pad1;
+  u16_t pad2;
+};
+
+
+/* RFB authentication constants. */
+
+#define RFB_AUTH_FAILED      0
+#define RFB_AUTH_NONE        1
+#define RFB_AUTH_VNC         2
+
+#define RFB_VNC_AUTH_OK      0
+#define RFB_VNC_AUTH_FAILED  1
+#define RFB_VNC_AUTH_TOOMANY 2
+
+/* RFB message types. */
+
+/* From server to client: */
+#define RFB_FB_UPDATE            0
+#define RFB_SET_COLORMAP_ENTRIES 1
+#define RFB_BELL                 2
+#define RFB_SERVER_CUT_TEXT      3
+
+/* From client to server. */
+#define RFB_SET_PIXEL_FORMAT     0
+#define RFB_FIX_COLORMAP_ENTRIES 1
+#define RFB_SET_ENCODINGS        2
+#define RFB_FB_UPDATE_REQ        3
+#define RFB_KEY_EVENT            4
+#define RFB_POINTER_EVENT        5
+#define RFB_CLIENT_CUT_TEXT      6
+
+/* Encoding types. */
+#define RFB_ENC_RAW      0
+#define RFB_ENC_COPYRECT 1
+#define RFB_ENC_RRE      2
+#define RFB_ENC_CORRE    3
+#define RFB_ENC_HEXTILE  4
+
+/* Message definitions. */
+
+/* Server to client messages. */
+
+struct rfb_server_init {
+  u16_t width;
+  u16_t height;
+  struct rfb_pixel_format format;
+  u8_t namelength[4];
+  /* Followed by name. */
+};
+
+struct rfb_fb_update {
+  u8_t type;
+  u8_t pad;
+  u16_t rects; /* Number of rectanges (struct rfb_fb_update_rect_hdr +
+		  data) that follows. */
+};
+
+struct rfb_fb_update_rect_hdr {
+  struct rfb_rect rect;
+  u8_t encoding[4];
+};
+
+struct rfb_copy_rect {
+  u16_t srcx;
+  u16_t srcy;
+};
+
+struct rfb_rre_hdr {
+  u16_t subrects[2];  /* Number of subrectangles (struct
+			 rfb_rre_subrect) to follow. */
+  u8_t bgpixel;
+};
+
+struct rfb_rre_subrect {
+  u8_t pixel;
+  struct rfb_rect rect;
+};
+
+struct rfb_corre_rect {
+  u8_t x;
+  u8_t y;
+  u8_t w;
+  u8_t h;
+};
+
+/* Client to server messages. */
+
+struct rfb_set_pixel_format {
+  u8_t type;
+  u8_t pad;
+  u16_t pad2;
+  struct rfb_pixel_format format;
+};
+
+struct rfb_fix_colormap_entries {
+  u8_t type;
+  u8_t pad;
+  u16_t firstcolor;
+  u16_t colors;
+};
+
+struct rfb_set_encodings {
+  u8_t type;
+  u8_t pad;
+  u16_t encodings;
+};
+
+struct rfb_fb_update_request {
+  u8_t type;
+  u8_t incremental;
+  u16_t x;
+  u16_t y;
+  u16_t w;
+  u16_t h;
+};
+
+struct rfb_key_event {
+  u8_t type;
+  u8_t down;
+  u16_t pad;
+  u8_t key[4];
+};
+
+#define RFB_BUTTON_MASK1 1
+#define RFB_BUTTON_MASK2 2
+#define RFB_BUTTON_MASK3 4
+struct rfb_pointer_event {
+  u8_t type;
+  u8_t buttonmask;
+  u16_t x;
+  u16_t y;
+};
+
+#endif /* __VNC_VIEWER_H__ */
diff --git a/contiki/apps/vnc.c b/contiki/apps/vnc.c
new file mode 100644
index 0000000..8853d14
--- /dev/null
+++ b/contiki/apps/vnc.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2003, 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. 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 VNC client
+ *
+ * $Id: vnc.c,v 1.10 2004/09/12 07:32:05 adamdunkels Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "contiki.h"
+
+#include "petsciiconv.h"
+#include "uiplib.h"
+#include "uip.h"
+#include "ctk.h"
+#include "ctk-mouse.h"
+#include "resolv.h"
+#include "telnet.h"
+#include "vnc.h"
+#include "vnc-draw.h"
+#include "vnc-viewer.h"
+#include "vnc-conf.h"
+
+#include "loader.h"
+
+#if 1
+#define PRINTF(x)
+#else
+#include <stdio.h>
+#define PRINTF(x) printf x
+#endif
+
+#define HEIGHT (4 + VNC_CONF_VIEWPORT_HEIGHT/8)
+
+/* Main window */
+static struct ctk_window mainwindow;
+
+static char host[20];
+static struct ctk_textentry hosttextentry =
+  {CTK_TEXTENTRY(0, 0, 18, 1, host, 18)};
+
+static char portentry[4];
+static struct ctk_textentry porttextentry =
+  {CTK_TEXTENTRY(21, 0, 3, 1, portentry, 3)};
+
+static struct ctk_button connectbutton =
+  {CTK_BUTTON(27, 0, 7, "Connect")};
+/*static struct ctk_button disconnectbutton =
+  {CTK_BUTTON(25, 3, 10, "Disconnect")};*/
+
+static struct ctk_separator sep1 =
+  {CTK_SEPARATOR(0, 1, 36)};
+
+static struct ctk_bitmap vncbitmap =
+  {CTK_BITMAP(2, 2,
+	      VNC_CONF_VIEWPORT_WIDTH / 8,
+	      VNC_CONF_VIEWPORT_HEIGHT / 8,
+	      vnc_draw_bitmap,
+	      VNC_CONF_VIEWPORT_WIDTH,
+	      VNC_CONF_VIEWPORT_HEIGHT)};
+
+static struct ctk_button leftbutton =
+  {CTK_BUTTON(6, HEIGHT - 1, 4, "Left")};
+
+static struct ctk_button upbutton =
+  {CTK_BUTTON(13, HEIGHT - 1, 2, "Up")};
+
+static struct ctk_button downbutton =
+  {CTK_BUTTON(18, HEIGHT - 1, 4, "Down")};
+
+static struct ctk_button rightbutton =
+  {CTK_BUTTON(25, HEIGHT - 1, 5, "Right")};
+
+/*static DISPATCHER_SIGHANDLER(vnc_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("VNC client", NULL, vnc_sighandler,
+		   vnc_viewer_app)};
+		   static ek_id_t id;*/
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "VNC viewer", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(vnc_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+show(char *text)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+connect(void)
+{
+  u16_t addr[2], *addrptr;
+  u16_t port;
+  char *cptr;
+
+  /* Find the first space character in host and put a zero there
+     to end the string. */
+  for(cptr = host; *cptr != ' ' && *cptr != 0; ++cptr);
+  *cptr = 0;
+
+  addrptr = &addr[0];  
+  if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) {
+    addrptr = resolv_lookup(host);
+    if(addrptr == NULL) {
+      resolv_query(host);
+      show("Resolving host...");
+      return;
+    }
+  }
+
+  port = 0;
+  for(cptr = portentry; *cptr != ' ' && *cptr != 0; ++cptr) {
+    if(*cptr < '0' || *cptr > '9') {
+      show("Port number error");
+      return;
+    }
+    port = 10 * port + *cptr - '0';
+  }
+
+
+  vnc_viewer_connect(addrptr, port);
+
+  show("Connecting...");
+
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  unsigned short x, y;
+  unsigned char xc, yc;
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&mainwindow, 36, HEIGHT, "VNC client");
+    ctk_window_move(&mainwindow, 0, 0);
+    
+    CTK_WIDGET_ADD(&mainwindow, &hosttextentry);
+    CTK_WIDGET_FOCUS(&mainwindow, &hosttextentry);
+    CTK_WIDGET_ADD(&mainwindow, &porttextentry);
+    CTK_WIDGET_ADD(&mainwindow, &connectbutton);
+
+    CTK_WIDGET_ADD(&mainwindow, &sep1);
+    
+    CTK_WIDGET_ADD(&mainwindow, &vncbitmap);
+
+    CTK_WIDGET_ADD(&mainwindow, &leftbutton);
+    CTK_WIDGET_ADD(&mainwindow, &upbutton);
+    CTK_WIDGET_ADD(&mainwindow, &downbutton);
+    CTK_WIDGET_ADD(&mainwindow, &rightbutton);
+
+    vnc_draw_init();
+  
+    ctk_window_open(&mainwindow);
+
+  } else if(ev == ctk_signal_button_activate) {
+    if(data == (ek_data_t)&connectbutton) {
+      connect();
+    }
+  } else if(ev == ctk_signal_window_close) {
+    ek_exit();
+    id = EK_ID_NONE;
+    LOADER_UNLOAD();
+  } else if(ev == resolv_event_found) {
+    if(strcmp(data, host) == 0) {
+      if(resolv_lookup(host) != NULL) {
+	connect();
+      } else {
+	show("Host not found");
+      }
+    }
+  } else if(ev == ctk_signal_pointer_move) {
+    /* Check if pointer is within the VNC viewer area */
+    x = ctk_mouse_x();
+    y = ctk_mouse_y();
+
+    xc = ctk_mouse_xtoc(x);
+    yc = ctk_mouse_ytoc(y);
+    
+    if(xc >= 2 && yc >= 2 &&
+       xc < 2 + VNC_CONF_VIEWPORT_WIDTH / 8 &&
+       yc < 2 + VNC_CONF_VIEWPORT_HEIGHT / 8) {
+    
+      VNC_VIEWER_POST_POINTER_EVENT(x, y, 0);
+    }
+       
+  } else if(ev == tcpip_event) {
+    vnc_viewer_appcall(data);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_viewer_refresh(void)
+{
+  CTK_WIDGET_REDRAW(&vncbitmap);
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/vnc.h b/contiki/apps/vnc.h
new file mode 100644
index 0000000..4f64360
--- /dev/null
+++ b/contiki/apps/vnc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003, 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. 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 VNC client.
+ *
+ * $Id: vnc.h,v 1.3 2004/06/06 06:03:03 adamdunkels Exp $
+ *
+ */
+#ifndef __VNC_H__
+#define __VNC_H__
+
+void vnc_init(char *arg);
+
+#endif /* __VNC_H__ */
diff --git a/contiki/apps/webclient.c b/contiki/apps/webclient.c
new file mode 100644
index 0000000..7e09096
--- /dev/null
+++ b/contiki/apps/webclient.c
@@ -0,0 +1,446 @@
+/*
+ * 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. 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.18 2004/07/04 17:50:39 adamdunkels Exp $
+ *
+ */
+
+#include "ek.h"
+#include "tcpip.h"
+#include "uip.h"
+#include "webclient.h"
+#include "resolv.h"
+#include "uiplib.h"
+
+#include "www-conf.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[WWW_CONF_MAX_URLLEN];  
+  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 +
+    strlen(http_user_agent_fields) +
+    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; 
+  static u16_t addr[2];
+  
+  /* First check if the host is an IP address. */
+  ipaddr = &addr[0];
+  if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) {    
+    ipaddr = resolv_lookup(host);
+    
+    if(ipaddr == NULL) {
+      return 0;
+    }
+  }
+  
+  conn = tcp_connect(ipaddr, htons(port), NULL);
+  
+  if(conn == NULL) {
+    return 0;
+  }
+  
+  s.port = port;
+  strncpy(s.file, file, sizeof(s.file));
+  strncpy(s.host, host, sizeof(s.host));
+  
+  init_connection();
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char * CC_FASTCALL
+copy_string(unsigned char *dest,
+	    const 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_user_agent_fields,
+		       strlen(http_user_agent_fields));
+    
+    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 char
+casecmp(char *str1, const char *str2, char len)
+{
+  static char c;
+  
+  while(len > 0) {
+    c = *str1;
+    /* Force lower-case characters. */
+    if(c & 0x40) {
+      c |= 0x20;
+    }
+    if(*str2 != c) {
+      return 1;
+    }
+    ++str1;
+    ++str2;
+    --len;
+  }
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+static u16_t
+parse_headers(u16_t len)
+{
+  char *cptr;
+  static unsigned char i;
+  
+  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(casecmp(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(casecmp(s.httpheaderline, http_location,
+			    sizeof(http_location) - 1) == 0) {
+	cptr = s.httpheaderline +
+	  sizeof(http_location) - 1;
+	
+	if(strncmp(cptr, http_http, 7) == 0) {
+	  cptr += 7; 
+	  for(i = 0; i < s.httpheaderlineptr - 7; ++i) {
+	    if(*cptr == 0 ||
+	       *cptr == '/' ||
+	       *cptr == ' ' ||
+	       *cptr == ':') {
+	      s.host[i] = 0;
+	      break;
+	    }
+	    s.host[i] = *cptr;
+	    ++cptr;
+	  }
+	}
+	strncpy(s.file, cptr, sizeof(s.file));
+	/*	s.file[s.httpheaderlineptr - i] = 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)
+{
+  if(uip_connected()) {
+    s.timer = 0;
+    s.state = WEBCLIENT_STATE_STATUSLINE;
+    senddata();
+    webclient_connected();
+    tcp_markconn(uip_conn, &s);
+    return;
+  }
+
+  if(uip_timedout()) {
+    webclient_timedout();
+  }
+  
+  if(state == NULL) {
+    uip_abort();
+    return;
+  }
+
+  if(s.state == WEBCLIENT_STATE_CLOSE) {
+    webclient_closed();
+    uip_abort();
+    return;
+  }        
+
+  if(uip_aborted()) {
+    webclient_aborted();
+  }
+  
+  
+  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()) {
+    tcp_markconn(uip_conn, NULL);
+    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();
+	}*/
+      if(resolv_lookup(s.host) == NULL) {
+	resolv_query(s.host);
+      }
+      webclient_get(s.host, s.port, s.file);
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/webclient.h b/contiki/apps/webclient.h
new file mode 100644
index 0000000..eaaa1dc
--- /dev/null
+++ b/contiki/apps/webclient.h
@@ -0,0 +1,67 @@
+/*
+ * 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. 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.6 2004/07/04 17:50:39 adamdunkels Exp $
+ *
+ */
+#ifndef __WEBCLIENT_H__
+#define __WEBCLIENT_H__
+
+
+#include "http-strings.h"
+#include "http-user-agent-string.h"
+#include "resolv.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 *state);
+/*DISPATCHER_UIPCALL(webclient_appcall, state);*/
+
+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-dsc.c b/contiki/apps/webserver-dsc.c
new file mode 100644
index 0000000..576a6c2
--- /dev/null
+++ b/contiki/apps/webserver-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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: webserver-dsc.c,v 1.3 2005/03/18 00:49:42 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon webserver_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(webserver_dsc,
+    "The Contiki web server",
+    "webserver.prg",
+    webserver_init,
+    &webserver_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char webservericon_textmap[9] = {
+  '+', '-', '+',
+  '|', ')', '|',
+  '+', '-', '+'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon webserver_icon =
+  {CTK_ICON("Web server", webservericon_bitmap, webservericon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/webserver-dsc.h b/contiki/apps/webserver-dsc.h
new file mode 100644
index 0000000..789a57d
--- /dev/null
+++ b/contiki/apps/webserver-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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: webserver-dsc.h,v 1.1 2003/04/17 19:00:01 adamdunkels Exp $
+ *
+ */
+#ifndef __WEBSERVER_DSC_H__
+#define __WEBSERVER_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(webserver_dsc);
+
+#endif /* __WEBSERVER_DSC_H__ */
diff --git a/contiki/apps/webserver.c b/contiki/apps/webserver.c
new file mode 100644
index 0000000..ddc0f7e
--- /dev/null
+++ b/contiki/apps/webserver.c
@@ -0,0 +1,143 @@
+/*
+ * 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. 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.14 2005/03/01 06:03:25 adamdunkels Exp $
+ *
+ */
+
+
+#include "ctk.h"
+#include "ek.h"
+#include "http-strings.h"
+
+#include "loader.h"
+
+#include "webserver.h"
+#include "httpd.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/* The main window. */
+static struct ctk_window mainwindow;
+
+static struct ctk_label message =
+  {CTK_LABEL(0, 0, 15, 1, "Latest requests")};
+
+/*static DISPATCHER_SIGHANDLER(webserver_sighandler, s, data);
+
+static struct dispatcher_proc p =
+{DISPATCHER_PROC("Web server", NULL, webserver_sighandler,
+		 httpd_appcall)};
+static ek_id_t id;*/
+
+EK_EVENTHANDLER(webserver_eventhandler, ev, data);
+EK_PROCESS(p, "Web server", EK_PRIO_NORMAL,
+	   webserver_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+
+#define LOG_WIDTH  38
+#define LOG_HEIGHT 16
+static char log[LOG_WIDTH*LOG_HEIGHT];
+
+static struct ctk_label loglabel =
+{CTK_LABEL(0, 1, LOG_WIDTH, LOG_HEIGHT, log)};
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(webserver_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(webserver_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    ctk_window_new(&mainwindow, LOG_WIDTH, LOG_HEIGHT+1, "Web server");
+    
+    CTK_WIDGET_ADD(&mainwindow, &message);
+    CTK_WIDGET_ADD(&mainwindow, &loglabel);
+ 
+    httpd_init();
+
+    ctk_window_open(&mainwindow);
+  } else if(ev == ctk_signal_window_close ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    ctk_window_close(&mainwindow);
+    ek_exit();
+    id = EK_ID_NONE;
+    LOADER_UNLOAD();    
+  } else if(ev == tcpip_event) {
+    httpd_appcall(data);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+httpd_log_file(u16_t *requester, char *file)
+{
+  int size;
+  
+  /* Scroll previous entries upwards */
+  memcpy(log, &log[LOG_WIDTH], LOG_WIDTH * (LOG_HEIGHT - 1));
+
+  /* Print out IP address of requesting host. */
+  size = sprintf(&log[LOG_WIDTH * (LOG_HEIGHT - 1)],
+		 "%d.%d.%d.%d: ",
+		 htons(requester[0]) >> 8,
+		 htons(requester[0]) & 0xff,
+		 htons(requester[1]) >> 8,
+		 htons(requester[1]) & 0xff);
+  
+  /* Copy filename into last line. */		 
+  strncpy(&log[LOG_WIDTH * (LOG_HEIGHT - 1) + size], file, LOG_WIDTH - size);
+	   
+  /* Update log display. */
+  CTK_WIDGET_REDRAW(&loglabel);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+httpd_log(char *msg)
+{
+  /* Scroll previous entries upwards */
+  memcpy(log, &log[LOG_WIDTH], LOG_WIDTH * (LOG_HEIGHT - 1));
+
+  /* Copy filename into last line. */		 
+  strncpy(&log[LOG_WIDTH * (LOG_HEIGHT - 1)], msg, LOG_WIDTH);
+  
+  /* Update log display. */
+  CTK_WIDGET_REDRAW(&loglabel);
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/webserver.h b/contiki/apps/webserver.h
new file mode 100644
index 0000000..64f8d57
--- /dev/null
+++ b/contiki/apps/webserver.h
@@ -0,0 +1,45 @@
+/*
+ * 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. 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.5 2004/09/12 07:20:04 adamdunkels Exp $
+ *
+ */
+#ifndef __WEBSERVER_H__
+#define __WEBSERVER_H__
+
+#include "uip.h"
+
+void webserver_init(char *arg);
+void webserver_log(char *msg);
+void webserver_log_file(u16_t *requester, char *file);
+
+
+#endif /* __WEBSERVER_H__ */
diff --git a/contiki/apps/www-dsc.c b/contiki/apps/www-dsc.c
new file mode 100644
index 0000000..4d52b5e
--- /dev/null
+++ b/contiki/apps/www-dsc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003, 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. 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-dsc.c,v 1.4 2005/04/19 22:00:54 oliverschmidt Exp $
+ *
+ */
+
+#include "dsc.h"
+
+extern struct ctk_icon www_icon;
+/*-----------------------------------------------------------------------------------*/
+DSC(www_dsc,
+    "The Contiki web browser",
+    "www.prg",
+    www_init,
+    &www_icon);
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_ICON_BITMAPS
+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
+};
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+#if CTK_CONF_ICON_TEXTMAPS
+static char wwwicon_textmap[9] = {
+  'w', 'w', 'w',
+  '(', ')', ' ',
+  ' ', '(', ')'
+};
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+
+#if CTK_CONF_ICONS
+static struct ctk_icon www_icon =
+  {CTK_ICON("Web browser", wwwicon_bitmap, wwwicon_textmap)};
+#endif /* CTK_CONF_ICONS */
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/apps/www-dsc.h b/contiki/apps/www-dsc.h
new file mode 100644
index 0000000..18bba6b
--- /dev/null
+++ b/contiki/apps/www-dsc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 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. 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-dsc.h,v 1.1 2003/04/17 19:00:01 adamdunkels Exp $
+ *
+ */
+#ifndef __WWW_DSC_H__
+#define __WWW_DSC_H__
+
+#include "dsc.h"
+
+DSC_HEADER(www_dsc);
+
+#endif /* __WWW_DSC_H__ */
diff --git a/contiki/apps/www.c b/contiki/apps/www.c
new file mode 100644
index 0000000..225f255
--- /dev/null
+++ b/contiki/apps/www.c
@@ -0,0 +1,983 @@
+/*
+ * 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. 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.31 2005/06/12 23:44:30 oliverschmidt Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "ek.h"
+#include "ctk.h"
+#include "webclient.h"
+#include "htmlparser.h"
+#include "http-strings.h"
+#include "resolv.h"
+
+#include "petsciiconv.h"
+
+#include "program-handler.h"
+
+#include "uiplib.h"
+
+#include "tcpip.h"
+
+#include "loader.h"
+
+#include "www-conf.h"
+
+#if 1
+#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. */
+static char webpage[WWW_CONF_WEBPAGE_WIDTH *
+		    WWW_CONF_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(WWW_CONF_WEBPAGE_WIDTH - 16, 0, 4, "Stop")};
+static struct ctk_button gobutton =
+  {CTK_BUTTON(WWW_CONF_WEBPAGE_WIDTH - 4, 0, 2, "Go")};
+
+static struct ctk_separator sep1 =
+  {CTK_SEPARATOR(0, 2, WWW_CONF_WEBPAGE_WIDTH)};
+
+static char editurl[WWW_CONF_MAX_URLLEN + 1];
+static struct ctk_textentry urlentry =
+  {CTK_TEXTENTRY(0, 1, WWW_CONF_WEBPAGE_WIDTH - 2,
+		 1, editurl, WWW_CONF_MAX_URLLEN)};
+static struct ctk_label webpagelabel =
+  {CTK_LABEL(0, 3, WWW_CONF_WEBPAGE_WIDTH,
+	     WWW_CONF_WEBPAGE_HEIGHT, webpage)};
+
+static char statustexturl[WWW_CONF_WEBPAGE_WIDTH];
+static struct ctk_label statustext =
+  {CTK_LABEL(0, WWW_CONF_WEBPAGE_HEIGHT + 4,
+	     WWW_CONF_WEBPAGE_WIDTH, 1, "")};
+static struct ctk_separator sep2 =
+  {CTK_SEPARATOR(0, WWW_CONF_WEBPAGE_HEIGHT + 3,
+		 WWW_CONF_WEBPAGE_WIDTH)};
+
+static struct ctk_window wgetdialog;
+static struct ctk_label wgetlabel1 =
+  {CTK_LABEL(1, 1, 34, 1, "This web page cannot be displayed.")};
+static struct ctk_label wgetlabel2 =
+  {CTK_LABEL(1, 3, 35, 1, "Would you like to download instead?")};
+static struct ctk_button wgetnobutton =
+  {CTK_BUTTON(1, 5, 6, "Cancel")};
+static struct ctk_button wgetyesbutton =
+  {CTK_BUTTON(11, 5, 24, "Close browser & download")};
+
+/* The char arrays that hold the history of visited URLs. */
+static char history[WWW_CONF_HISTORY_SIZE][WWW_CONF_MAX_URLLEN];
+static char history_last;
+
+
+/* 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];
+#if WWW_CONF_FORMS
+  struct formattribs form;
+#endif /* WWW_CONF_FORMS */
+};
+static struct ctk_widget pagewidgets[WWW_CONF_MAX_NUMPAGEWIDGETS];
+static union pagewidgetattrib pagewidgetattribs[WWW_CONF_MAX_NUMPAGEWIDGETS];
+static unsigned char pagewidgetptr;
+
+#if WWW_CONF_RENDERSTATE
+static unsigned char renderstate;
+#endif /* WWW_CONF_RENDERSTATE */
+
+#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 char *webpageptr;
+static unsigned char x, y;
+static unsigned char loading;
+static unsigned short firsty, pagey;
+
+static unsigned char count;
+static char receivingmsgs[4][23] = {
+  "Receiving web page ...",
+  "Receiving web page. ..",
+  "Receiving web page.. .",
+  "Receiving web page... "
+};
+
+
+EK_EVENTHANDLER(www_eventhandler, ev, data);
+EK_PROCESS(p, "Web browser", EK_PRIO_NORMAL,
+	   www_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+/*static DISPATCHER_SIGHANDLER(www_sighandler, s, data);
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("Web browser", NULL, www_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_SET_FLAG(&webpagelabel, CTK_WIDGET_FLAG_MONOSPACE);
+  CTK_WIDGET_ADD(&mainwindow, &sep2);
+  CTK_WIDGET_ADD(&mainwindow, &statustext);
+
+  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.
+ */
+LOADER_INIT_FUNC(www_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    /*    id = dispatcher_start(&p);*/
+    id = ek_start(&p);
+    
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+clear_page(void)
+{
+  ctk_window_clear(&mainwindow);
+  make_window();
+  redraw_window();
+  memset(webpage, 0, WWW_CONF_WEBPAGE_WIDTH * WWW_CONF_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
+start_loading(void)
+{
+  loading = 1;
+  x = y = 0;
+  pagey = 0;
+  webpageptr = webpage;
+
+  clear_page();
+}
+/*-----------------------------------------------------------------------------------*/
+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;
+  static u16_t addr[2];
+
+  /* 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(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) {    
+    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. */
+  show_url();
+  open_url();
+
+
+  start_loading();
+}
+/*-----------------------------------------------------------------------------------*/
+/* log_back():
+ *
+ * Copies the current URL from the url variable and into the log for
+ * the back button.
+ */
+static void
+log_back(void)
+{
+  if(strncmp(url, history[(int)history_last], WWW_CONF_MAX_URLLEN) != 0) {
+    memcpy(history[(int)history_last], url, WWW_CONF_MAX_URLLEN);
+    ++history_last;
+    if(history_last >= WWW_CONF_HISTORY_SIZE) {
+      history_last = 0;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+quit(void)
+{
+  ctk_window_close(&mainwindow);
+  ek_exit();
+  id = EK_ID_NONE;
+  LOADER_UNLOAD();
+}
+/*-----------------------------------------------------------------------------------*/
+/* www_dispatcher():
+ *
+ * The program's signal dispatcher function. Is called by the ek
+ * dispatcher whenever a signal arrives.
+ */
+/*static
+  DISPATCHER_SIGHANDLER(www_sighandler, s, data)*/
+EK_EVENTHANDLER(www_eventhandler, ev, data)
+{
+  static struct ctk_widget *w;
+  static unsigned char i;
+  static char *argptr;
+  
+  /*  DISPATCHER_SIGHANDLER_ARGS(s, data);*/
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  
+  w = (struct ctk_widget *)data;
+
+  if(ev == tcpip_event) {
+    webclient_appcall(data);
+  } else if(ev == EK_EVENT_INIT) {
+    /* Create the main window. */
+    memset(webpage, 0, sizeof(webpage));
+    ctk_window_new(&mainwindow, WWW_CONF_WEBPAGE_WIDTH, 
+                   WWW_CONF_WEBPAGE_HEIGHT+5, "Web browser");
+    make_window();
+#ifdef WWW_CONF_HOMEPAGE
+    strncpy(editurl, WWW_CONF_HOMEPAGE, sizeof(editurl));
+#endif /* WWW_CONF_HOMEPAGE */    
+    CTK_WIDGET_FOCUS(&mainwindow, &urlentry);
+
+    /* Create download dialog.*/
+    ctk_dialog_new(&wgetdialog, 38, 7);
+    CTK_WIDGET_ADD(&wgetdialog, &wgetlabel1);
+    CTK_WIDGET_ADD(&wgetdialog, &wgetlabel2);
+    CTK_WIDGET_ADD(&wgetdialog, &wgetnobutton);
+    CTK_WIDGET_ADD(&wgetdialog, &wgetyesbutton);
+
+    ctk_window_open(&mainwindow);
+    
+  } else if(ev == ctk_signal_widget_activate) {
+    if(w == (struct ctk_widget *)&backbutton) {
+      firsty = 0;
+      start_loading();
+
+      --history_last;
+      if(history_last > WWW_CONF_HISTORY_SIZE) {
+	history_last = WWW_CONF_HISTORY_SIZE - 1;
+      }
+      memcpy(url, history[(int)history_last], WWW_CONF_MAX_URLLEN);
+      open_url();
+      CTK_WIDGET_FOCUS(&mainwindow, &backbutton);      
+    } else if(w == (struct ctk_widget *)&downbutton) {
+      firsty = pagey + WWW_CONF_WEBPAGE_HEIGHT - 4;
+      start_loading();
+      open_url();
+      CTK_WIDGET_FOCUS(&mainwindow, &downbutton);
+    } else if(w == (struct ctk_widget *)&gobutton ||
+	      w == (struct ctk_widget *)&urlentry) {
+      start_loading();
+      firsty = 0;
+
+      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) {
+      loading = 0;
+      webclient_close();
+    } else if(w == (struct ctk_widget *)&wgetnobutton) {
+      ctk_dialog_close();
+    } else if(w == (struct ctk_widget *)&wgetyesbutton) {
+      ctk_dialog_close();      
+      quit();
+      argptr = arg_alloc(WWW_CONF_MAX_URLLEN);
+      if(argptr != NULL) {
+	strncpy(argptr, url, WWW_CONF_MAX_URLLEN);
+      } 
+      program_handler_load("wget.prg", argptr);
+      
+#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(ev == ctk_signal_hyperlink_activate) {
+    firsty = 0;
+    log_back();
+    open_link(w->widget.hyperlink.url);
+    CTK_WIDGET_FOCUS(&mainwindow, &stopbutton);
+    /*    ctk_window_open(&mainwindow);*/
+  } else if(ev == ctk_signal_hyperlink_hover) {
+    if(CTK_WIDGET_TYPE((struct ctk_widget *)data) ==
+       CTK_WIDGET_HYPERLINK) {
+      strncpy(statustexturl, w->widget.hyperlink.url,
+	      sizeof(statustexturl));
+      petsciiconv_topetscii(statustexturl, sizeof(statustexturl));
+      show_statustext(statustexturl);
+    }
+  } else if(ev == resolv_event_found) {
+    /* Either found a hostname, or not. */
+    if((char *)data != NULL &&
+       resolv_lookup((char *)data) != NULL) {
+      open_url();
+    } else {
+      show_statustext("Host not found.");
+    }
+  } else if(ev == ctk_signal_window_close ||
+	    ev == EK_EVENT_REQUEST_EXIT) {
+    quit();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/* 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[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
+				 WWW_CONF_WEBPAGE_WIDTH], WWW_CONF_WEBPAGE_WIDTH);
+  CTK_WIDGET_FOCUS(&mainwindow, &downbutton);
+  redraw_window();
+}
+/*-----------------------------------------------------------------------------------*/
+/* webclient_closed():
+ *
+ * Callback function. Called from the webclient when the HTTP
+ * connection is connected.
+ */
+void
+webclient_connected(void)
+{
+  start_loading();
+    
+  clear_page();
+  
+  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();
+}
+/*-----------------------------------------------------------------------------------*/
+/* 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);
+      redraw_window();
+    } else {
+      uip_abort();
+      ctk_dialog_open(&wgetdialog);
+    }
+  } else {
+    /* Clear remaining parts of page. */
+    loading = 0;
+  }
+  
+  if(data == NULL) {
+    loading = 0;
+    show_statustext("Done.");
+    petsciiconv_topetscii(&webpage[(WWW_CONF_WEBPAGE_HEIGHT - 1) *
+				   WWW_CONF_WEBPAGE_WIDTH], WWW_CONF_WEBPAGE_WIDTH);
+    CTK_WIDGET_FOCUS(&mainwindow, &urlentry);
+    redraw_window();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void *
+add_pagewidget(char *text, unsigned char len, unsigned char type,
+		unsigned char border)
+{  
+  register struct ctk_widget *lptr;
+  register unsigned char *wptr;
+  static unsigned char maxwidth;
+  static void *dataptr;
+
+  if(!loading) {
+    return NULL;
+  }
+  
+  if(len + border == 0) {
+    return NULL;
+  }
+  
+  maxwidth = WWW_CONF_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) {
+    htmlparser_newline();
+    if(!loading) {
+      return NULL;
+    }
+  }
+
+  /* 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 a link into a multiline link, or add multiple
+     buttons. But this will do for now. */
+  if(len > maxwidth) {
+    text[maxwidth] = 0;
+    len = maxwidth;
+  }
+
+  dataptr = NULL;
+  
+  if(firsty == pagey) {
+    wptr = webpageptr;
+    /* To save memory, we'll copy the widget text to the web page
+       drawing area and reference it from there. */
+    wptr[0] = 0;
+    wptr += border;
+    memcpy(wptr, text, len);
+    wptr[len] = 0;
+    wptr[len + border] = ' ';
+    if(pagewidgetptr < WWW_CONF_MAX_NUMPAGEWIDGETS) {
+      dataptr = &pagewidgetattribs[pagewidgetptr];
+      lptr = &pagewidgets[pagewidgetptr];
+      
+      switch(type) {
+      case CTK_WIDGET_HYPERLINK:
+	CTK_HYPERLINK_NEW((struct ctk_hyperlink *)lptr, x,
+			  y + 3, len,
+			  wptr, dataptr);
+	break;
+      case CTK_WIDGET_BUTTON:
+	CTK_BUTTON_NEW((struct ctk_button *)lptr, x,
+		       y + 3, len,
+		       wptr);
+	((struct formattribs *)dataptr)->inputvalue = wptr;
+	break;
+      case CTK_WIDGET_TEXTENTRY:
+	CTK_TEXTENTRY_NEW((struct ctk_textentry *)lptr, x,
+			  y + 3, len, 1,
+			  wptr, len);
+	((struct formattribs *)dataptr)->inputvalue = wptr;
+	break;	
+      }
+      CTK_WIDGET_SET_FLAG(lptr, CTK_WIDGET_FLAG_MONOSPACE);
+      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. */
+  len = len + 1 + 2 * border;
+  x += len;
+
+  if(firsty == pagey) {
+    webpageptr += len;
+  }
+  
+  if(x == WWW_CONF_WEBPAGE_WIDTH) {
+    htmlparser_newline();
+  }
+
+  return dataptr;
+}
+/*-----------------------------------------------------------------------------------*/
+#if WWW_CONF_RENDERSTATE
+static void
+centerline(char *wptr)
+{
+  unsigned char spaces, i;
+  char *cptr;
+  register struct ctk_widget *linksptr;
+  
+  cptr = wptr + WWW_CONF_WEBPAGE_WIDTH;
+  for(spaces = 0; spaces < WWW_CONF_WEBPAGE_WIDTH; ++spaces) {
+    if(*--cptr != 0) {
+      break;
+    }
+  }
+  
+  spaces /= 2;
+
+  while(cptr >= wptr) {
+    *(cptr + spaces) = *cptr;
+    --cptr;
+  }
+
+  memset(wptr, ' ', spaces);
+  
+  linksptr = pagewidgets;
+  
+  for(i = 0; i < pagewidgetptr; ++i) {
+    if(CTK_WIDGET_YPOS(linksptr) == y + 2) {
+      linksptr->x += spaces;
+      linksptr->widget.hyperlink.text += spaces;
+    }
+    ++linksptr;
+  }
+}
+#endif /* WWW_CONF_RENDERSTATE */
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_newline(void)
+{
+  char *wptr;
+  
+  if(pagey < firsty) {
+    ++pagey;
+    x = 0;
+    return;
+  }
+  
+  if(!loading) {
+    return;
+  }
+
+  webpageptr += (WWW_CONF_WEBPAGE_WIDTH - x);
+  ++y;
+  x = 0;
+  
+  wptr = webpageptr - WWW_CONF_WEBPAGE_WIDTH;
+  petsciiconv_topetscii(wptr,
+			WWW_CONF_WEBPAGE_WIDTH);
+#if WWW_CONF_RENDERSTATE
+  if(renderstate & HTMLPARSER_RENDERSTATE_CENTER) {
+    centerline(wptr);
+  }
+#endif /* WWW_CONF_RENDERSTATE */  
+  
+  if(y == WWW_CONF_WEBPAGE_HEIGHT) {
+    loading = 0;
+    webclient_close();
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_word(char *word, unsigned char wordlen)
+{
+
+  if(loading) {
+    if(wordlen + 1 > WWW_CONF_WEBPAGE_WIDTH - x) {
+      htmlparser_newline();
+    }
+
+    if(loading) {
+      if(pagey == firsty) {
+	memcpy(webpageptr, word, wordlen);
+	webpageptr += wordlen;      
+	*webpageptr = ' ';
+	++webpageptr;
+      }
+      x += wordlen + 1;
+      if(x == WWW_CONF_WEBPAGE_WIDTH) {
+	htmlparser_newline();
+      }
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+htmlparser_link(char *text, unsigned char textlen, char *url)
+{
+  static unsigned char *linkurlptr;
+
+  linkurlptr = add_pagewidget(text, textlen, CTK_WIDGET_HYPERLINK, 0);
+  if(linkurlptr != NULL &&
+     strlen(url) < WWW_CONF_MAX_URLLEN) {
+    strcpy(linkurlptr, url);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+#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, strlen(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(unsigned char size, char *text, char *name,
+		      char *formname, char *formaction)
+{
+  register struct formattribs *form;
+
+  form = add_pagewidget(text, size, 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;
+  register char *urlptr, *valueptr;
+  register 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;
+  log_back();
+  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..3d9c9c6
--- /dev/null
+++ b/contiki/apps/www.h
@@ -0,0 +1,40 @@
+/*
+ * 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. 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.2 2004/06/06 06:03:03 adamdunkels Exp $
+ *
+ */
+#ifndef __WWW_H__
+#define __WWW_H__
+
+void www_init(void);
+
+#endif /* __WWW_H__ */
diff --git a/contiki/conf/FILES b/contiki/conf/FILES
new file mode 100644
index 0000000..72ec6f2
--- /dev/null
+++ b/contiki/conf/FILES
@@ -0,0 +1,30 @@
+The contiki/conf/ directory contains example configuration
+files.
+
+cc-conf.h.example
+
+  An example configuration file for C compiler tweaks.
+
+clock-conf.h.example
+
+  An example configuration file for the clock module.
+
+ctk-conf.h.example
+
+  An example configuration file for the CTK GUI module.
+
+ek-conf.h.example
+
+  An example configuration file for the Contiki event kernel.
+
+telnetd-conf.h.example
+
+  An example configuration file for the telnet server.
+
+uip-conf.h.example
+
+  An example configuration file for the uIP TCP/IP stack.
+
+www-conf.h.example
+
+  An example configuration file for the web browser.
\ No newline at end of file
diff --git a/contiki/conf/cc-conf.h.example b/contiki/conf/cc-conf.h.example
new file mode 100644
index 0000000..c4d2fdb
--- /dev/null
+++ b/contiki/conf/cc-conf.h.example
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: cc-conf.h.example,v 1.3 2004/07/04 11:37:34 adamdunkels Exp $
+ *
+ */
+#ifndef __CC_CONF_H__
+#define __CC_CONF_H__
+
+/* This file is used to configure stuff that depends on the
+   capabilities of the C compiler used. */
+
+/* CC_CONF_REGISTER_ARGS: 1 or 0; 1 if the C compiler can handle the
+   "register" keyword in function argument, 0 otherwise. */
+#define CC_CONF_REGISTER_ARGS          1
+
+/* CC_CONF_FUNCTION_POINTR_ARGS: 1 or 0; 1 if the C compiler can
+   handle function arguments with function pointers, 0 otherwise. */
+#define CC_CONF_FUNCTION_POINTER_ARGS  1
+
+/* CC_CONF_FASTCALL: if the C compiler supports the fastcall keyword,
+   it should be defined here. If the C compiler does not support it,
+   leave the definition blank. */
+
+   Example:
+   #define CC_CONF_FASTCALL               fastcall */
+#define CC_CONF_FASTCALL
+
+#endif /* __CC_CONF_H__ */
+
diff --git a/contiki/conf/clock-conf.h.example b/contiki/conf/clock-conf.h.example
new file mode 100644
index 0000000..a690e15
--- /dev/null
+++ b/contiki/conf/clock-conf.h.example
@@ -0,0 +1,8 @@
+#ifndef __CLOCK_CONF_H__
+#define __CLOCK_CONF_H__
+
+typedef unsigned short clock_time_t;
+
+#define CLOCK_CONF_SECOND CLK_TCK
+
+#endif /* __CLOCK_CONF_H__ */
diff --git a/contiki/conf/ctk-conf.h.example b/contiki/conf/ctk-conf.h.example
new file mode 100644
index 0000000..789dd32
--- /dev/null
+++ b/contiki/conf/ctk-conf.h.example
@@ -0,0 +1,89 @@
+/*
+ * 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. 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.example,v 1.7 2004/06/27 12:31:24 oliverschmidt 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
+
+/* Defines which key that is to be used for switching to the prevoius
+   widget.  */
+#define CTK_CONF_WIDGETUP_KEY         CH_F5
+
+/* Defines which key that is to be used for switching to the next
+   widget.  */
+#define CTK_CONF_WIDGETDOWN_KEY       CH_F7
+
+/* Toggles mouse support (must have support functions in the
+architecture specific files to work). */
+#define CTK_CONF_MOUSE_SUPPORT        0 /* 1342 bytes */
+
+/* Toggles support for icons. */
+#define CTK_CONF_ICONS                1 /* 107 bytes */
+
+/* Toggles support for icon bitmaps. */
+#define CTK_CONF_ICON_BITMAPS         1
+
+/* Toggles support for icon textmaps. */
+#define CTK_CONF_ICON_TEXTMAPS        1
+
+/* Toggles support for movable windows. */
+#define CTK_CONF_WINDOWMOVE           1 /* 333 bytes */
+
+/* Toggles support for closable windows. */
+#define CTK_CONF_WINDOWCLOSE          1 /* 14 bytes */
+
+/* Toggles support for menus. */
+#define CTK_CONF_MENUS                1 /* 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
+
+/* Toggles support for screen savers. */
+#define CTK_CONF_SCREENSAVER          0
+
+#endif /* __CTK_CONF_H__ */
diff --git a/contiki/conf/ek-conf.h.example b/contiki/conf/ek-conf.h.example
new file mode 100644
index 0000000..082a5b1
--- /dev/null
+++ b/contiki/conf/ek-conf.h.example
@@ -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. 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.example,v 1.3 2004/07/04 11:37:34 adamdunkels Exp $
+ *
+ */
+
+
+#ifndef __EK_CONF_H__
+#define __EK_CONF_H__
+
+#include <time.h>
+
+typedef void *ek_data_t;
+
+typedef unsigned char ek_event_t;
+typedef unsigned char ek_id_t;
+
+#define EK_CONF_EVENTS   32    /* Must be 2^n */
+typedef unsigned char ek_num_events_t;
+
+#define EK_CONF_MAXPROCS 32
+
+#endif /* __EK_CONF_H__ */
diff --git a/contiki/conf/telnetd-conf.h.example b/contiki/conf/telnetd-conf.h.example
new file mode 100644
index 0000000..becfd44
--- /dev/null
+++ b/contiki/conf/telnetd-conf.h.example
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003, 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. 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 Destop OS
+ *
+ * $Id: telnetd-conf.h.example,v 1.3 2004/08/22 12:35:37 oliverschmidt Exp $
+ *
+ */
+#ifndef __TELNETD_CONF_H__
+#define __TELNETD_CONF_H__
+
+#define TELNETD_CONF_LINELEN 36
+#define TELNETD_CONF_NUMLINES 24
+
+#endif /* __TELNETD_CONF_H__ */
+
+
+
+
+
+
+
+
diff --git a/contiki/conf/uip-conf.h.example b/contiki/conf/uip-conf.h.example
new file mode 100644
index 0000000..b23c409
--- /dev/null
+++ b/contiki/conf/uip-conf.h.example
@@ -0,0 +1,93 @@
+/**
+ * \file
+ * uIP configuration file.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * This file contains configuration options for the uIP TCP/IP
+ * stack. Each Contiki port will contain its own uip-conf.h file
+ * containing architecture specific configuration options.
+ *
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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 Destop OS
+ *
+ * $Id: uip-conf.h.example,v 1.5 2004/08/22 12:35:37 oliverschmidt Exp $
+ *
+ */
+#ifndef __UIP_CONF_H__
+#define __UIP_CONF_H__
+
+/**
+ * The maximum number of TCP connections.
+ *
+ * Since the TCP connections are statically allocated, turning this
+ * configuration knob down results in less RAM used. Each TCP
+ * connection requires approximatly 30 bytes of memory.
+ */
+#define UIP_CONF_MAX_CONNECTIONS 40
+
+/**
+ * The maximum number of listening TCP ports.
+ *
+ * Each listening TCP port requires 2 bytes of memory.
+ */
+#define UIP_CONF_MAX_LISTENPORTS 40
+
+/**
+ * The size of the uIP packet buffer.
+ *
+ * The uIP packet buffer should not be smaller than 60 bytes, and does
+ * not need to be larger than 1500 bytes. Lower size results in lower
+ * TCP throughput, larger size results in higher TCP throughput.
+ */
+#define UIP_CONF_BUFFER_SIZE     400
+
+/**
+ * The host byte order.
+ *
+ * Used for telling uIP if the architecture has LITTLE_ENDIAN or
+ * BIG_ENDIAN byte order. x86 CPUs have LITTLE_ENDIAN byte order,
+ * whereas Motorola CPUs have BIG_ENDIAN. Check the documentation of
+ * the CPU to find out the byte order.
+ */
+#define UIP_CONF_BYTE_ORDER      LITTLE_ENDIAN
+
+
+/**
+ * IP address configuration through ping.
+ *
+ * uIP features IP address configuration using an ICMP echo (ping)
+ * packet. In this mode, the destination IP address of the first ICMP
+ * echo packet that is received is used to set the host IP address.  
+ */
+#define UIP_CONF_PINGADDRCONF    0
+#endif /* __UIP_CONF_H__ */
diff --git a/contiki/conf/www-conf.h.example b/contiki/conf/www-conf.h.example
new file mode 100644
index 0000000..374c78f
--- /dev/null
+++ b/contiki/conf/www-conf.h.example
@@ -0,0 +1,110 @@
+/**
+ * \file
+ * The Contiki web browser configuration file.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/*
+ * Copyright (c) 2002-2003, 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. 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.example,v 1.4 2004/07/04 11:37:34 adamdunkels Exp $
+ *
+ */
+#ifndef __WWW_CONF_H__
+#define __WWW_CONF_H__
+
+/**
+ * The width of the web page viewing area, measured in characters.
+ */
+#define WWW_CONF_WEBPAGE_WIDTH 36
+
+/**
+ * The height of the web page viewing area, measured in characters.
+ */
+#define WWW_CONF_WEBPAGE_HEIGHT 17
+
+/**
+ * The size of the "Back" history.
+ */
+#define WWW_CONF_HISTORY_SIZE 4
+
+/**
+ * The maximum length of the URLs the web browser will handle.
+ */
+#define WWW_CONF_MAX_URLLEN 100
+
+/**
+ * The maxiumum number of widgets (i.e., hyperlinks, form elements) on
+ * a single web page view.
+ *
+ * \note This does not limit the total number of widgets in a web
+ * page, only the number of widget that are visible simultaneously.
+ */
+#define WWW_CONF_MAX_NUMPAGEWIDGETS 20
+
+/**
+ * Turns support for the \<center\> tag on or off, and must be on for
+ * HTML forms to work.
+ */
+#define WWW_CONF_RENDERSTATE 1
+
+/**
+ * Toggles support for HTML forms.
+ */
+#define WWW_CONF_FORMS       1
+
+/**
+ * Maximum length of HTML form action URLs.
+ */
+#define WWW_CONF_MAX_FORMACTIONLEN  40
+
+/**
+ * Maximum length of HTML form name.
+ */
+#define WWW_CONF_MAX_FORMNAMELEN    20
+
+/**
+ * Maximum length of HTML form input name.
+ */
+#define WWW_CONF_MAX_INPUTNAMELEN   20
+
+/**
+ * Maximum length of HTML form input value.
+ */
+#define WWW_CONF_MAX_INPUTVALUELEN  (WWW_CONF_WEBPAGE_WIDTH - 1)
+
+/**
+ * The defaule home page.
+ */
+#define WWW_CONF_HOMEPAGE "http://contiki.c64.org/"
+
+#endif /* __WWW_CONF_H__ */
diff --git a/contiki/ctk/FILES b/contiki/ctk/FILES
new file mode 100644
index 0000000..c6245ba
--- /dev/null
+++ b/contiki/ctk/FILES
@@ -0,0 +1,30 @@
+The contiki/ctk/ directory contains the source code for CTK, the
+Contiki ToolKit, that provides the Contiki graphical user interface.
+
+ctk-conio*.[ch]
+
+  A CTK driver that provides a text-mode version of the CTK GUI for a
+  locally connected display.
+
+ctk-draw*.[ch]
+
+  The interface that all CTK drivers use to communicate with CTK.
+
+ctk-mouse.[ch]
+
+  The CTK mouse pointer interface.
+
+ctk-term*.[ch]
+
+  A CTK driver that provides a text-mode version of the CTK GUI for a
+  remotely connected display over a serial line or via Telnet.
+
+ctk-vnc*[ch], vnc*.[ch]
+
+  A CTK driver that provides a graphical version of the CTK GUI for a
+  remotely connected display over an IP network using the VNC
+  protocol.
+
+ctk.[ch]
+
+  CTK implementation. 
\ No newline at end of file
diff --git a/contiki/ctk/ctk-conio-service.c b/contiki/ctk/ctk-conio-service.c
new file mode 100644
index 0000000..75d082f
--- /dev/null
+++ b/contiki/ctk/ctk-conio-service.c
@@ -0,0 +1,576 @@
+/*
+ * 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. 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-conio-service.c,v 1.12 2006/05/28 20:38:19 oliverschmidt Exp $
+ *
+ */
+
+#include <conio.h>
+
+#include "ctk.h"
+#include "ctk-draw.h"
+
+#include "ctk-draw-service.h"
+
+#include "ctk-conio-conf.h"
+#include <string.h>
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+static unsigned char sizex, sizey;
+
+/*unsigned char ctk_draw_windowborder_height = 1;
+unsigned char ctk_draw_windowborder_width = 1;
+unsigned char ctk_draw_windowtitle_height = 1;*/
+
+
+/*-----------------------------------------------------------------------------------*/
+static void
+cputsn(char *str, unsigned char len)
+{
+  char c;
+
+  while(len > 0) {
+    --len;
+    c = *str;
+    if(c == 0) {
+      break;
+    }
+    cputc(c);
+    ++str;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+s_ctk_draw_init(void)
+{
+  (void)bgcolor(SCREENCOLOR);
+  (void)bordercolor(BORDERCOLOR);
+  screensize(&sizex, &sizey);
+  ctk_draw_clear(0, sizey);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_widget(struct ctk_widget *w,
+	    unsigned char x, unsigned char y,
+	    unsigned char clipx,
+	    unsigned char clipy,
+	    unsigned char clipy1, unsigned char clipy2,
+	    unsigned char focus)
+{
+  unsigned char xpos, ypos, xscroll;
+  unsigned char i, j;
+  char c, *text;
+  unsigned char len, wfocus;
+
+  wfocus = 0;
+  if(focus & CTK_FOCUS_WINDOW) {    
+    (void)textcolor(WIDGETCOLOR_FWIN);
+    if(focus & CTK_FOCUS_WIDGET) {
+      (void)textcolor(WIDGETCOLOR_FOCUS);
+      wfocus = 1;
+    }
+  } else if(focus & CTK_FOCUS_DIALOG) {
+    (void)textcolor(WIDGETCOLOR_DIALOG);
+    if(focus & CTK_FOCUS_WIDGET) {
+      (void)textcolor(WIDGETCOLOR_FOCUS);
+      wfocus = 1;
+    }
+  } else {
+    (void)textcolor(WIDGETCOLOR);
+  }
+  
+  xpos = x + w->x;
+  ypos = y + w->y;
+    
+  switch(w->type) {
+  case CTK_WIDGET_SEPARATOR:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      chlinexy(xpos, ypos, w->w);
+    }
+    break;
+  case CTK_WIDGET_LABEL:
+    text = w->widget.label.text;
+    for(i = 0; i < w->h; ++i) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	gotoxy(xpos, ypos);
+	cputsn(text, w->w);
+	if(w->w - (wherex() - xpos) > 0) {
+	  cclear(w->w - (wherex() - xpos));
+	}
+      }
+      ++ypos;
+      text += w->w;
+    }
+    break;
+  case CTK_WIDGET_BUTTON:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      revers(wfocus != 0);
+      cputcxy(xpos, ypos, '[');
+      cputsn(w->widget.button.text, w->w);
+      cputc(']');
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_HYPERLINK:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      revers(wfocus == 0);
+      gotoxy(xpos, ypos);
+      (void)textcolor(WIDGETCOLOR_HLINK);
+      cputsn(w->widget.button.text, w->w);
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_TEXTENTRY:
+    text = w->widget.textentry.text;
+    xscroll = 0;
+    if(w->widget.textentry.xpos >= w->w - 1) {
+      xscroll = w->widget.textentry.xpos - w->w + 1;
+    }
+    for(j = 0; j < w->h; ++j) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
+	   w->widget.textentry.ypos == j) {
+	  revers(0);
+	  cputcxy(xpos, ypos, '>');
+	  c = 1;
+	  for(i = 0; i < w->w; ++i) {
+	    if(c != 0) {
+	      c = text[i + xscroll];
+	    }
+            revers(i == w->widget.textentry.xpos - xscroll);
+	    if(c == 0) {
+	      cputc(' ');
+	    } else {
+	      cputc(c);
+	    }
+	  }
+	  revers(0);
+	  cputc('<');
+	} else {
+	  revers(wfocus != 0 && j == w->widget.textentry.ypos);
+	  cvlinexy(xpos, ypos, 1);
+	  gotoxy(xpos + 1, ypos);          
+	  cputsn(text, w->w);
+	  i = wherex();
+	  if(i - xpos - 1 < w->w) {
+	    cclear(w->w - (i - xpos) + 1);
+	  }
+	  cvline(1);
+	}
+      }
+      ++ypos;
+      text += w->widget.textentry.len + 1;
+    }
+    revers(0);
+    break;
+  case CTK_WIDGET_ICON:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      revers(wfocus != 0);
+      gotoxy(xpos, ypos);
+      if(w->widget.icon.textmap != NULL) {
+	for(i = 0; i < 3; ++i) {
+	  gotoxy(xpos, ypos);
+	  if(ypos >= clipy1 && ypos < clipy2) {
+	    cputc(w->widget.icon.textmap[0 + 3 * i]);
+	    cputc(w->widget.icon.textmap[1 + 3 * i]);
+	    cputc(w->widget.icon.textmap[2 + 3 * i]);
+	  }
+	  ++ypos;
+	}
+      }
+      x = xpos;
+  
+      len = strlen(w->widget.icon.title);
+      if(x + len >= sizex) {
+	x = sizex - len;
+      }
+
+      gotoxy(x, ypos);
+      if(ypos >= clipy1 && ypos < clipy2) {
+	cputs(w->widget.icon.title);
+      }
+      revers(0);
+    }
+    break;
+
+  default:
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+s_ctk_draw_widget(struct ctk_widget *w,
+		  unsigned char focus,
+		  unsigned char clipy1,
+		  unsigned char clipy2)
+{
+  struct ctk_window *win = w->window;
+  unsigned char posx, posy;
+
+  posx = win->x + 1;
+  posy = win->y + 2;
+
+  if(w == win->focused) {
+    focus |= CTK_FOCUS_WIDGET;
+  }
+  
+  draw_widget(w, posx, posy,
+	      posx + win->w,
+	      posy + win->h,
+	      clipy1, clipy2,
+	      focus);
+  
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+s_ctk_draw_clear_window(struct ctk_window *window,
+		      unsigned char focus,
+		      unsigned char clipy1,
+		      unsigned char clipy2)
+{
+  unsigned char i;
+  unsigned char h;
+
+  if(focus & CTK_FOCUS_WINDOW) {
+    (void)textcolor(WINDOWCOLOR_FOCUS);
+  } else {
+    (void)textcolor(WINDOWCOLOR);
+  }
+    
+  h = window->y + 2 + window->h;
+
+  /* Clear window contents. */
+  for(i = window->y + 2; i < h; ++i) {
+    if(i >= clipy1 && i < clipy2) {
+      cclearxy(window->x + 1, i, window->w);
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_window_contents(struct ctk_window *window, unsigned char focus,
+		     unsigned char clipy1, unsigned char clipy2,
+		     unsigned char x1, unsigned char x2,
+		     unsigned char y1, unsigned char y2)
+{
+  struct ctk_widget *w;
+  unsigned char wfocus;
+  
+  /* Draw inactive widgets. */
+  for(w = window->inactive; w != NULL; w = w->next) {
+    draw_widget(w, x1, y1, x2, y2,
+		clipy1, clipy2,
+		focus);
+  }
+  
+  /* Draw active widgets. */
+  for(w = window->active; w != NULL; w = w->next) {  
+    wfocus = focus;
+    if(w == window->focused) {
+      wfocus |= CTK_FOCUS_WIDGET;
+    }
+
+   draw_widget(w, x1, y1, x2, y2, 
+	       clipy1, clipy2,
+	       wfocus);
+  }
+
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+s_ctk_draw_window(struct ctk_window *window, unsigned char focus,
+		  unsigned char clipy1, unsigned char clipy2,
+		  unsigned char draw_borders)
+{
+  unsigned char x, y;
+  unsigned char h;
+  unsigned char x1, y1, x2, y2;
+
+  if(window->y + 1 >= clipy2) {
+    return;
+  }
+    
+  x = window->x;
+  y = window->y + 1;
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + window->w;
+  y2 = y1 + window->h;
+
+  if(draw_borders) {  
+
+    /* Draw window frame. */
+    if(focus & CTK_FOCUS_WINDOW) {
+      (void)textcolor(WINDOWCOLOR_FOCUS);
+    } else {
+      (void)textcolor(WINDOWCOLOR);
+    }
+
+    if(y >= clipy1) {
+      cputcxy(x, y, CH_ULCORNER);
+      gotoxy(wherex() + window->titlelen + CTK_CONF_WINDOWMOVE * 2, wherey());
+      chline(window->w - (wherex() - x) - 2);
+      cputcxy(x2, y, CH_URCORNER);
+    }
+
+    h = window->h;
+  
+    if(clipy1 > y1) {
+      if(clipy1 - y1 < h) {
+	h = clipy1 - y1;
+	      y1 = clipy1;
+      } else {
+	h = 0;
+      }
+    }
+
+    if(clipy2 < y1 + h) {
+      if(y1 >= clipy2) {
+	h = 0;
+      } else {
+	h = clipy2 - y1;
+      }
+    }
+
+    cvlinexy(x, y1, h);
+    cvlinexy(x2, y1, h);  
+
+    if(y + window->h >= clipy1 &&
+       y + window->h < clipy2) {
+      cputcxy(x, y2, CH_LLCORNER);
+      chlinexy(x1, y2, window->w);
+      cputcxy(x2, y2, CH_LRCORNER);
+    }
+  }
+
+  draw_window_contents(window, focus, clipy1, clipy2,
+		       x1, x2, y + 1, y2);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+s_ctk_draw_dialog(struct ctk_window *dialog)
+{
+  unsigned char x, y;
+  unsigned char i;
+  unsigned char x1, y1, x2, y2;
+  
+  (void)textcolor(DIALOGCOLOR);
+
+  x = dialog->x;
+  y = dialog->y + 1;
+
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + dialog->w;
+  y2 = y1 + dialog->h;
+
+  /* Draw dialog frame. */
+  cvlinexy(x, y1,
+	   dialog->h);
+  cvlinexy(x2, y1,
+	   dialog->h);
+
+  chlinexy(x1, y,
+	   dialog->w);
+  chlinexy(x1, y2,
+	   dialog->w);
+
+  cputcxy(x, y, CH_ULCORNER);
+  cputcxy(x, y2, CH_LLCORNER);
+  cputcxy(x2, y, CH_URCORNER);
+  cputcxy(x2, y2, CH_LRCORNER);
+  
+  /* Clear dialog contents. */
+  for(i = y1; i < y2; ++i) {
+    cclearxy(x1, i, dialog->w);
+  }
+
+  draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
+		       x1, x2, y1, y2);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+s_ctk_draw_clear(unsigned char y1, unsigned char y2)
+{
+  unsigned char i;
+ 
+  (void)textcolor(BACKGROUNDCOLOR);
+  for(i = y1; i < y2; ++i) {
+    cclearxy(0, i, sizex);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_menu(struct ctk_menu *m, unsigned char open)
+{
+  unsigned char x, x2, y;
+
+  if(open) {
+    x = x2 = wherex();
+    if(x2 + CTK_CONF_MENUWIDTH > sizex) {
+      x2 = sizex - CTK_CONF_MENUWIDTH;
+    }
+
+    for(y = 0; y < m->nitems; ++y) {
+      if(y == m->active) {
+	(void)textcolor(ACTIVEMENUITEMCOLOR);
+	revers(0);
+      } else {
+	(void)textcolor(MENUCOLOR);	  
+	revers(1);
+      }
+      gotoxy(x2, y + 1);
+      if(m->items[y].title[0] == '-') {
+	chline(CTK_CONF_MENUWIDTH);
+      } else {
+	cputs(m->items[y].title);
+      }
+      if(x2 + CTK_CONF_MENUWIDTH > wherex()) {
+	cclear(x2 + CTK_CONF_MENUWIDTH - wherex());
+      }
+    }
+
+    gotoxy(x, 0);
+    (void)textcolor(OPENMENUCOLOR);
+    revers(0);
+  }
+
+  cputs(m->title);
+  cputc(' ');
+  (void)textcolor(MENUCOLOR);
+  revers(1);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+s_ctk_draw_menus(struct ctk_menus *menus)
+{
+  struct ctk_menu *m;
+
+  /* Draw menus */
+  (void)textcolor(MENUCOLOR);
+  gotoxy(0, 0);
+  revers(1);
+  cputc(' ');
+  for(m = menus->menus->next; m != NULL; m = m->next) {
+    draw_menu(m, m == menus->open);
+  }
+
+  /* Draw desktopmenu */
+  if(wherex() + strlen(menus->desktopmenu->title) + 1 >= sizex) {
+    gotoxy(sizex - strlen(menus->desktopmenu->title) - 1, 0);
+  } else {
+    cclear(sizex - wherex() -
+	   strlen(menus->desktopmenu->title) - 1);
+  }
+  draw_menu(menus->desktopmenu, menus->desktopmenu == menus->open);
+
+  revers(0);
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char
+s_ctk_draw_height(void)
+{
+  return sizey;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char
+s_ctk_draw_width(void)
+{
+  return sizex;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned short
+s_ctk_mouse_xtoc(unsigned short x)
+{
+  return x / 8;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned short
+s_ctk_mouse_ytoc(unsigned short y)
+{
+  return y / 8;
+}
+/*-----------------------------------------------------------------------------------*/
+static const struct ctk_draw_service_interface interface =
+  {CTK_DRAW_SERVICE_VERSION,
+   1,
+   1,
+   1,
+   s_ctk_draw_init,
+   s_ctk_draw_clear,
+   s_ctk_draw_clear_window,
+   s_ctk_draw_window,
+   s_ctk_draw_dialog,
+   s_ctk_draw_widget,
+   s_ctk_draw_menus,
+   s_ctk_draw_width,
+   s_ctk_draw_height,
+   s_ctk_mouse_xtoc,
+   s_ctk_mouse_ytoc,
+  };
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(proc, CTK_DRAW_SERVICE_NAME ": text", EK_PRIO_NORMAL,
+	   eventhandler, NULL, (void *)&interface);
+
+/*--------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(ctk_conio_service_init, arg)
+{
+  s_ctk_draw_init();
+  ek_service_start(CTK_DRAW_SERVICE_NAME, &proc);
+}
+/*--------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+  
+  switch(ev) {
+  case EK_EVENT_INIT:
+  case EK_EVENT_REPLACE:
+    s_ctk_draw_init();
+    ctk_restore();
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    ek_replace((struct ek_proc *)data, NULL);
+    LOADER_UNLOAD();
+    break;    
+  }
+}
+/*--------------------------------------------------------------------------*/
diff --git a/contiki/ctk/ctk-conio.c b/contiki/ctk/ctk-conio.c
new file mode 100644
index 0000000..2f8399b
--- /dev/null
+++ b/contiki/ctk/ctk-conio.c
@@ -0,0 +1,524 @@
+/*
+ * 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. 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-conio.c,v 1.24 2006/05/28 20:38:19 oliverschmidt Exp $
+ *
+ */
+
+#include <conio.h>
+
+#include "ctk.h"
+#include "ctk-draw.h"
+
+#include "ctk-conio-conf.h"
+#include <string.h>
+#include <ctype.h>
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+static unsigned char sizex, sizey;
+
+unsigned char ctk_draw_windowborder_height = 1;
+unsigned char ctk_draw_windowborder_width = 1;
+unsigned char ctk_draw_windowtitle_height = 1;
+
+
+/*-----------------------------------------------------------------------------------*/
+static void
+cputsn(char *str, unsigned char len)
+{
+  char c;
+
+  while(len > 0) {
+    --len;
+    c = *str;
+    if(c == 0) {
+      break;
+    }
+    cputc(c);
+    ++str;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_init(void)
+{
+  (void)bgcolor(SCREENCOLOR);
+  (void)bordercolor(BORDERCOLOR);
+  screensize(&sizex, &sizey);
+  ctk_draw_clear(0, sizey);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_widget(struct ctk_widget *w,
+	    unsigned char x, unsigned char y,
+	    unsigned char clipx,
+	    unsigned char clipy,
+	    unsigned char clipy1, unsigned char clipy2,
+	    unsigned char focus)
+{
+  unsigned char xpos, ypos, xscroll;
+  unsigned char i, j;
+  char c, *text;
+  unsigned char len, wfocus;
+
+  wfocus = 0;
+  if(focus & CTK_FOCUS_WINDOW) {    
+    (void)textcolor(WIDGETCOLOR_FWIN);
+    if(focus & CTK_FOCUS_WIDGET) {
+      (void)textcolor(WIDGETCOLOR_FOCUS);
+      wfocus = 1;
+    }
+  } else if(focus & CTK_FOCUS_DIALOG) {
+    (void)textcolor(WIDGETCOLOR_DIALOG);
+    if(focus & CTK_FOCUS_WIDGET) {
+      (void)textcolor(WIDGETCOLOR_FOCUS);
+      wfocus = 1;
+    }
+  } else {
+    (void)textcolor(WIDGETCOLOR);
+  }
+  
+  xpos = x + w->x;
+  ypos = y + w->y;
+    
+  switch(w->type) {
+  case CTK_WIDGET_SEPARATOR:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      chlinexy(xpos, ypos, w->w);
+    }
+    break;
+  case CTK_WIDGET_LABEL:
+    text = w->widget.label.text;
+    for(i = 0; i < w->h; ++i) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	gotoxy(xpos, ypos);
+	cputsn(text, w->w);
+	if(w->w - (wherex() - xpos) > 0) {
+	  cclear(w->w - (wherex() - xpos));
+	}
+      }
+      ++ypos;
+      text += w->w;
+    }
+    break;
+  case CTK_WIDGET_BUTTON:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      revers(wfocus != 0);
+      cputcxy(xpos, ypos, '[');
+      cputsn(w->widget.button.text, w->w);
+      cputc(']');
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_HYPERLINK:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      revers(wfocus == 0);
+      gotoxy(xpos, ypos);
+      (void)textcolor(WIDGETCOLOR_HLINK);
+      cputsn(w->widget.button.text, w->w);
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_TEXTENTRY:
+    text = w->widget.textentry.text;
+    xscroll = 0;
+    if(w->widget.textentry.xpos >= w->w - 1) {
+      xscroll = w->widget.textentry.xpos - w->w + 1;
+    }
+    for(j = 0; j < w->h; ++j) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
+	   w->widget.textentry.ypos == j) {
+	  revers(0);
+	  cputcxy(xpos, ypos, '>');
+	  c = 1;
+	  for(i = 0; i < w->w; ++i) {
+	    if(c != 0) {
+	      c = text[i + xscroll];
+	    }
+	    revers(i == w->widget.textentry.xpos - xscroll);
+	    if(c == 0) {
+	      cputc(' ');
+	    } else {
+	      cputc(c);
+	    }
+	  }
+	  revers(0);
+	  cputc('<');
+	} else {
+	  revers(wfocus != 0 && j == w->widget.textentry.ypos);
+	  cvlinexy(xpos, ypos, 1);
+	  gotoxy(xpos + 1, ypos);          
+	  cputsn(text, w->w);
+	  i = wherex();
+	  if(i - xpos - 1 < w->w) {
+	    cclear(w->w - (i - xpos) + 1);
+	  }
+	  cvline(1);
+	}
+      }
+      ++ypos;
+      text += w->widget.textentry.len + 1;
+    }
+    revers(0);
+    break;
+#if CTK_CONF_ICONS
+  case CTK_WIDGET_ICON:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      revers(wfocus != 0);
+#if CTK_CONF_ICON_TEXTMAPS
+      if(w->widget.icon.textmap != NULL) {
+	for(i = 0; i < 3; ++i) {
+	  gotoxy(xpos, ypos);
+	  if(ypos >= clipy1 && ypos < clipy2) {
+	    cputc(w->widget.icon.textmap[0 + 3 * i]);
+	    cputc(w->widget.icon.textmap[1 + 3 * i]);
+	    cputc(w->widget.icon.textmap[2 + 3 * i]);
+	  }
+	  ++ypos;
+	}
+      }
+#endif /* CTK_CONF_ICON_TEXTMAPS */
+  
+      len = strlen(w->widget.icon.title);
+      if(xpos + len >= sizex) {
+	xpos = sizex - len;
+      }
+
+      gotoxy(xpos, ypos);
+      if(ypos >= clipy1 && ypos < clipy2) {
+	cputs(w->widget.icon.title);
+      }
+      revers(0);
+    }
+    break;
+#endif /* CTK_CONF_ICONS */
+
+  default:
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_widget(struct ctk_widget *w,
+		unsigned char focus,
+		unsigned char clipy1,
+		unsigned char clipy2)
+{
+  struct ctk_window *win = w->window;
+  unsigned char posx, posy;
+
+  posx = win->x + 1;
+  posy = win->y + 2;
+
+  if(w == win->focused) {
+    focus |= CTK_FOCUS_WIDGET;
+  }
+  
+  draw_widget(w, posx, posy,
+	      posx + win->w,
+	      posy + win->h,
+	      clipy1, clipy2,
+	      focus);
+  
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear_window(struct ctk_window *window,
+		      unsigned char focus,
+		      unsigned char clipy1,
+		      unsigned char clipy2)
+{
+  unsigned char i;
+  unsigned char h;
+
+  if(focus & CTK_FOCUS_WINDOW) {
+    (void)textcolor(WINDOWCOLOR_FOCUS);
+  } else {
+    (void)textcolor(WINDOWCOLOR);
+  }
+  
+  h = window->y + 2 + window->h;
+
+  /* Clear window contents. */
+  for(i = window->y + 2; i < h; ++i) {
+    if(i >= clipy1 && i < clipy2) {
+      cclearxy(window->x + 1, i, window->w);
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_window_contents(struct ctk_window *window, unsigned char focus,
+		     unsigned char clipy1, unsigned char clipy2,
+		     unsigned char x1, unsigned char x2,
+		     unsigned char y1, unsigned char y2)
+{
+  struct ctk_widget *w;
+  unsigned char wfocus;
+  
+  /* Draw inactive widgets. */
+  for(w = window->inactive; w != NULL; w = w->next) {
+    draw_widget(w, x1, y1, x2, y2,
+		clipy1, clipy2,
+		focus);
+  }
+  
+  /* Draw active widgets. */
+  for(w = window->active; w != NULL; w = w->next) {  
+    wfocus = focus;
+    if(w == window->focused) {
+      wfocus |= CTK_FOCUS_WIDGET;
+    }
+
+   draw_widget(w, x1, y1, x2, y2, 
+	       clipy1, clipy2,
+	       wfocus);
+  }
+
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_window(struct ctk_window *window, unsigned char focus,
+		unsigned char clipy1, unsigned char clipy2,
+		unsigned char draw_borders)
+{
+  unsigned char x, y;
+  unsigned char h;
+  unsigned char x1, y1, x2, y2;
+
+  if(window->y + 1 >= clipy2) {
+    return;
+  }
+    
+  x = window->x;
+  y = window->y + 1;
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + window->w;
+  y2 = y1 + window->h;
+
+  if(draw_borders) {
+
+    /* Draw window frame. */  
+    if(focus & CTK_FOCUS_WINDOW) {
+      (void)textcolor(WINDOWCOLOR_FOCUS);
+    } else {
+      (void)textcolor(WINDOWCOLOR);
+    }
+
+    if(y >= clipy1) {
+      cputcxy(x, y, CH_ULCORNER);
+      gotoxy(wherex() + window->titlelen + CTK_CONF_WINDOWMOVE * 2, wherey());
+      chline(window->w - (wherex() - x) - 2);
+      cputcxy(x2, y, CH_URCORNER);
+    }
+
+    h = window->h;
+  
+    if(clipy1 > y1) {
+      if(clipy1 - y1 < h) {
+	h = clipy1 - y1;
+	      y1 = clipy1;
+      } else {
+	h = 0;
+      }
+    }
+
+    if(clipy2 < y1 + h) {
+      if(y1 >= clipy2) {
+	h = 0;
+      } else {
+	h = clipy2 - y1;
+      }
+    }
+
+    cvlinexy(x, y1, h);
+    cvlinexy(x2, y1, h);  
+
+    if(y + window->h >= clipy1 &&
+       y + window->h < clipy2) {
+      cputcxy(x, y2, CH_LLCORNER);
+      chlinexy(x1, y2, window->w);
+      cputcxy(x2, y2, CH_LRCORNER);
+    }
+  }
+
+  draw_window_contents(window, focus, clipy1, clipy2,
+		       x1, x2, y + 1, y2);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_dialog(struct ctk_window *dialog)
+{
+  unsigned char x, y;
+  unsigned char i;
+  unsigned char x1, y1, x2, y2;
+  
+  (void)textcolor(DIALOGCOLOR);
+
+  x = dialog->x;
+  y = dialog->y + 1;
+
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + dialog->w;
+  y2 = y1 + dialog->h;
+
+  /* Draw dialog frame. */
+  cvlinexy(x, y1,
+	   dialog->h);
+  cvlinexy(x2, y1,
+	   dialog->h);
+
+  chlinexy(x1, y,
+	   dialog->w);
+  chlinexy(x1, y2,
+	   dialog->w);
+
+  cputcxy(x, y, CH_ULCORNER);
+  cputcxy(x, y2, CH_LLCORNER);
+  cputcxy(x2, y, CH_URCORNER);
+  cputcxy(x2, y2, CH_LRCORNER);
+  
+  /* Clear dialog contents. */
+  for(i = y1; i < y2; ++i) {
+    cclearxy(x1, i, dialog->w);
+  }
+
+  draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
+		       x1, x2, y1, y2);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear(unsigned char y1, unsigned char y2)
+{
+  unsigned char i;
+ 
+  (void)textcolor(BACKGROUNDCOLOR);
+  for(i = y1; i < y2; ++i) {
+    cclearxy(0, i, sizex);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_menu(struct ctk_menu *m, unsigned char open)
+{
+  unsigned char x, x2, y;
+
+  if(open) {
+    x = x2 = wherex();
+    if(x2 + CTK_CONF_MENUWIDTH > sizex) {
+      x2 = sizex - CTK_CONF_MENUWIDTH;
+    }
+
+    for(y = 0; y < m->nitems; ++y) {
+      if(y == m->active) {
+	(void)textcolor(ACTIVEMENUITEMCOLOR);
+	revers(0);
+      } else {
+	(void)textcolor(MENUCOLOR);	  
+	revers(1);
+      }
+      gotoxy(x2, y + 1);
+      if(m->items[y].title[0] == '-') {
+	chline(CTK_CONF_MENUWIDTH);
+      } else {
+	cputs(m->items[y].title);
+      }
+      if(x2 + CTK_CONF_MENUWIDTH > wherex()) {
+	cclear(x2 + CTK_CONF_MENUWIDTH - wherex());
+      }
+    }
+
+    gotoxy(x, 0);
+    (void)textcolor(OPENMENUCOLOR);
+    revers(0);
+  }
+
+  cputs(m->title);
+  cputc(' ');
+  (void)textcolor(MENUCOLOR);
+  revers(1);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_menus(struct ctk_menus *menus)
+{
+  struct ctk_menu *m;
+
+  /* Draw menus */
+  (void)textcolor(MENUCOLOR);
+  gotoxy(0, 0);
+  revers(1);
+  cputc(' ');
+  for(m = menus->menus->next; m != NULL; m = m->next) {
+    draw_menu(m, m == menus->open);
+  }
+
+  /* Draw desktopmenu */
+  if(wherex() + strlen(menus->desktopmenu->title) + 1 >= sizex) {
+    gotoxy(sizex - strlen(menus->desktopmenu->title) - 1, 0);
+  } else {
+    cclear(sizex - wherex() -
+	   strlen(menus->desktopmenu->title) - 1);
+  }
+  draw_menu(menus->desktopmenu, menus->desktopmenu == menus->open);
+
+  revers(0);
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_height(void)
+{
+  return sizey;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_width(void)
+{
+  return sizex;
+}
+/*-----------------------------------------------------------------------------------*/
+int
+ctk_arch_isprint(char c)
+{
+  return isprint(c);
+}
diff --git a/contiki/ctk/ctk-conio.h b/contiki/ctk/ctk-conio.h
new file mode 100644
index 0000000..3c9851c
--- /dev/null
+++ b/contiki/ctk/ctk-conio.h
@@ -0,0 +1,66 @@
+/*
+ * 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. 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-conio.h,v 1.5 2004/09/27 22:14:48 oliverschmidt Exp $
+ *
+ */
+
+#ifndef __CTK_CONIO_H__
+#define __CTK_CONIO_H__
+
+#include <conio.h>
+
+typedef char ctk_arch_key_t;
+
+#define ctk_arch_keyavail kbhit
+#define ctk_arch_getkey   cgetc
+
+#ifndef CH_ENTER
+#define CH_ENTER '\n'
+#endif /* CH_ENTER */
+
+#ifndef CH_F1
+#define CH_F1 CH_ESC
+#endif /* CH_F1 */
+
+#ifndef CH_F3
+#define CH_F3 CH_STOP
+#endif /* CH_F1 */
+
+#ifndef CH_CURS_RIGHT
+#define CH_CURS_RIGHT 254
+#endif /* CH_CURS_RIGHT */
+
+#ifndef CH_CURS_LEFT
+#define CH_CURS_LEFT 255
+#endif /* CH_CURS_LEFT */
+
+#endif /* __CTK_CONIO_H__ */
diff --git a/contiki/ctk/ctk-draw-service.h b/contiki/ctk/ctk-draw-service.h
new file mode 100644
index 0000000..8b19768
--- /dev/null
+++ b/contiki/ctk/ctk-draw-service.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ctk-draw-service.h,v 1.4 2005/03/15 15:51:17 oliverschmidt Exp $
+ */
+#ifndef __CTK_DRAW_SERVICE_H__
+#define __CTK_DRAW_SERVICE_H__
+
+#include "ek-service.h"
+
+#include "ctk.h"
+
+#define CTK_DRAW_SERVICE_NAME "CTK driver"
+#define CTK_DRAW_SERVICE_VERSION 0x0001
+struct ctk_draw_service_interface {
+  unsigned char version;
+  unsigned char windowborder_width,
+    windowborder_height,
+    windowtitle_height;
+    
+  void (* draw_init)(void);
+  void (* draw_clear)(unsigned char clipy1, unsigned char clipy2);
+  void (* draw_clear_window)(struct ctk_window *window,
+			     unsigned char focus,
+			     unsigned char clipy1,
+			     unsigned char clipy2);
+  void (* draw_window)(struct ctk_window *window,
+		       unsigned char focus,
+		       unsigned char clipy1,
+		       unsigned char clipy2,
+		       unsigned char draw_borders);
+  void (* draw_dialog)(struct ctk_window *dialog);
+  void (* draw_widget)(struct ctk_widget *widget,
+		       unsigned char focus,
+		       unsigned char clipy1,
+		       unsigned char clipy2);
+  void (* draw_menus)(struct ctk_menus *menus);
+
+  unsigned char (* width)(void);
+  unsigned char (* height)(void);
+
+  unsigned short (* mouse_xtoc)(unsigned short);
+  unsigned short (* mouse_ytoc)(unsigned short);
+};
+
+#endif /* __CTK_DRAW_SERVICE_H__ */
diff --git a/contiki/ctk/ctk-draw.c b/contiki/ctk/ctk-draw.c
new file mode 100644
index 0000000..7e0827a
--- /dev/null
+++ b/contiki/ctk/ctk-draw.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ctk-draw.c,v 1.5 2005/03/15 15:51:17 oliverschmidt Exp $
+ */
+
+#include "ek-service.h"
+
+#include "ctk-draw.h"
+#include "ctk.h"
+
+#include "ctk-draw-service.h"
+
+
+unsigned char ctk_draw_windowborder_width = 1,
+  ctk_draw_windowborder_height = 1,
+  ctk_draw_windowtitle_height = 1;
+
+EK_SERVICE(service, CTK_DRAW_SERVICE_NAME);
+
+/*---------------------------------------------------------------------------*/
+static struct ctk_draw_service_interface *
+find_interface(void)
+{
+  struct ctk_draw_service_interface *interface;
+  interface = (struct ctk_draw_service_interface *)ek_service_state(&service);
+  if(interface != NULL &&
+     interface->version == CTK_DRAW_SERVICE_VERSION) {
+    return interface;
+  } else {
+    return NULL;
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_init(void)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    interface->draw_init();
+    ctk_draw_windowborder_width = interface->windowborder_width;
+    ctk_draw_windowborder_height = interface->windowborder_height;
+    ctk_draw_windowtitle_height = interface->windowtitle_height;
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_clear(unsigned char clipy1, unsigned char clipy2)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    interface->draw_clear(clipy1, clipy2);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_clear_window(struct ctk_window *window,
+		      unsigned char focus,
+		      unsigned char clipy1,
+		      unsigned char clipy2)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    interface->draw_clear_window(window, focus, clipy1, clipy2);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_window(struct ctk_window *window,
+		unsigned char focus,
+		unsigned char clipy1,
+		unsigned char clipy2,
+		unsigned char draw_borders)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    interface->draw_window(window, focus, clipy1, clipy2, draw_borders);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_dialog(struct ctk_window *dialog)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    interface->draw_dialog(dialog);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_widget(struct ctk_widget *widget,
+		unsigned char focus,
+		unsigned char clipy1,
+		unsigned char clipy2)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    interface->draw_widget(widget, focus, clipy1, clipy2);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_menus(struct ctk_menus *menus)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    interface->draw_menus(menus);
+  }
+}
+/*---------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_width(void)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    return interface->width();
+  }
+  return 40;
+}
+/*---------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_height(void)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    return interface->height();
+  }
+  return 24;
+}
+/*---------------------------------------------------------------------------*/
+unsigned short
+ctk_mouse_xtoc(unsigned short x)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    return interface->mouse_xtoc(x);
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+unsigned short
+ctk_mouse_ytoc(unsigned short y)
+{
+  struct ctk_draw_service_interface *interface;
+  
+  if((interface = find_interface()) != NULL) {   
+    return interface->mouse_ytoc(y);
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_draw_quit(void)
+{
+  ek_post(service.id, EK_EVENT_REQUEST_EXIT, NULL);
+  ek_service_reset(&service);  
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/ctk/ctk-draw.h b/contiki/ctk/ctk-draw.h
new file mode 100644
index 0000000..c0ba064
--- /dev/null
+++ b/contiki/ctk/ctk-draw.h
@@ -0,0 +1,336 @@
+/**
+ * \addtogroup ctk
+ * @{
+ */
+
+/**
+ * \file
+ * CTK screen drawing module interface, ctk-draw.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * This file contains the interface for the ctk-draw module.The
+ * ctk-draw module takes care of the actual screen drawing for CTK by
+ * implementing a handful of functions that are called by CTK.
+ *
+ */
+
+/*
+ * Copyright (c) 2002-2003, 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. 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 OS.
+ *
+ * $Id: ctk-draw.h,v 1.7 2005/03/15 15:51:17 oliverschmidt Exp $
+ *
+ */
+
+#ifndef __CTK_DRAW_H__
+#define __CTK_DRAW_H__
+
+#include "ctk.h"
+
+#include "ctk-arch.h"
+
+/**
+ * \defgroup ctkdraw CTK device driver functions
+ * @{
+ *
+ * The CTK device driver functions are divided into two modules, the
+ * ctk-draw module and the ctk-arch module. The purpose of the
+ * ctk-arch and the ctk-draw modules is to act as an interface between
+ * the CTK and the actual hardware of the system on which Contiki is
+ * run. The ctk-arch takes care of the keyboard input from the user,
+ * and the ctk-draw is responsible for drawing the CTK desktop,
+ * windows and user interface widgets onto the actual screen.
+ *
+ * More information about the ctk-draw and the ctk-arch modules can be
+ * found in the sections \ref ctk-draw and \ref ctk-arch.
+ */
+
+/**
+ * \page ctk-draw The ctk-draw module
+ *
+ * In order to work efficiently even on limited systems, CTK uses a
+ * simple coordinate system, where the screen is addressed using
+ * character coordinates instead of pixel coordinates. This makes it
+ * trivial to implement the coordinate system on a text-based screen,
+ * and significantly reduces complexity for pixel based screen
+ * systems.
+ *
+ * The top left of the screen is (0,0) with x and y coordinates
+ * growing downwards and to the right.
+ *
+ * It is the responsibility of the ctk-draw module to keep track of
+ * the screen size and must implement the two functions
+ * ctk_draw_width() and ctk_draw_height(), which are used by the CTK
+ * for querying the screen size. The functions must return the width
+ * and the height of the ctk-draw screen in character coordinates.
+ *
+ * The ctk-draw module is responsible for drawing CTK windows onto the
+ * screen through the function ctk_draw_window().. A pseudo-code
+ * implementation of this  function might look like this:
+ * \code
+   ctk_draw_window(window, focus, clipy1, clipy2, draw_borders) {
+      if(draw_borders) {
+         draw_window_borders(window, focus, clipy1, clipy2);
+      }
+      foreach(widget, window->inactive) {
+         ctk_draw_widget(widget, focus, clipy1, clipy2);
+      }
+      foreach(widget, window->active) {
+         if(widget == window->focused) {
+	    ctk_draw_widget(widget, focus | CTK_FOCUS_WIDGET,
+	                    clipy1, clipy2);
+	 } else {
+	    ctk_draw_widget(widget, focus, clipy1, clipy2);
+	 }
+      }
+   }
+   
+   \endcode
+ *
+ * Where draw_window_borders() draws the window borders (also between
+ * clipy1 and clipy2). The ctk_draw_widget() function is explained
+ * below. Notice how the clipy1 and clipy2 parameters are passed to
+ * all other functions; every function needs to know the boundaries
+ * within which they are allowed to draw.
+ *
+ * In order to aid in implementing a ctk-draw module, a text-based
+ * ctk-draw called ctk-conio has already been implemented. It conforms
+ * to the Borland conio C library, and a skeleton implementation of
+ * said library exists in lib/libconio.c. If a more machine specific
+ * ctk-draw module is to be implemented, the instructions in this file
+ * should be followed.
+ * 
+ */
+
+/**
+ * The initialization function.
+ *
+ * This function is supposed to get the screen ready for drawing, and
+ * may be called at more than one time during the operation of the
+ * system.
+ */
+void ctk_draw_init(void);
+
+/**
+ * Clear the screen between the clip bounds.
+ *
+ * This function should clear the screen between the y coordinates
+ * "clipy1" and "clipy2", including the line at y coordinate "clipy1",
+ * but not the line at y coordinate "clipy2".
+ *
+ * \note This function may be used to draw a background image
+ * (wallpaper) on the desktop; it does not necessarily "clear" the
+ * screen.
+ *
+ * \param clipy1 The lower y coordinate of the clip region.
+ * \param clipy2 The upper y coordinate of the clip region. 
+ */
+void ctk_draw_clear(unsigned char clipy1, unsigned char clipy2);
+
+/**
+ * Draw the window background.
+ *
+ * This function will be called by the CTK before a window will be
+ * completely redrawn.The function is supposed to draw the window
+ * background, excluding window borders as these should be drawn by
+ * the function that actually draws the window, between "clipy1" and
+ * "clipy2".
+ *
+ * \note This function does not necessarily have to clear the window -
+ * it can be used for drawing a background pattern in the window as
+ * well.
+ *
+ * \param window The window for which the background should be drawn.
+ *
+ * \param focus The focus of the window, either CTK_FOCUS_NONE for a
+ * background window, or CTK_FOCUS_WINDOW for the foreground window.
+ * 
+ * \param clipy1 The lower y coordinate of the clip region.
+ * \param clipy2 The upper y coordinate of the clip region. 
+*/
+void ctk_draw_clear_window(struct ctk_window *window,
+			   unsigned char focus,
+			   unsigned char clipy1,
+			   unsigned char clipy2);
+/**
+ * Draw a window onto the screen.
+ *
+ * This function is called by the CTK when a window should be drawn on
+ * the screen. The ctk-draw layer is free to choose how the window
+ * will appear on screen; with or without window borders and the style
+ * of the borders, with or without transparent window background and
+ * how the background shall look, etc.
+ *
+ * \param window The window which is to be drawn.
+ *
+ * \param focus Specifies if the window should be drawn in foreground
+ * or background colors and can be either CTK_FOCUS_NONE or
+ * CTK_FOCUS_WINDOW. Windows with a focus of CTK_FOCUS_WINDOW is
+ * usually drawn in a brighter color than those with CTK_FOCUS_NONE.
+ *
+ * \param clipy1 Specifies the first lines on screen that actually
+ * should be drawn, in screen coordinates (line 1 is the first line
+ * below the menus).
+ *
+ * \param clipy2 Specifies the last + 1 line on screen that should be
+ * drawn, in screen coordinates (line 1 is the first line below the
+ * menus)
+ *
+ */
+void ctk_draw_window(struct ctk_window *window,
+		     unsigned char focus,
+		     unsigned char clipy1,
+		     unsigned char clipy2,
+		     unsigned char draw_borders);
+
+
+/**
+ * Draw a dialog onto the screen.
+ *
+ * In CTK, a dialog is similar to a window, with the only exception
+ * being that they are drawn in a different style. Also, since dialogs
+ * always are drawn on top of everything else, they do not need to be
+ * drawn within any special boundaries.
+ *
+ * \note This function can usually be implemented so that it uses the
+ * same widget drawing code as the ctk_draw_window() function.
+ *
+ * \param dialog The dialog that is to be drawn.
+ */
+void ctk_draw_dialog(struct ctk_window *dialog);
+
+/**
+ * Draw a widget on a window.
+ *
+ * This function is used for drawing a CTK widgets onto the screem is
+ * likely to be the most complex function in the ctk-draw
+ * module. Still, it is straightforward to implement as it can be
+ * written in an incremental fashion, starting with a single widget
+ * type and adding more widget types, one at a time.
+
+ * The ctk-draw module may exploit how the CTK focus constants are
+ * defined in order to use a look-up table for the colors. The CTK
+ * focus constants are defined in the file ctk/ctk.h as follows:
+ \code
+   #define CTK_FOCUS_NONE     0
+   #define CTK_FOCUS_WIDGET   1
+   #define CTK_FOCUS_WINDOW   2
+   #define CTK_FOCUS_DIALOG   4
+ \endcode
+
+ * This gives the following table:
+ \code
+   0: CTK_FOCUS_NONE      (Background window, non-focused widget)
+   1: CTK_FOCUS_WIDGET    (Background window, focused widget)
+   2: CTK_FOCUS_WINDOW    (Foreground window, non-focused widget)
+   3: CTK_FOCUS_WINDOW | CTK_FOCUS_WIDGET
+                          (Foreground window, focused widget)
+   4: CTK_FOCUS_DIALOG    (Dialog, non-focused widget)
+   5: CTK_FOCUS_DIALOG | CTK_FOCUS_WIDGET
+                          (Dialog, focused widget)
+ \endcode 
+
+
+ * \param w The widget to be drawn.
+ * \param focus The focus of the widget.
+ * \param clipy1 The lower y coordinate of the clip region.
+ * \param clipy2 The upper y coordinate of the clip region. 
+ */
+
+void ctk_draw_widget(struct ctk_widget *w,
+		     unsigned char focus,
+		     unsigned char clipy1,
+		     unsigned char clipy2);
+
+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);
+
+
+extern unsigned char ctk_draw_windowborder_width,
+  ctk_draw_windowborder_height,
+  ctk_draw_windowtitle_height;
+
+
+#endif /* __CTK_DRAW_H__ */
+
+
+/**
+ * The keyboard character type of the system
+ *
+ * The ctk_arch_key_t is usually typedef'd to the char type, but some
+ * systems (such as VNC) have a 16-bit key type.
+ *
+ * \var typedef char ctk_arch_key_t;
+ */
+
+/**
+ * Get a keypress from the keyboard input queue.
+ *
+ * This function will remove the first keypress in the keyboard input
+ * queue and return it. If the keyboard queue is empty, the return
+ * value is undefined. This function is intended to be used only after
+ * the ctk_arch_keyavail() function has returned non-zero.
+ *
+ * \return The first keypress from the keyboard input queue.
+ *
+ * \fn ctk_arch_key_t ctk_arch_getkey(void);
+ */
+
+/**
+ * Check if there is a keypress in the keyboard input queue.
+ *
+ * \return Zero if the keyboard input queue is empty, non-zero
+ * otherwise.
+ *
+ * \fn unsigned char ctk_arch_keyavail(void);
+ */
+
+/**
+ * The character used for the Return/Enter key.
+ *
+ * \define #define CH_ENTER '\n'
+ */
+
+/**
+ * \page ctk-arch The ctk-arch module
+ *
+ * The ctk-arch module deals with keyboard input from the underlying
+ * target system on which Contiki is running. The ctk-arch manages a
+ * keyboard input queue that is queried using the two functions
+ * ctk_arch_keyavail() and ctk_arch_getkey().
+ */
+
+/** @} */
+/** @} */
diff --git a/contiki/ctk/ctk-mouse.h b/contiki/ctk/ctk-mouse.h
new file mode 100644
index 0000000..09ef6f3
--- /dev/null
+++ b/contiki/ctk/ctk-mouse.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003, 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. 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-mouse.h,v 1.4 2004/09/12 20:24:55 adamdunkels Exp $
+ *
+ */
+#ifndef __CTK_MOUSE_H__
+#define __CTK_MOUSE_H__
+
+#include "ctk-conf.h"
+
+#if CTK_CONF_MOUSE_SUPPORT
+
+void ctk_mouse_init(void);
+
+unsigned short ctk_mouse_x(void);
+unsigned short ctk_mouse_y(void);
+
+unsigned char ctk_mouse_xtoc(unsigned short x);
+unsigned char ctk_mouse_ytoc(unsigned short y);
+
+unsigned char ctk_mouse_button(void);
+
+void ctk_mouse_hide(void);
+void ctk_mouse_show(void);
+
+#else
+
+#define ctk_mouse_init()
+#define ctk_mouse_x() 0
+#define ctk_mouse_y() 0
+#define ctk_mouse_xtoc(x) 0
+#define ctk_mouse_ytoc(y) 0
+
+#define ctk_mouse_button() 0
+
+#define ctk_mouse_hide()
+#define ctk_mouse_show()
+
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+
+#endif /* __CTK_MOUSE_H__ */
diff --git a/contiki/ctk/ctk-term-ascii.h b/contiki/ctk/ctk-term-ascii.h
new file mode 100644
index 0000000..7d71a97
--- /dev/null
+++ b/contiki/ctk/ctk-term-ascii.h
@@ -0,0 +1,91 @@
+/*   ascii_control.h
+ *
+ *   ASCII CONTROL CHARACTERS
+ *   from American National Standard Code for Information Interchange X3.4-1977
+ *
+ *   Abbreviations
+ *   
+ *   CC:    communication control
+ *   FE:    format effector
+ *   IS:    information separator
+ *   Delim: delimiter
+ *   Intro: introducer
+ */
+
+/*   ----------------------------------------------------------------------- */
+/*   C0 (7-bit) set                                                          */
+/*   ----------------------------------------------------------------------- */
+/*      mnemonic   octal      decimal   C     meaning                        */
+/*   ----------------------------------------------------------------------- */
+
+#define ASCII_NUL  (000)    /*      0 '\0'    Null                           */
+#define ASCII_SOH  (001)    /*      1         Start of Heading (CC)          */
+#define ASCII_STX  (002)    /*      2         Start of Text (CC)             */
+#define ASCII_ETX  (003)    /*      3         End of Text (CC)               */
+#define ASCII_EOT  (004)    /*      4         End of Transmission (CC)       */
+#define ASCII_ENQ  (005)    /*      5         Enquiry (CC)                   */
+#define ASCII_ACK  (006)    /*      6         Acknowledge (CC)               */
+#define ASCII_BEL  (007)    /*      7 '\a'    Bell / Alert                   */
+#define ASCII_BS   (010)    /*      8 '\b'    Backspace (FE)                 */
+#define ASCII_HT   (011)    /*      9 '\t'    Horizontal Tabulation (FE)     */
+#define ASCII_LF   (012)    /*     10 '\n'    Line Feed / Newline (FE)       */
+#define ASCII_VT   (013)    /*     11 '\v'    Vertical Tabulation (FE)       */
+#define ASCII_FF   (014)    /*     12 '\f'    Form Feed (FE)                 */
+#define ASCII_CR   (015)    /*     13 '\r'    Carriage Return (FE)           */
+#define ASCII_SO   (016)    /*     14         Shift Out                      */
+#define ASCII_SI   (017)    /*     15         Shift In                       */
+#define ASCII_DLE  (020)    /*     16         Data Link Escape (CC)          */
+#define ASCII_DC1  (021)    /*     17         Device Control 1  XON          */
+#define ASCII_DC2  (022)    /*     18         Device Control 2               */
+#define ASCII_DC3  (023)    /*     19         Device Control 3  XOFF         */
+#define ASCII_DC4  (024)    /*     20         Device Control 4               */
+#define ASCII_NAK  (025)    /*     21         Negative Acknowledge (CC)      */
+#define ASCII_SYN  (026)    /*     22         Synchronous Idle (CC)          */
+#define ASCII_ETB  (027)    /*     23         End of Transmission Block (CC) */
+#define ASCII_CAN  (030)    /*     24         Cancel                         */
+#define ASCII_EM   (031)    /*     25         End of Medium                  */
+#define ASCII_SUB  (032)    /*     26         Substitute                     */
+#define ASCII_ESC  (033)    /*     27         Escape                         */
+#define ASCII_FS   (034)    /*     28         File Separator                 */
+#define ASCII_GS   (035)    /*     29         Group Separator                */
+#define ASCII_RS   (036)    /*     30         Record Separator               */
+#define ASCII_US   (037)    /*     31         Unit Separator                 */
+
+#define ASCII_DEL (0177)    /*    127         Delete                         */
+
+#define ASCII_NL  ASCII_LF  /*     10         alias for Newline              */
+
+/*   ----------------------------------------------------------------------- */
+/*   C1 (8-bit) set (which have equivalent 7-bit multi-char sequences)       */
+/*   ----------------------------------------------------------------------- */
+/*      mnemonic   octal      decimal  7-bit  meaning                        */
+/*   ----------------------------------------------------------------------- */
+
+#define ASCII_IND (0204)    /*    132  Esc D  Index (FE)                     */
+#define ASCII_NEL (0205)    /*    133  Esc E  Next Line (FE)                 */
+#define ASCII_SSA (0206)    /*    134  Esc F  Start Selected Area            */
+#define ASCII_ESA (0207)    /*    135  Esc G  End Selected Area              */
+#define ASCII_HTS (0210)    /*    136  Esc H  Horizontal Tab Set (FE)        */
+#define ASCII_HTJ (0211)    /*    137  Esc I  Horizontal Tab w/Justificat(FE)*/
+#define ASCII_VTS (0212)    /*    138  Esc J  Vertical Tab Set (FE)          */
+#define ASCII_PLD (0213)    /*    138  Esc K  Partial Line Down (FE)         */
+#define ASCII_PLU (0214)    /*    140  Esc L  Partial Line Up (FE)           */
+#define ASCII_RI  (0215)    /*    141  Esc M  Reverse Index (FE)             */
+#define ASCII_SS2 (0216)    /*    142  Esc N  Single Shift G2 (Intro)        */
+#define ASCII_SS3 (0217)    /*    143  Esc O  Single Shift G3 (Intro)        */
+#define ASCII_DCS (0220)    /*    144  Esc P  Device Control String (Delim)  */
+#define ASCII_PU1 (0221)    /*    145  Esc Q  Private Use 1                  */
+#define ASCII_PU2 (0222)    /*    146  Esc R  Private Use 2                  */
+#define ASCII_STS (0223)    /*    147  Esc S  Set Transmit State             */
+#define ASCII_CCH (0224)    /*    148  Esc T  Cancel Previous Character      */
+#define ASCII_MW  (0225)    /*    149  Esc U  Message Waiting                */
+#define ASCII_SPA (0226)    /*    150  Esc V  Start Protected Area           */
+#define ASCII_EPA (0227)    /*    151  Esc W  End Protected Area             */
+
+#define ASCII_CSI (0233)    /*    155  Esc [  Control Sequence Introducer    */
+#define ASCII_ST  (0234)    /*    156  Esc \  String Terminator (Delim)      */
+#define ASCII_OSC (0235)    /*    157  Esc ]  Operating System Control (Delim*/
+#define ASCII_PM  (0236)    /*    158  Esc ^  Privacy Message (Delim)        */
+#define ASCII_APC (0237)    /*    159  Esc _  Application Program Command (De*/
+
+/* ------------------------------------------------------------------------- */
diff --git a/contiki/ctk/ctk-term-in.c b/contiki/ctk/ctk-term-in.c
new file mode 100644
index 0000000..667c33a
--- /dev/null
+++ b/contiki/ctk/ctk-term-in.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2004, 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ctk-term-in.c,v 1.2 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#include <string.h>
+#include "ctk.h"
+#include "ctk-term.h"
+#include "ctk-term-int.h"
+#include "ctk-term-ascii.h"
+
+#define PRINTF(x) 
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * #defines and enums
+ */
+/*-----------------------------------------------------------------------------------*/
+
+/* Size of input key buffer */
+#define NUMKEYS 20 
+
+/* ANSI character classes */
+enum {ACC_C0, ACC_INTERM, ACC_PARAM, ACC_LOWCASE, ACC_UPCASE,ACC_C1, ACC_G1, ACC_DEL, ACC_SPEC };
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Structures
+ */
+/*-----------------------------------------------------------------------------------*/
+
+/* Structure for mapping a character sequence to a key */
+struct seqmap
+{
+  const char* seq;
+  const ctk_arch_key_t key;
+};
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Local variables
+ */
+/*-----------------------------------------------------------------------------------*/
+
+static ctk_arch_key_t keys[NUMKEYS];
+static int firstkey, lastkey;
+
+/* Sequences starting with ESC [ .... */
+const static struct seqmap ctrlmap[] =
+{
+  {"A",CH_CURS_UP},
+  {"B",CH_CURS_DOWN},
+  {"C",CH_CURS_RIGHT},
+  {"D",CH_CURS_LEFT},
+
+  {"11~",CH_F1},
+  {"12~",CH_F2},
+  {"13~",CH_F3},
+  {"14~",CH_F4},
+  // linux console
+  {"[A",CH_F1},
+  {"[B",CH_F2},
+  {"[C",CH_F3},
+  {"[D",CH_F4},
+  {0,0}
+};
+
+/* Sequences starting with ESC O .... */
+const static struct seqmap ss3map[] =
+{
+  {"A",CH_CURS_UP},
+  {"B",CH_CURS_DOWN},
+  {"C",CH_CURS_RIGHT},
+  {"D",CH_CURS_LEFT},
+  {"P",CH_F1},
+  {"Q",CH_F2},
+  {"R",CH_F3},
+  {"S",CH_F4},
+  {0,0}
+};
+
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Add a key to the input buffer
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+enqueue_key(ctk_arch_key_t k)
+{
+  keys[lastkey] = k;
+  ++lastkey;
+  if(lastkey >= NUMKEYS) {
+    lastkey = 0;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Classify a character 
+ */
+/*-----------------------------------------------------------------------------------*/
+static unsigned char 
+classify(unsigned char c)
+{
+  if (0x00 <= c && c <=0x1f) return ACC_C0;
+  if (0x20 <= c && c <=0x2f) return ACC_INTERM;
+  if (0x30 <= c && c <=0x3f) return ACC_PARAM;
+  if (0x40 <= c && c <=0x5f) return ACC_UPCASE;
+  if (0x60 <= c && c <=0x7e) return ACC_LOWCASE;
+  if (c == 0x7f) return ACC_DEL;
+  if (0x90 <= c && c <=0x9f) return ACC_C1;
+  if (c == 0xa0) return ACC_SPEC;
+  if (0xA1 <= c && c <=0xfe) return ACC_G1;
+  if (0x90 <= c && c <=0x9f) return ACC_C1;
+  if (c == 0xff) return ACC_SPEC;
+  return ACC_SPEC;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Lookup a key sequence in a sequencemap and queue the key if sequence found
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+lookup_seq(const char* str, const struct seqmap* map)
+{
+  while (map->seq !=  0) {
+    if (strcmp(str,map->seq) == 0) {
+      enqueue_key(map->key);
+      return;
+    }
+    map++;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* \internal
+ * Parse a character stream 
+ * Returns -1 if c is consumed by the state machine 1 else.
+ */
+/*-----------------------------------------------------------------------------------*/
+static int 
+parse_input(struct ctk_term_state* st, unsigned char c)
+{
+  unsigned char cl = classify(c);
+  int ret = -1;
+  switch(st->inputstate) {
+  case ANS_IDLE:
+    switch(cl) {
+    case ACC_C0:
+      {
+	switch(c) {
+	case ASCII_ESC: st->inputstate = ANS_ESCSEQ; break;
+	case ASCII_BS:  enqueue_key(CH_DEL); break;
+	case ASCII_HT:  enqueue_key(CH_TAB); break;
+	case ASCII_FF:  ctk_term_redraw(st); break;
+	case ASCII_CR:  enqueue_key(CH_ENTER); break;
+	}
+      }
+      break;
+      
+    case ACC_INTERM:
+    case ACC_PARAM:
+    case ACC_LOWCASE:
+    case ACC_UPCASE:
+    case ACC_G1:
+      ret = 1;
+      break;
+    case ACC_C1:
+      if (c == ASCII_CSI) {
+	st->inputstate = ANS_CTRLSEQ;
+	st->ctrlCnt = 0;
+      }
+      else if (c == ASCII_SS3) {
+	st->inputstate = ANS_SS3;
+	st->ctrlCnt = 0;
+      }
+      break;
+    case ACC_DEL:
+      enqueue_key(CH_DEL);
+      break;
+    case ACC_SPEC:
+      break;
+    }
+    break;
+    
+  case ANS_ESCSEQ:
+    {
+      switch(cl) {
+      case ACC_C0:
+      case ACC_DEL:
+	break;
+      case ACC_INTERM:
+	st->inputstate = ANS_ESCSEQ_1;
+	break;
+      case ACC_UPCASE:
+	/* C1 control character */
+	if (c == '[') {
+	  st->inputstate = ANS_CTRLSEQ;
+	  st->ctrlCnt = 0;
+	}
+	else if (c == 'O') {
+	  st->inputstate = ANS_SS3;
+	  st->ctrlCnt = 0;
+	}
+	else {
+	  st->inputstate = ANS_IDLE;
+	}
+	break;
+      case ACC_PARAM:
+	/* Private 2-character sequence */
+      case ACC_LOWCASE:
+	/* Standard 2-character sequence */
+      default:
+	st->inputstate = ANS_IDLE;
+	break;
+      }
+    }
+    break;
+    
+  case ANS_ESCSEQ_1:
+    {
+      switch(cl) {
+      case ACC_C0:
+      case ACC_INTERM:
+	break;
+      case ACC_PARAM:
+	/* Private function*/
+      case ACC_LOWCASE:
+      case ACC_UPCASE:
+	/* Standard function */
+      default:
+	st->inputstate = ANS_IDLE;
+	break;
+      }
+    }
+    break;
+  case ANS_SS3:
+    {
+      switch(cl) {
+      case ACC_PARAM:
+	if (st->ctrlCnt < CTK_TERM_CTRLBUFLEN) st->ctrlbuf[st->ctrlCnt++]=c;
+	break;
+      case ACC_UPCASE:
+	/* VT100 PF seq */
+	if (st->ctrlCnt < CTK_TERM_CTRLBUFLEN) st->ctrlbuf[st->ctrlCnt++]=c;
+	st->inputstate = ANS_IDLE;
+	st->ctrlbuf[st->ctrlCnt] = 0;
+	lookup_seq((const char*)(st->ctrlbuf), ss3map);
+	break;
+      default:
+	st->inputstate = ANS_IDLE;
+	break;
+      }
+    }
+    break;
+  case ANS_CTRLSEQ:
+    {
+      switch(cl) {
+      case ACC_C0:
+	break;
+      case ACC_INTERM:
+      case ACC_PARAM:
+	if (st->ctrlCnt < CTK_TERM_CTRLBUFLEN) st->ctrlbuf[st->ctrlCnt++]=c;
+	break;
+      case ACC_LOWCASE:
+      case ACC_UPCASE:
+	/* Standard control sequence */
+	if (st->ctrlCnt < CTK_TERM_CTRLBUFLEN) st->ctrlbuf[st->ctrlCnt++]=c;
+	/* Cygwin console sends ESC [ [ A for function keys */
+	if (c != '[') {
+	  st->ctrlbuf[st->ctrlCnt] = 0;
+	  lookup_seq((const char*)(st->ctrlbuf), ctrlmap);
+	  st->inputstate = ANS_IDLE;
+	}
+	break;
+      default:
+	st->inputstate = ANS_IDLE;
+	break;
+      }
+    }
+    break;
+  }
+  return ret;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Initialize the input buffer
+ */
+/*-----------------------------------------------------------------------------------*/
+void ctk_term_input_init()
+{
+  firstkey = lastkey = 0;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Handles an input character provided by the client
+ *
+ * \param ts State information
+ * \param b  Input character
+ */
+/*-----------------------------------------------------------------------------------*/
+void ctk_term_input(struct ctk_term_state* ts, unsigned char b)
+{
+  int ret = parse_input(ts, b);
+  PRINTF(("terminput: 0x%02x\n", b));
+  if (ret > 0) {
+    enqueue_key((ctk_arch_key_t)b);
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Checks the key press input queue to see if there are pending
+ * keys. Called by the CTK module.
+ *
+ * \return Zero if no key presses are in buffer, non-zero if there are
+ * key presses in input buffer.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_arch_keyavail(void)
+{
+  return firstkey != lastkey;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Retrieves key presses from the VNC client. Called by the CTK
+ * module.
+ *
+ * \return The next key in the input queue.
+ */
+/*-----------------------------------------------------------------------------------*/
+ctk_arch_key_t
+ctk_arch_getkey(void)
+{
+  ctk_arch_key_t key;
+  key = keys[firstkey];
+  
+  if(firstkey != lastkey) {
+    ++firstkey;
+    if(firstkey >= NUMKEYS) {
+      firstkey = 0;
+    }
+  }
+  
+  return key;  
+}
+
diff --git a/contiki/ctk/ctk-term-int.h b/contiki/ctk/ctk-term-int.h
new file mode 100644
index 0000000..711c8ab
--- /dev/null
+++ b/contiki/ctk/ctk-term-int.h
@@ -0,0 +1,67 @@
+#ifndef __CTK_TERM_INT_H__
+#define __CTK_TERM_INT_H__
+
+/* Color definitions */
+
+#define TERM_BACKGROUNDCOLOR 0
+#define TERM_WINDOWCOLOR    1
+#define TERM_SEPARATORCOLOR 7 /*(TERM_WINDOWCOLOR + 6)*/
+#define TERM_LABELCOLOR     13 /*(TERM_SEPARATORCOLOR + 6)*/
+#define TERM_BUTTONCOLOR    19 /*(TERM_LABELCOLOR + 6)*/
+#define TERM_HYPERLINKCOLOR 25 /*(TERM_BUTTONCOLOR + 6)*/
+#define TERM_TEXTENTRYCOLOR 31 /*(TERM_HYPERLINKCOLOR + 6)*/
+#define TERM_ICONCOLOR      37 /*(TERM_TEXTENTRYCOLOR + 6)*/
+#define TERM_MENUCOLOR      43 /*(TERM_ICONCOLOR + 6)*/
+#define TERM_OPENMENUCOLOR  44/*(TERM_MENUCOLOR + 1)*/
+#define TERM_ACTIVEMENUCOLOR 45 /*(TERM_OPENMENUCOLOR + 1) */
+
+/* Structure describing an updated region */
+struct ctk_term_update {
+  struct ctk_term_update *next;
+
+#define UPDATE_NONE  0
+#define UPDATE_PARTS 1
+#define UPDATE_FULL  2
+
+  unsigned char type;
+
+  unsigned char x, y;
+  unsigned char w, h;  
+};
+
+/* Character sequence parsing states */
+enum { ANS_IDLE, ANS_ESCSEQ,ANS_ESCSEQ_1,ANS_SS3, ANS_CTRLSEQ};
+
+struct ctk_term_state {
+  unsigned char type;
+  unsigned char state;
+  unsigned char height, width;
+
+  /* Variables used when sending screen updates. */
+  unsigned char x, y, x1, y1, x2, y2;
+  unsigned char w, h;
+  unsigned char c1, c2;
+
+#define CTK_TERM_MAX_UPDATES 8  
+  struct ctk_term_update *updates_current;
+  struct ctk_term_update *updates_pending;
+  struct ctk_term_update *updates_free;
+  struct ctk_term_update updates_pool[CTK_TERM_MAX_UPDATES];
+
+  /* Variables used when parsing input sequences */
+  unsigned char inputstate;
+#define CTK_TERM_CTRLBUFLEN 5
+  unsigned char ctrlbuf[CTK_TERM_CTRLBUFLEN+1];
+  unsigned char ctrlCnt;
+};
+
+struct ctk_term_update * ctk_term_update_alloc(struct ctk_term_state *vs);
+void ctk_term_update_free(struct ctk_term_state *ts, struct ctk_term_update *a);
+void ctk_term_update_remove(struct ctk_term_state *ts, struct ctk_term_update *a);
+
+void ctk_term_update_add(struct ctk_term_state *ts, struct ctk_term_update *a);
+struct ctk_term_update * ctk_term_update_dequeue(struct ctk_term_state *ts);
+
+void ctk_term_input_init();
+
+#endif /* __CTK_TERM_INT_H__ */
diff --git a/contiki/ctk/ctk-term-out.c b/contiki/ctk/ctk-term-out.c
new file mode 100644
index 0000000..5a35a5f
--- /dev/null
+++ b/contiki/ctk/ctk-term-out.c
@@ -0,0 +1,318 @@
+#include "libconio.h"
+#include "ctk-term-int.h"
+#include <string.h>
+#include <stdio.h> // sprintf
+
+#define PRINTF(x)
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * #defines and enums
+ */
+/*-----------------------------------------------------------------------------------*/
+
+#define CHARS_WIDTH    LIBCONIO_CONF_SCREEN_WIDTH
+#define CHARS_HEIGHT   LIBCONIO_CONF_SCREEN_HEIGHT
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Local variables
+ */
+/*-----------------------------------------------------------------------------------*/
+
+/* ANSI/VT100 colors
+  0 - None
+  1 - Bold (inc. inten)
+  4 - Underscore
+  7 - Reverse
+  x0 - black
+  x1 - red
+  x2 - green
+  x3 - yellow
+  x4 - blue
+  x5 - magenta
+  x6 - cyan
+  x7 - white
+  x = 3 fg x = 4 bg
+*/
+#if 0 /* Colorfull theme */
+static const char backgroundcolor[] = "\033[0;37;40m";
+
+static const char wincol[] = "\033[0;37;40m";
+static const char wincol_f[] = "\033[0;1;37;40m";
+static const char wincol_d[] = "\033[0;30;47m";
+
+static const char sepcol[] = "\033[0;37;40m";
+static const char sepcol_f[] = "\033[0;1;37;40m";
+static const char sepcol_d[] = "\033[0;30;47m";
+
+static const char labcol[] = "\033[0;37;40m";
+static const char labcol_f[] = "\033[1;37;40m";
+static const char labcol_d[] = "\033[0;30;47m";
+
+static const char butcol[] = "\033[0;37;40m";
+static const char butcol_w[] = "\033[0;30;47m";
+static const char butcol_f[] = "\033[0;1;37;40m";
+static const char butcol_fw[] = "\033[0;1;37;46m";
+static const char butcol_d[] = "\033[0;30;47m";
+static const char butcol_dw[] = "\033[0;37;46m";
+
+static const char hlcol[] = "\033[0;4;36;40m";
+static const char hlcol_w[] = "\033[0;4;30;47m";
+static const char hlcol_f[] = "\033[0;1;4;36;40m";
+static const char hlcol_fw[] = "\033[0;1;4;37;46m";
+static const char hlcol_d[] = "\033[0;4;34;47m";
+static const char hlcol_dw[] = "\033[0;4;37;46m";
+
+static const char iconcol[] = "\033[0;32;40m";
+static const char iconcol_w[] = "\033[0;30;42m";
+
+static const char menucolor[] = "\033[0;37;43m";
+static const char activemenucolor[] = "\033[0;1;37;43m";
+#endif
+
+#if 1 /* B/W theme */
+static const char backgroundcolor[] = "\033[0m";
+
+static const char wincol[] = "\033[0m";
+static const char wincol_f[] = "\033[0;1m";
+static const char wincol_d[] = "\033[0;7m";
+
+static const char sepcol[] = "\033[0m";
+static const char sepcol_f[] = "\033[0;1m";
+static const char sepcol_d[] = "\033[0;7m";
+
+static const char labcol[] = "\033[0m";
+static const char labcol_f[] = "\033[0;1m";
+static const char labcol_d[] = "\033[0;7m";
+
+static const char butcol[] = "\033[0m";
+static const char butcol_w[] = "\033[0m";
+static const char butcol_f[] = "\033[0;1m";
+static const char butcol_fw[] = "\033[0;1;7m";
+static const char butcol_d[] = "\033[0;7m";
+static const char butcol_dw[] = "\033[0m";
+
+static const char hlcol[] = "\033[0;4m";
+static const char hlcol_w[] = "\033[0;4;7m";
+static const char hlcol_f[] = "\033[0;1;4m";
+static const char hlcol_fw[] = "\033[0;1;4;7m";
+static const char hlcol_d[] = "\033[0;4;7m";
+static const char hlcol_dw[] = "\033[0;4m";
+
+static const char iconcol[] = "\033[0m";
+static const char iconcol_w[] = "\033[0;7m";
+
+static const char menucolor[] = "\033[0;7m";
+static const char activemenucolor[] = "\033[0m";
+
+#endif
+
+static const char* const colortheme[] =
+{
+    backgroundcolor,
+    
+    /* Window colors */
+    wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d,
+
+    /* Separator colors. */
+    sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d,    
+
+    /* Label colors. */
+    labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d,    
+
+    /* Button colors. */
+    butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,    
+
+    /* Hyperlink colors. */
+    hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw,
+
+    /* Textentry colors. */
+    butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
+
+    /* Icon colors */
+    iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w,
+    
+    /* Menu colors. */
+    menucolor, activemenucolor, activemenucolor
+  };
+
+static unsigned char  
+  screen[CHARS_WIDTH * CHARS_HEIGHT],
+  colorscreen[CHARS_WIDTH * CHARS_HEIGHT];
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Add a character to the screen buffer 
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_term_out_update_screen(unsigned char  xpos, 
+			   unsigned char  ypos, 
+			   unsigned char  c, 
+			   unsigned char  color)
+{
+  if (c < 0x20) c = 0x20;
+  screen[xpos + ypos * CHARS_WIDTH] = c;
+  colorscreen[xpos + ypos * CHARS_WIDTH] = color;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Check if there are any updated pending. If so, make the first one current
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+check_updates(struct ctk_term_state* ts)
+{
+  if (ts->updates_current != NULL) return;
+  ts->updates_current = ctk_term_update_dequeue(ts);
+  if (ts->updates_current != NULL) {
+    ts->x = ts->updates_current->x;
+    ts->y = ts->updates_current->y;
+    ts->w = ts->updates_current->w;
+    ts->h = ts->updates_current->h;
+    ts->x1 = ts->x2 = ts->x;
+    ts->y1 = ts->y2 = ts->y;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Adds a cursor position change to buffer. Returns 0 if string doesn't fit else
+ * number of bytes actually written is returned.
+ *
+ * \param x X coordinate (screen coordinates)
+ * \param y Y coordinate (screen coordinates)
+ * \param buf Output buffer
+ * \param maxlen Maximum number of bytes to store in buffer
+ */
+/*-----------------------------------------------------------------------------------*/
+static unsigned short
+move_to(unsigned char x, unsigned char y, unsigned char* buf, unsigned short maxlen)
+{
+  if (maxlen < 14) return 0;
+  return (unsigned short)sprintf((char*)buf, "\033[%d;%dH", y+1, x+1);
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Adds a attribute string to buffer. Returns 0 if string doesn't fit else
+ * number of bytes actually written is returned.
+ *
+ * \param c Color number
+ * \param buf Output buffer
+ * \param maxlen Maximum number of bytes to store in buffer
+ */
+/*-----------------------------------------------------------------------------------*/
+static unsigned short
+set_color(unsigned char c, unsigned char* buf, unsigned short maxlen)
+{
+  int len = strlen((const char*)colortheme[c]);
+  if (maxlen < len) return 0;
+  memcpy(buf, colortheme[c], len);
+  return len;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Stores terminal data in buffer provided by caller. Returns number of bytes written
+ * to the output buffer.
+ *
+ * \param ts State information
+ * \param buf Output buffer
+ * \param maxlen Maximum number of bytes to store in buffer
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned short 
+ctk_term_send(struct ctk_term_state* ts, 
+	      unsigned char* buf, 
+	      unsigned short maxlen)
+{
+  unsigned char x, y, x0;
+  unsigned char col, c;
+  unsigned short tmp;
+  unsigned short totlen;
+  
+  check_updates(ts);
+  
+  if (ts->updates_current == NULL) return 0;
+
+  x0 = ts->x1;
+  col = ts->c1;
+  totlen = 0;
+  /* Loop across the update region starting at (x1,y1) */
+  for(y = ts->y1; y < ts->y + ts->h; ++y) {
+    for(x = x0; x < ts->x + ts->w; ++x) {
+      /* New line ? */
+      if (x == ts->x) {
+	/* Move cursor to start of line */
+	tmp = move_to(x,y,buf,maxlen);
+	if (tmp == 0) goto loopend;
+	buf += tmp;
+	totlen += tmp;
+	maxlen -= tmp;
+      }
+      /* Check color */
+      c = colorscreen[x + y * CHARS_WIDTH];
+      if (c != col) {
+	PRINTF(("colorchange at (%d, %d) to %d\n", x,y,c));
+	/* Send new color information */
+	tmp = set_color(c, buf, maxlen);
+	if (tmp == 0) goto loopend;
+	col = c;
+	buf += tmp;
+	totlen += tmp;
+	maxlen -= tmp;
+      }
+      /* Check remaining space */
+      if (maxlen < 1) goto loopend;
+      /* Add character */
+      *buf = screen[x + y * CHARS_WIDTH];
+      buf++;
+      maxlen--;
+      totlen++;
+    }
+    x0 = ts->x;
+  }
+loopend:
+  /* Always save current color state */
+  ts->c2 = col;  
+  PRINTF(("ending loop at (%d, %d)\n", x,y));
+  /* Check if done */
+  if (x == ts->x+ts->w && y == ts->y+ts->h) {
+    /* Signal done with this update */
+    ts->x2 = ts->y2 = 0;
+  }
+  else {
+    /* Not done. Save state */
+    ts->x2 = x;
+    ts->y2 = y;
+  }
+  return totlen;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Called by client when the data returned by ctk_term_send() are successfully sent.
+ *
+ * \param ts State information
+ */
+/*-----------------------------------------------------------------------------------*/
+void ctk_term_sent(struct ctk_term_state* ts)
+{
+  if (ts->updates_current != NULL) {
+    /* Check if current update done */
+    if (ts->x2 == 0 && ts->y2 == 0) {
+      /* Yes, free it */
+      ctk_term_update_free(ts, ts->updates_current);
+      ts->updates_current = NULL;
+    }
+    else {
+      /* Nop. Update start posititions */
+      ts->x1 = ts->x2;
+      ts->y1 = ts->y2;
+    }
+    ts->c1 = ts->c2;
+  }
+}
diff --git a/contiki/ctk/ctk-term-out.h b/contiki/ctk/ctk-term-out.h
new file mode 100644
index 0000000..6db7544
--- /dev/null
+++ b/contiki/ctk/ctk-term-out.h
@@ -0,0 +1,10 @@
+#ifndef __CTK_TERM_OUT_H__
+#define __CTK_TERM_OUT_H__
+
+void
+ctk_term_out_update_screen(unsigned char  xpos, 
+			   unsigned char  ypos, 
+			   unsigned char  c, 
+			   unsigned char  color);
+
+#endif /* __CTK_TERM_OUT_H__ */
diff --git a/contiki/ctk/ctk-term.c b/contiki/ctk/ctk-term.c
new file mode 100644
index 0000000..cd9bbfe
--- /dev/null
+++ b/contiki/ctk/ctk-term.c
@@ -0,0 +1,996 @@
+#include "ctk.h"
+#include "ctk-draw.h"
+
+#include "contiki.h"
+#include "loader.h"
+#include "ctk-term.h"
+#include "ctk-term-int.h"
+#include "ctk-term-out.h"
+#include "ctk-term-conf.h"
+#include "libconio.h"
+
+#define PRINTF(x)
+
+#define reverse(x)
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * #defines and enums
+ */
+/*-----------------------------------------------------------------------------------*/
+#define CH_ULCORNER '+' //0x00
+#define CH_TITLEBAR '-' //0x01
+#define CH_URCORNER '+' //0x02
+#define CH_WINDOWRBORDER '|' //0x03
+#define CH_LRCORNER '+' //0x04
+#define CH_WINDOWLOWERBORDER '-' //0x05
+#define CH_LLCORNER '+' //0x06
+#define CH_WINDOWLBORDER '|' //0x07
+
+#define CH_DIALOG_ULCORNER '+' //0x12
+#define CH_DIALOGUPPERBORDER '-' //0x09
+#define CH_DIALOG_URCORNER '+' //0x0a
+#define CH_DIALOGRBORDER '|' //0x0b
+#define CH_DIALOG_LRCORNER '+' //0x0c
+#define CH_DIALOGLOWERBORDER '-' //0x0d
+#define CH_DIALOG_LLCORNER '+' //0x0e
+#define CH_DIALOGLBORDER '|' //0x0f
+
+#define CH_BUTTONLEFT  '[' //0x10
+#define CH_BUTTONRIGHT ']' //0x11
+
+#define CH_SEPARATOR   '=' //0x13
+
+#ifdef CTK_TERM_CONF_MAX_CLIENTS
+#define CTK_TERM_NUMCONNS CTK_TERM_CONF_MAX_CLIENTS
+#else
+#define CTK_TERM_NUMCONNS 1
+#endif
+
+unsigned char ctk_draw_windowborder_height = 1;
+unsigned char ctk_draw_windowborder_width = 1;
+unsigned char ctk_draw_windowtitle_height = 1;
+
+
+/* Term context states */
+enum {
+  TERM_DEALLOCATED,
+  TERM_ALLOCATED
+};
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Local variables
+ */
+/*-----------------------------------------------------------------------------------*/
+
+static unsigned char sizex, sizey;
+static struct ctk_term_state conns[CTK_TERM_NUMCONNS];
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Unconditionally add an update
+ */
+/*-----------------------------------------------------------------------------------*/
+void ctk_term_update_add(struct ctk_term_state *ts, struct ctk_term_update *a)
+{
+  /* XXX: test both head and tail placement!*/
+  a->next = ts->updates_pending;
+  ts->updates_pending = a;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Allocate an update from the update pool
+ */
+/*-----------------------------------------------------------------------------------*/
+struct ctk_term_update *
+ctk_term_update_alloc(struct ctk_term_state *vs)
+{
+  struct ctk_term_update *a;
+
+  a = vs->updates_free;
+  if(a == NULL) {
+    return NULL;
+  }
+  vs->updates_free = a->next;
+  a->next = NULL;
+  return a;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Return an update to the pool
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_term_update_free(struct ctk_term_state *ts, struct ctk_term_update *a)
+{
+  a->next = ts->updates_free;
+  ts->updates_free = a;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Fetch update from the update list
+ */
+/*-----------------------------------------------------------------------------------*/
+struct ctk_term_update *
+ctk_term_update_dequeue(struct ctk_term_state *ts)
+{
+  struct ctk_term_update *a;
+
+  a = ts->updates_pending;
+  if(a == NULL) {
+    return a;
+  }
+  ts->updates_pending = a->next;
+  a->next = NULL;
+  return a;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Remove an update from the update list
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_term_update_remove(struct ctk_term_state *ts, struct ctk_term_update *a)
+{
+  struct ctk_term_update *b, *c;
+
+  if(a == ts->updates_pending) {
+    ts->updates_pending = a->next;
+  } else {
+    b = ts->updates_pending;
+    for(c = ts->updates_pending; c != a; b = c, c = c->next);
+
+    b->next = a->next;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Add an area update for a specific connection. Overlapping updates are merged
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+update_area_connection(struct ctk_term_state *ts,
+		    unsigned char  x, unsigned char  y, unsigned char  w, unsigned char  h)
+{
+  unsigned char  x2, y2, ax2, ay2;
+  struct ctk_term_update *a;
+
+  PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",
+	 x, y, w, h));
+  
+  /* First check if we already have a full update queued. If so, there
+     is no need to put this update on the list. If there is a full
+     update, it is always the first one on the list, so there is no
+     need to go step the list in search for it. */
+
+  if(ts->updates_pending != NULL &&
+     ts->updates_pending->type == UPDATE_FULL) {
+    PRINTF(("Update_area_connecion: full update already queued...\n"));
+    return;
+  }
+
+again:
+  
+  /* Check that we don't update the same area twice by going through
+     the list and search for an update with the same coordinates. */
+  for(a = ts->updates_pending; a != NULL; a = a->next) {
+    if(a->x == x && a->y == y &&
+       a->w == w && a->h == h) {
+      PRINTF(("Update_area_connecion: found equal area\n"));
+      return;
+    }    
+  }
+
+  /* Next we check if this update covers an existing update. If so, we
+     remove the old update, expand this update so that it covers both
+     areas to be updated and run through the process again. */
+  for(a = ts->updates_pending; a != NULL; a = a->next) {      
+    x2 = x + w;
+    y2 = y + h;
+    
+    ax2 = a->x + a->w;
+    ay2 = a->y + a->h;
+
+    /* Test if updates overlaps */
+    if(((x < ax2) && (a->x < x2)) &&
+      ((y < ay2) && (a->y < y2))) {
+
+      /* Remove the old update from the list. */
+      ctk_term_update_remove(ts, a);
+
+      /* Put it on the free list. */
+      ctk_term_update_free(ts, a);
+
+      PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",
+	     a->x, a->y, ax2, ay2));
+      
+      /* Find the area that covers both updates. */
+#define MIN(a,b) ((a) < (b)? (a): (b))
+#define MAX(a,b) ((a) > (b)? (a): (b))
+      x = MIN(a->x, x);
+      y = MIN(a->y, y);
+      ax2 = MAX(ax2, x2);
+      ay2 = MAX(ay2, y2);
+      w = ax2 - x;
+      h = ay2 - y;
+
+      /* This should really be done by a recursive call to this
+	 function: update_area_connection(vs, x, y, w, h); but because
+	 some compilers might not be able to optimize away the
+	 recursive call, we do it using a goto instead. */
+      PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));
+      goto again;
+    }
+  }
+  
+  /* Allocate an update object by pulling it off the free list. If
+     there are no free objects, we go for a full update instead. */
+
+  a = ctk_term_update_alloc(ts);
+  if(a == NULL) {
+    PRINTF(("Update_area_connecion: no free updates, doing full\n"));
+    /* Put all pending updates, except for one, on the free list. Use
+       the remaining update as a full update. */
+    while(ts->updates_pending != NULL) {
+      a = ts->updates_pending;
+      ctk_term_update_remove(ts, a);
+      ctk_term_update_free(ts, a);
+    }
+
+    a = ctk_term_update_alloc(ts);
+    a->type = UPDATE_FULL;
+    ctk_term_update_add(ts, a);
+					
+
+  } else {
+    
+    PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));
+  /* Else, we put the update object at the end of the pending
+     list. */
+    a->type = UPDATE_PARTS;
+    a->x = x;
+    a->y = y;
+    a->w = w;
+    a->h = h;
+    ctk_term_update_add(ts, a);
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Update an area for all connections.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+update_area(unsigned char  x, unsigned char  y, unsigned char  w, unsigned char  h)
+{
+  unsigned char  i;
+  
+  if(h == 0 || w == 0) {
+    return;
+  }
+
+  if ((x+w) > sizex) {
+    w = sizex - x;
+  }
+
+  if ((y+h) > sizey) {
+    h = sizey - y;
+  }
+  
+  /* Update for all active terminal connections. */
+  for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {
+    if(conns[i].state != TERM_DEALLOCATED) {
+      update_area_connection(&conns[i],x, y, w, h);
+    }
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Request a full update for a specific connections. Usefull when a new client is
+ * connected through telnet for example.
+ *
+ * \param ts Terminal connection state
+ */
+/*-----------------------------------------------------------------------------------*/
+void ctk_term_redraw(struct ctk_term_state *ts)
+{
+  update_area_connection(ts,0,0,ts->width, ts->height);
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Initialize a terminal state structure
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+init_state(struct ctk_term_state *ts)
+{
+  unsigned char i;
+  
+  ts->width = sizex;
+  ts->height = sizey;
+  ts->x = ts->y = ts->x1 = ts->y1 = ts->x2 = ts->y2 = 0;
+  ts->c1 = ts->c2 = 0;
+  ts->w = sizex;
+  ts->h = sizey;
+  ts->state = TERM_ALLOCATED;
+  ts->inputstate = ANS_IDLE;
+
+  /* Initialize the linked list of updates. */
+  for(i = 0; i < CTK_TERM_MAX_UPDATES - 1; ++i) {
+    ts->updates_pool[i].next = &(ts->updates_pool[i + 1]);    
+  }
+  ts->updates_pool[CTK_TERM_MAX_UPDATES-1].next = NULL;
+
+  ts->updates_free = &ts->updates_pool[0];
+  ts->updates_pending = ts->updates_current = NULL;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Allocate a new state structure. Returns NULL if none available
+ */
+/*-----------------------------------------------------------------------------------*/
+struct ctk_term_state *
+ctk_term_alloc_state(void)
+{
+  unsigned char i;
+  for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {
+    if(conns[i].state == TERM_DEALLOCATED) {
+      init_state(&conns[i]);
+      return &conns[i];
+    }
+  }
+  return NULL;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Free a state structure.
+ *
+ * \param ts Terminal connection state
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_term_dealloc_state(struct ctk_term_state *s)
+{
+  s->state = TERM_DEALLOCATED;
+}
+/*-----------------------------------------------------------------------------------*/
+static char tmp[40];
+static void
+cputsn(char *str, unsigned char len)
+{
+  strncpy(tmp, str, len);
+  tmp[len] = 0;
+  cputs(tmp);
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Initialize the terminal ctk-draw module. Called by the CTK module.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_init(void)
+{
+  int i;
+  bgcolor(TERM_BACKGROUNDCOLOR);
+  screensize(&sizex, &sizey);
+  ctk_draw_clear(0, sizey);
+  ctk_term_input_init();
+  for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {
+    conns[i].state = TERM_DEALLOCATED;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_widget(struct ctk_widget *w,
+	    unsigned char x, unsigned char y,
+	    unsigned char clipx,
+	    unsigned char clipy,
+	    unsigned char clipy1, unsigned char clipy2,
+	    unsigned char focus)
+{
+  unsigned char xpos, ypos, xscroll;
+  unsigned char i, j;
+  char c, *text;
+  unsigned char len;
+
+  xpos = x + w->x;
+  ypos = y + w->y;
+    
+  switch(w->type) {
+  case CTK_WIDGET_SEPARATOR:
+    textcolor((unsigned char)(TERM_SEPARATORCOLOR + focus));
+    if(ypos >= clipy1 && ypos < clipy2) {
+      gotoxy(xpos, ypos);
+      for(i = 0; i < w->w; ++i) {
+	cputc(CH_SEPARATOR);
+      }
+    }
+    break;
+  case CTK_WIDGET_LABEL:
+    textcolor((unsigned char)(TERM_LABELCOLOR + focus));
+    text = w->widget.label.text;
+    for(i = 0; i < w->h; ++i) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	gotoxy(xpos, ypos);
+	cputsn(text, w->w);
+	if(w->w - (wherex() - xpos) > 0) {
+	  cclear((unsigned char)(w->w - (wherex() - xpos)));
+	}
+      }
+      ++ypos;
+      text += w->w;
+    }
+    break;
+  case CTK_WIDGET_BUTTON:
+    textcolor((unsigned char)(TERM_BUTTONCOLOR + focus));
+    if(ypos >= clipy1 && ypos < clipy2) {
+      if(focus & CTK_FOCUS_WIDGET) {
+	revers(1);
+      } else {
+	revers(0);
+      }
+      cputcxy(xpos, ypos, CH_BUTTONLEFT);
+      cputsn(w->widget.button.text, w->w);
+      cputc(CH_BUTTONRIGHT);
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_HYPERLINK:
+    textcolor((unsigned char)(TERM_HYPERLINKCOLOR + focus));
+    if(ypos >= clipy1 && ypos < clipy2) {
+      if(focus & CTK_FOCUS_WIDGET) {
+	revers(0);	
+      } else {
+	revers(1);
+      }
+      gotoxy(xpos, ypos);
+      cputsn(w->widget.button.text, w->w);
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_TEXTENTRY:
+    textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + focus));
+    text = w->widget.textentry.text;
+    xscroll = 0;
+    if(w->widget.textentry.xpos >= w->w - 1) {
+      xscroll = w->widget.textentry.xpos - w->w + 1;
+    }
+    for(j = 0; j < w->h; ++j) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
+	   w->widget.textentry.ypos == j) {
+	  revers(0);
+	  cputcxy(xpos, ypos, '>');
+	  c = 1;
+	  for(i = 0; i < w->w; ++i) {
+	    if(c != 0) {
+	      c = text[i + xscroll];
+	    }
+	    if(i == w->widget.textentry.xpos - xscroll) {
+	      textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + (focus ^ 0x01)));
+	      revers(1);
+	    } else {
+	      revers(0);
+	    }
+	    if(c == 0) {
+	      cputc(' ');
+	    } else {
+	      cputc(c);
+	    }
+	    revers(0);
+	    textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + focus));
+	  }
+	  cputc('<');
+	} else {
+	  if(focus & CTK_FOCUS_WIDGET && j == w->widget.textentry.ypos) {
+	    revers(1);
+	  } else {
+	    revers(0);
+	  }
+	  cvlinexy(xpos, ypos, 1);
+	  gotoxy((unsigned char)(xpos + 1), ypos);          
+	  cputsn(text, w->w);
+	  i = wherex();
+	  if(i - xpos - 1 < w->w) {
+	    cclear((unsigned char)(w->w - (i - xpos) + 1));
+	  }
+	  cvline(1);
+	}
+      }
+      ++ypos;
+      text += w->widget.textentry.len + 1;
+    }
+    revers(0);
+    break;
+  case CTK_WIDGET_ICON:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      textcolor((unsigned char)(TERM_ICONCOLOR + focus));
+      if(focus & 1) {
+	revers(1);
+      } else {
+	revers(0);
+      }
+
+      x = xpos;
+      len = strlen(w->widget.icon.title);
+      if(x + len >= sizex) {
+	x = sizex - len;
+      }
+
+      gotoxy(x, (unsigned char)(ypos + 3));
+      if(ypos >= clipy1 && ypos < clipy2) {
+	cputs(w->widget.icon.title);
+      }
+
+      gotoxy(xpos, ypos);
+
+      if (w->widget.icon.textmap != NULL) {
+	for(i = 0; i < 3; ++i) {
+	  
+	  if(ypos >= clipy1 && ypos < clipy2) {
+	    gotoxy(xpos,ypos);
+	    cputc(w->widget.icon.textmap[0 + 3 * i]);
+	    cputc(w->widget.icon.textmap[1 + 3 * i]);
+	    cputc(w->widget.icon.textmap[2 + 3 * i]);
+	  }
+	  ++ypos;
+	}
+      }
+      x = xpos;
+      revers(0);
+    }
+    break;
+
+  default:
+    break;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw a widget on the VNC screen. Called by the CTK module.
+ *
+ * \param w The widget to be drawn.
+ * \param focus The focus of the widget.
+ * \param clipy1 The lower y coordinate bound.
+ * \param clipy2 The upper y coordinate bound.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_widget(struct ctk_widget *w,
+		unsigned char focus,
+		unsigned char clipy1,
+		unsigned char clipy2)
+{
+  struct ctk_window *win = w->window;
+  struct ctk_icon *icon;
+  unsigned char posx, posy, x, len;
+
+  posx = win->x + 1;
+  posy = win->y + 2;
+
+  if(w == win->focused) {
+    focus |= CTK_FOCUS_WIDGET;
+  }
+  
+  draw_widget(w, posx, posy,
+	      (unsigned char)(posx + win->w),
+	      (unsigned char)(posy + win->h),
+	      clipy1, clipy2,
+	      focus);
+
+  if(w->type != CTK_WIDGET_ICON) {
+    update_area((unsigned char)(posx + w->x),
+		(unsigned char)(posy + w->y), 
+		(unsigned char)(w->w + 2), 
+		w->h);
+  } else {
+    icon = (struct ctk_icon *)w;
+
+    len = strlen(icon->title);
+    x = posx + w->x;
+    if(x + len >= sizex) {
+      x = sizex - len;
+    }
+
+    update_area(x, 
+      (unsigned char)(posy + w->y), 
+      (unsigned char)(len > 4? len: 4), 
+      w->h);    
+  }
+  
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Clear a window on the terminal screen. Called by the CTK module.
+ *
+ * \param window The window to be cleared.
+ * \param focus The focus of the window.
+ * \param clipy1 The lower y coordinate bound.
+ * \param clipy2 The upper y coordinate bound.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear_window(struct ctk_window *window,
+		      unsigned char focus,
+		      unsigned char clipy1,
+		      unsigned char clipy2)
+{
+  unsigned char i;
+  unsigned char h;
+
+  textcolor((unsigned char)(TERM_WINDOWCOLOR + focus));
+  
+  h = window->y + 2 + window->h;
+  /* Clear window contents. */
+  for(i = window->y + 2; i < h; ++i) {
+    if(i >= clipy1 && i < clipy2) {
+      cclearxy((unsigned char)(window->x + 1), i, window->w);
+    }
+  }
+
+  update_area((unsigned char)(window->x + 1),
+    (unsigned char)(window->y + 2), 
+    window->w, window->h);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_window_contents(struct ctk_window *window, unsigned char focus,
+		     unsigned char clipy1, unsigned char clipy2,
+		     unsigned char x1, unsigned char x2,
+		     unsigned char y1, unsigned char y2)
+{
+  struct ctk_widget *w;
+  unsigned char wfocus;
+  
+  /* Draw inactive widgets. */
+  for(w = window->inactive; w != NULL; w = w->next) {
+    draw_widget(w, x1, y1, x2, y2,
+		clipy1, clipy2,
+		focus);
+  }
+  
+  /* Draw active widgets. */
+  for(w = window->active; w != NULL; w = w->next) {  
+    wfocus = focus;
+    if(w == window->focused) {
+      wfocus |= CTK_FOCUS_WIDGET;
+    }
+
+   draw_widget(w, x1, y1, x2, y2, 
+	       clipy1, clipy2,
+	       wfocus);
+  }
+
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw a window on the terminal screen. Called by the CTK module.
+ *
+ * \param window The window to be drawn.
+ * \param focus The focus of the window.
+ * \param clipy1 The lower y coordinate bound.
+ * \param clipy2 The upper y coordinate bound.
+ * \param draw_borders The flag for border drawing.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_window(struct ctk_window *window, unsigned char focus,
+		unsigned char clipy1, unsigned char clipy2,
+		unsigned char draw_borders)
+{
+  unsigned char x, y;
+  unsigned char h;
+  unsigned char x1, y1, x2, y2;
+  unsigned char i;
+  
+
+  if(window->y + 1 >= clipy2) {
+    return;
+  }
+    
+  x = window->x;
+  y = window->y + 1;
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + window->w;
+  y2 = y1 + window->h;
+
+  if(draw_borders) {
+
+    /* Draw window frame. */  
+    textcolor((unsigned char)(TERM_WINDOWCOLOR + focus));
+
+    if(y >= clipy1) {
+      cputcxy(x, y, CH_ULCORNER);
+      for(i = wherex() + window->titlelen + CTK_CONF_WINDOWMOVE * 2; i < x2; ++i) {
+	cputcxy(i, y, CH_TITLEBAR);
+      }
+      cputcxy(x2, y, CH_URCORNER);
+    }
+
+    h = window->h;
+  
+    if(clipy1 > y1) {
+      if(clipy1 - y1 < h) {
+	h = clipy1 - y1;
+	y1 = clipy1;
+      } else {
+	h = 0;
+      }
+    }
+  
+    if(clipy2 < y1 + h) {
+      if(y1 >= clipy2) {
+	h = 0;
+      } else {
+	h = clipy2 - y1;
+      }
+    }
+  
+    for(i = y1; i < y1 + h; ++i) {
+      cputcxy(x, i, CH_WINDOWLBORDER);
+      cputcxy(x2, i, CH_WINDOWRBORDER);
+    }
+
+    if(y2 >= clipy1 &&
+       y2 < clipy2) {
+      cputcxy(x, y2, CH_LLCORNER);
+      for(i = x1; i < x2; ++i) {
+	cputcxy(i, y2, CH_WINDOWLOWERBORDER);
+      }
+      cputcxy(x2, y2, CH_LRCORNER);
+    }
+  }
+
+  draw_window_contents(window, focus, clipy1, clipy2,
+		       x1, x2, (unsigned char)(y + 1), y2);
+
+  update_area(window->x, window->y, 
+    (unsigned char)(window->w + 2), 
+    (unsigned char)(window->h + 2));
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw a dialog on the terminal screen. Called by the CTK module.
+ *
+ * \param dialog The dialog to be drawn.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_dialog(struct ctk_window *dialog)
+{
+  unsigned char x, y;
+  unsigned char i;
+  unsigned char x1, y1, x2, y2;
+
+  textcolor(TERM_WINDOWCOLOR + CTK_FOCUS_DIALOG);
+
+  x = dialog->x;
+  y = dialog->y + 1;
+
+
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + dialog->w;
+  y2 = y1 + dialog->h;
+
+
+  /* Draw dialog frame. */
+  
+  for(i = y1; i < y1 + dialog->h; ++i) {
+    cputcxy(x, i, CH_DIALOGLBORDER);
+    cputcxy(x2, i, CH_DIALOGRBORDER);
+  }
+  
+  for(i = x1; i < x2; ++i) {
+    cputcxy(i, y, CH_DIALOGUPPERBORDER);
+    cputcxy(i, y2, CH_DIALOGLOWERBORDER);
+  }
+
+  cputcxy(x, y, CH_DIALOG_ULCORNER);
+  cputcxy(x, y2, CH_DIALOG_LLCORNER);
+  cputcxy(x2, y, CH_DIALOG_URCORNER);
+  cputcxy(x2, y2, CH_DIALOG_LRCORNER);
+  
+  
+  /* Clear dialog contents. */
+  for(i = y1; i < y2; ++i) {
+    cclearxy(x1, i, dialog->w);
+  }
+
+  draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
+		       x1, x2, y1, y2);
+
+  update_area(dialog->x, dialog->y, 
+    (unsigned char)(dialog->w + 4), 
+    (unsigned char)(dialog->h + 4));
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Clear parts of the terminal desktop. Called by the CTK module.
+ *
+ * \param y1 The lower y coordinate bound.
+ * \param y2 The upped y coordinate bound.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear(unsigned char y1, unsigned char y2)
+{
+  unsigned char i;
+
+  textcolor(TERM_BACKGROUNDCOLOR);
+  for(i = y1; i < y2; ++i) {
+    cclearxy(0, i, sizex);
+  }
+
+  update_area(0, y1, sizex, (unsigned char)(y2 - y1));
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Draw one menu on the termainl desktop.
+ *
+ * \param m The CTK menu to be drawn.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_menu(struct ctk_menu *m)
+{
+  unsigned char x, x2, y;
+
+  textcolor(TERM_MENUCOLOR);
+  x = wherex();
+  cputs(m->title);
+  cputc(' ');
+  x2 = wherex();
+  if(x + CTK_CONF_MENUWIDTH > sizex) {
+    x = sizex - CTK_CONF_MENUWIDTH;
+  }
+  
+  
+  for(y = 0; y < m->nitems; ++y) {
+    if(y == m->active) {
+      textcolor(TERM_ACTIVEMENUCOLOR);
+      revers(0);
+    } else {
+      textcolor(TERM_MENUCOLOR);	  
+    }
+    gotoxy(x, (unsigned char)(y + 1));
+    if(m->items[y].title[0] == '-') {
+      chline(CTK_CONF_MENUWIDTH);
+    } else {
+      cputs(m->items[y].title);
+    }
+    if(x + CTK_CONF_MENUWIDTH > wherex()) {
+      cclear((unsigned char)(x + CTK_CONF_MENUWIDTH - wherex()));
+    }
+    revers(1);
+  }
+  
+  gotoxy(x2, 0);
+  textcolor(TERM_MENUCOLOR);  
+
+  update_area(x, 0, CTK_CONF_MENUWIDTH, (unsigned char)(m->nitems + 1));
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw the menus on the terminal desktop. Called by the CTK module.
+ *
+ * \param menus The CTK menubar.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_menus(struct ctk_menus *menus)
+{
+  struct ctk_menu *m;  
+
+  
+  /* Draw menus */
+  textcolor(TERM_MENUCOLOR);
+  gotoxy(0, 0);
+  revers(1);
+  cputc(' ');
+  for(m = menus->menus->next; m != NULL; m = m->next) {
+    if(m != menus->open) {
+      update_area(wherex(), 0, (unsigned char)(strlen(m->title) + 1), 1);
+      cputs(m->title);
+      cputc(' ');
+    } else {
+      draw_menu(m);
+    }
+  }
+
+
+  if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
+    gotoxy((unsigned char)(sizex - strlen(menus->desktopmenu->title) - 1), 0);
+  } else {
+    cclear((unsigned char)(sizex - wherex() - strlen(menus->desktopmenu->title) - 1));
+    update_area(wherex(), 0, 
+      (unsigned char)(sizex - wherex() -strlen(menus->desktopmenu->title) - 1), 
+      1);
+  }
+  
+  /* Draw desktopmenu */
+  if(menus->desktopmenu != menus->open) {
+    update_area(wherex(), 0, (unsigned char)(strlen(menus->desktopmenu->title) + 1), 1);
+    cputs(menus->desktopmenu->title);
+    cputc(' ');
+  } else {
+    draw_menu(menus->desktopmenu);
+  }
+
+  revers(0);
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Obtain the height of the terminal desktop. Called by the CTK module.
+ *
+ * \return The height of the terminal desktop, in characters.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_height(void)
+{
+  return sizey;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Obtain the height of the terminal desktop. Called by the CTK module.
+ *
+ * \return The height of the terminal desktop, in characters.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_width(void)
+{
+  return sizex;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Draws a character on the virtual screen. Called by the libconio module.
+ *
+ * \param c The character to be drawn.
+ * \param xpos The x position of the character.
+ * \param ypos The y position of the character.
+ * \param reversedflag Determines if the character should be reversed or not.
+ * \param color The color of the character.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_arch_draw_char(char c,
+		   unsigned char xpos,
+		   unsigned char ypos,
+		   unsigned char reversedflag,
+		   unsigned char color)
+{
+  /* Check if out of bounds */
+  if (xpos >= sizex || ypos >= sizey) {
+    return;
+  }
+  ctk_term_out_update_screen(xpos,ypos, (unsigned char)(c & 0x7f), color);
+}
diff --git a/contiki/ctk/ctk-term.h b/contiki/ctk/ctk-term.h
new file mode 100644
index 0000000..e3bebd5
--- /dev/null
+++ b/contiki/ctk/ctk-term.h
@@ -0,0 +1,14 @@
+#ifndef __CTK_TERM_H__
+#define __CTK_TERM_H__
+
+struct ctk_term_state* ctk_term_alloc_state(void);
+void ctk_term_dealloc_state(struct ctk_term_state *s);
+void ctk_term_redraw(struct ctk_term_state *s);
+void ctk_term_sent(struct ctk_term_state* ts);
+unsigned short ctk_term_send(struct ctk_term_state* ts, 
+				 unsigned char* buf, 
+				 unsigned short maxlen);
+
+void ctk_term_input(struct ctk_term_state* ts, unsigned char b);
+
+#endif /* __CTK_TERM_H__ */
diff --git a/contiki/ctk/ctk-termarch.h b/contiki/ctk/ctk-termarch.h
new file mode 100644
index 0000000..317bbf6
--- /dev/null
+++ b/contiki/ctk/ctk-termarch.h
@@ -0,0 +1,26 @@
+#ifndef __CTK_TERMARCH_H__
+#define __CTK_TERMARCH_H__
+
+
+typedef char ctk_arch_key_t;
+
+unsigned char ctk_arch_keyavail(void);
+ctk_arch_key_t ctk_arch_getkey(void);
+
+#define CH_ENTER 0x0d
+#define CH_DEL 0x08
+
+#define CH_TAB  0x09
+
+#define CH_CURS_LEFT  0x11
+#define CH_CURS_UP    0x12
+#define CH_CURS_RIGHT 0x13
+#define CH_CURS_DOWN  0x14
+
+
+#define CH_F1 0x15
+#define CH_F2 0x16
+#define CH_F3 0x17
+#define CH_F4 0x18
+
+#endif /* __CTK_TERMARCH_H__ */
diff --git a/contiki/ctk/ctk-termserial.c b/contiki/ctk/ctk-termserial.c
new file mode 100644
index 0000000..2246f68
--- /dev/null
+++ b/contiki/ctk/ctk-termserial.c
@@ -0,0 +1,78 @@
+#include "contiki.h"
+#include "loader.h"
+#include "ctk-term.h"
+#include "serial32.h"
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * #defines and enums
+ */
+/*-----------------------------------------------------------------------------------*/
+#define SIO_POLL(c)  (SerialRead(&c) == 1)
+#define SIO_SEND(c)  SerialWrite(c)
+#define SIO_INIT     SerialOpenPort("COM1")
+
+#ifdef CTK_TERM_CONF_SERIAL_BUFFER_SIZE
+#define OUTPUT_BUFFER_SIZE CTK_TERM_CONF_SERIAL_BUFFER_SIZE
+#else
+#define OUTPUT_BUFFER_SIZE 200
+#endif
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Local variables
+ */
+/*-----------------------------------------------------------------------------------*/
+static ek_id_t id = EK_ID_NONE;
+
+static struct ctk_term_state* termstate;
+static unsigned char outbuffer[OUTPUT_BUFFER_SIZE];
+
+EK_POLLHANDLER(pollhandler);
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "CTK serial server", EK_PRIO_NORMAL,
+	   eventhandler, pollhandler, NULL);
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Idle function
+ */
+/*-----------------------------------------------------------------------------------*/
+EK_POLLHANDLER(pollhandler)
+{
+  unsigned char c;
+  unsigned short len;
+  while(SIO_POLL(c)) {
+    ctk_term_input(termstate, c);
+  }
+
+  len = ctk_term_send(termstate, outbuffer, OUTPUT_BUFFER_SIZE);
+  if (len > 0) {
+    unsigned short i;
+    for (i=0; i < len; ++i) {
+      SIO_SEND(outbuffer[i]);
+    }
+    ctk_term_sent(termstate);
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Init function
+ */
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(ctk_termserial_init, arg)
+{
+  arg_free(arg);
+  SIO_INIT;
+  termstate = ctk_term_alloc_state();
+  if (termstate == NULL) return;
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+
+}
diff --git a/contiki/ctk/ctk-termserial.h b/contiki/ctk/ctk-termserial.h
new file mode 100644
index 0000000..55dcd4e
--- /dev/null
+++ b/contiki/ctk/ctk-termserial.h
@@ -0,0 +1,6 @@
+#ifndef __CTK_TERMSERIAL_H__
+#define __CTK_TERMSERIAL_H__
+
+void ctk_termserial_init(char *arg);
+
+#endif /* __CTK_TERMSERIAL_H__ */
diff --git a/contiki/ctk/ctk-termtelnet.c b/contiki/ctk/ctk-termtelnet.c
new file mode 100644
index 0000000..6531de0
--- /dev/null
+++ b/contiki/ctk/ctk-termtelnet.c
@@ -0,0 +1,620 @@
+#include "contiki.h"
+#include "loader.h"
+#include "memb.h"
+#include "ctk-term.h"
+#include "ctk-term-conf.h"
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * #defines and enums
+ */
+/*-----------------------------------------------------------------------------------*/
+/* Telnet special characters */
+#define TN_NULL   0
+#define TN_BL    7
+#define TN_BS     8
+#define TN_HT     9
+#define TN_LF    10
+#define TN_VT    11
+#define TN_FF    12
+#define TN_CR    13
+
+/* Commands preceeded by TN_IAC */
+#define TN_SE   240
+#define TN_NOP  241
+#define TN_DM   242
+#define TN_BRK  243
+#define TN_IP   244
+#define TN_AO   245
+#define TN_AYT  246
+#define TN_EC   247
+#define TN_EL   248
+#define TN_GA   249
+#define TN_SB   250
+#define TN_WILL 251
+#define TN_WONT 252
+#define TN_DO   253
+#define TN_DONT 254
+#define TN_IAC  255
+
+#define TNO_BIN   0
+#define TNO_ECHO  1
+#define TNO_SGA   3
+#define TNO_NAWS 31
+
+/* Telnet parsing states */
+enum { 
+  TNS_IDLE, 
+  TNS_IAC, 
+  TNS_OPT, 
+  TNS_SB, 
+  TNS_SBIAC 
+};
+
+/* Telnet option negotiation states */
+enum { 
+  TNOS_NO, 
+  TNOS_WANTNO_EMPTY, 
+  TNOS_WANTNO_OPPOSITE, 
+  TNOS_WANTYES_EMPTY, 
+  TNOS_WANTYES_OPPOSITE, 
+  TNOS_YES 
+};
+
+/* Telnet session states */
+enum {
+  TTS_FREE,        /* Not allocated */
+  TTS_IDLE,        /* No data to send and nothing sent */
+  TTS_SEND_TNDATA, /* Sending telnet data */
+  TTS_SEND_APPDATA /* Sending data from upper layers */
+};
+
+/* Number of options supported (we only need ECHO(1) and SGA(3) options) */
+#define TNSM_MAX_OPTIONS 4
+
+/* Max option replies in output queue */
+#define TNQLEN 20
+
+/* Number of option buffer */
+#define OPTION_POOL_SIZE 20
+
+/* Maximum number of telnet sessions */
+#ifdef CTK_TERM_CONF_MAX_TELNET_CLIENTS
+#define NUM_CONNS CTK_TERM_CONF_MAX_TELNET_CLIENTS
+#else
+#define NUM_CONNS 1
+#endif
+
+#ifdef CTK_TERM_CONF_TELNET_PORT
+#define PORT CTK_TERM_CONF_TELNET_PORT
+#else
+#define PORT 23
+#endif
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Structures
+ */
+/*-----------------------------------------------------------------------------------*/
+/* Telnet option state structure */
+struct TNOption {
+  unsigned char state;
+  unsigned char wants;
+};
+
+/* Telnet handling state structure */
+struct TNSMState
+{
+  struct TNOption myOpt[TNSM_MAX_OPTIONS];
+  struct TNOption hisOpt[TNSM_MAX_OPTIONS];
+  unsigned char cmd;
+  unsigned char state;
+};
+
+/* Telnet session state */
+struct telnet_state
+{
+  unsigned char state;
+  unsigned char* sendq[TNQLEN];
+  struct TNSMState tnsm;
+  struct ctk_term_state* termstate;
+};
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Local variables
+ */
+/*-----------------------------------------------------------------------------------*/
+/*static DISPATCHER_UIPCALL(ctk_termtelnet_appcall, state);*/
+static void ctk_termtelnet_appcall(void *state);
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "CTK telnet server", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+/*static struct dispatcher_proc p =
+  {DISPATCHER_PROC("CTK telnet server", NULL, NULL,
+  ctk_termtelnet_appcall)};*/
+
+static ek_id_t id = EK_ID_NONE;
+
+/* Option negotiation buffer pool */
+MEMB(telnetbuf, 3, OPTION_POOL_SIZE);
+
+static int i,j;
+static struct telnet_state states[NUM_CONNS];
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Send an option reply on a connection
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+Reply(struct telnet_state* tns, unsigned char cmd, unsigned char opt)
+{
+  unsigned char* buf = (unsigned char*)memb_alloc(&telnetbuf);
+  if (buf != 0) {
+    buf[0]=TN_IAC;
+    buf[1]=cmd;
+    buf[2]=opt;
+    for (i=0; i < TNQLEN; i++) {
+      if (tns->sendq[i] == 0) {
+	tns->sendq[i] = buf;
+	return;
+      }
+    }
+    /* Queue is full. Drop it */
+    memb_free(&telnetbuf, (char*)buf);
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Prepare for enabling one of remote side options.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+EnableHisOpt(struct telnet_state* tns, unsigned char opt)
+{
+  switch(tns->tnsm.hisOpt[opt].state) {
+  case TNOS_NO:
+    tns->tnsm.hisOpt[opt].wants = 1;
+    tns->tnsm.hisOpt[opt].state = TNOS_WANTYES_EMPTY;
+    Reply(tns, TN_DO, opt);
+    break;
+  case TNOS_WANTNO_EMPTY:
+    tns->tnsm.hisOpt[opt].state = TNOS_WANTNO_OPPOSITE;
+    break;
+  case TNOS_WANTNO_OPPOSITE:
+    break;
+  case TNOS_WANTYES_EMPTY:
+    tns->tnsm.hisOpt[opt].state = TNOS_YES;
+    break;
+  case TNOS_WANTYES_OPPOSITE:
+    tns->tnsm.hisOpt[opt].state = TNOS_WANTYES_EMPTY;
+    break;
+  case TNOS_YES:
+    break;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Prepare for enabling one of my options 
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+EnableMyOpt(struct telnet_state* tns, unsigned char opt)
+{
+  if (opt < TNSM_MAX_OPTIONS) {
+    switch(tns->tnsm.myOpt[opt].state) {
+    case TNOS_NO:
+      tns->tnsm.myOpt[opt].wants = 1;
+      tns->tnsm.myOpt[opt].state = TNOS_WANTYES_EMPTY;
+      Reply(tns, TN_WILL, opt);
+      break;
+    case TNOS_WANTNO_EMPTY:
+      tns->tnsm.myOpt[opt].state = TNOS_WANTNO_OPPOSITE;
+      break;
+    case TNOS_WANTNO_OPPOSITE:
+      break;
+    case TNOS_WANTYES_EMPTY:
+      tns->tnsm.myOpt[opt].state = TNOS_YES;
+      break;
+    case TNOS_WANTYES_OPPOSITE:
+      tns->tnsm.myOpt[opt].state = TNOS_WANTYES_EMPTY;
+      break;
+    case TNOS_YES:
+      break;
+    }
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Implementation of option negotiation using the Q-method 
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+HandleCommand(struct telnet_state* tns, unsigned char cmd, unsigned char opt)
+{
+  if (opt < TNSM_MAX_OPTIONS) {
+    /* Handling according to RFC 1143 "Q Method" */
+    switch(cmd) {
+    case TN_WILL: 
+      switch(tns->tnsm.hisOpt[opt].state) {
+      case TNOS_NO:
+	if (tns->tnsm.hisOpt[opt].wants) {
+	  tns->tnsm.hisOpt[opt].state = TNOS_YES;
+	  Reply(tns, TN_DO, opt);
+	}
+	else {
+	  Reply(tns, TN_DONT, opt);
+	}
+	break;
+      case TNOS_WANTNO_EMPTY:
+	tns->tnsm.hisOpt[opt].state = TNOS_NO;
+	break;
+      case TNOS_WANTNO_OPPOSITE:
+	tns->tnsm.hisOpt[opt].state = TNOS_YES;
+	break;
+      case TNOS_WANTYES_EMPTY:
+	tns->tnsm.hisOpt[opt].state = TNOS_YES;
+	break;
+      case TNOS_WANTYES_OPPOSITE:
+	tns->tnsm.hisOpt[opt].state = TNOS_WANTNO_EMPTY;
+	Reply(tns, TN_DONT, opt);
+	break;
+      case TNOS_YES:
+	break;
+      }
+      break;
+      case TN_WONT:
+	switch(tns->tnsm.hisOpt[opt].state) {
+	case TNOS_NO:
+	  break;
+	case TNOS_WANTNO_EMPTY:
+	case TNOS_WANTYES_EMPTY:
+	case TNOS_WANTYES_OPPOSITE:
+	  tns->tnsm.hisOpt[opt].state = TNOS_NO;
+	  break;
+	case TNOS_WANTNO_OPPOSITE:
+	  tns->tnsm.hisOpt[opt].state = TNOS_WANTYES_EMPTY;
+	  Reply(tns, TN_DO, opt);
+	  break;
+	case TNOS_YES:
+	  tns->tnsm.hisOpt[opt].state = TNOS_NO;
+	  Reply(tns, TN_DONT, opt);
+	  break;
+	}
+	break;
+	case TN_DO:
+	  switch(tns->tnsm.myOpt[opt].state) {
+	  case TNOS_NO:
+	    if (tns->tnsm.myOpt[opt].wants) {
+	      tns->tnsm.myOpt[opt].state = TNOS_YES;
+	      Reply(tns, TN_WILL, opt);
+	    }
+	    else {
+	      Reply(tns, TN_WONT, opt);
+	    }
+	    break;
+	  case TNOS_WANTNO_EMPTY:
+	    tns->tnsm.myOpt[opt].state = TNOS_NO;
+	    break;
+	  case TNOS_WANTNO_OPPOSITE:
+	    tns->tnsm.myOpt[opt].state = TNOS_YES;
+	    break;
+	  case TNOS_WANTYES_EMPTY:
+	    tns->tnsm.myOpt[opt].state = TNOS_YES;
+	    break;
+	  case TNOS_WANTYES_OPPOSITE:
+	    tns->tnsm.myOpt[opt].state = TNOS_WANTNO_EMPTY;
+	    Reply(tns, TN_WONT, opt);
+	    break;
+	  case TNOS_YES:
+	    break;
+	  }
+	  break;
+	  case TN_DONT:
+	    switch(tns->tnsm.myOpt[opt].state) {
+	    case TNOS_NO:
+	      break;
+	    case TNOS_WANTNO_EMPTY:
+	    case TNOS_WANTYES_EMPTY:
+	    case TNOS_WANTYES_OPPOSITE:
+	      tns->tnsm.myOpt[opt].state = TNOS_NO;
+	      break;
+	    case TNOS_WANTNO_OPPOSITE:
+	      tns->tnsm.myOpt[opt].state = TNOS_WANTYES_EMPTY;
+	      Reply(tns, TN_WILL, opt);
+	      break;
+	    case TNOS_YES:
+	      tns->tnsm.myOpt[opt].state = TNOS_NO;
+	      Reply(tns, TN_WONT, opt);
+	      break;
+	    }
+	    break;
+    }
+  }
+  else {
+    switch(cmd) {
+    case TN_WILL: 
+      Reply(tns, TN_DONT, opt);
+      break;
+    case TN_WONT:
+      break;
+    case TN_DO:
+      Reply(tns, TN_WONT, opt);
+      break;
+    case TN_DONT:
+      break;
+    }
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Telnet data parsing
+ */
+/*-----------------------------------------------------------------------------------*/
+static unsigned char 
+parse_input(struct telnet_state* tns, unsigned char b)
+{
+  unsigned char ret = 0;
+  switch(tns->tnsm.state) {
+  case TNS_IDLE:
+    if (b == TN_IAC) tns->tnsm.state = TNS_IAC;
+    else ret = 1;
+    break;
+  case TNS_IAC:
+    switch(b) {
+    case TN_SE:
+    case TN_NOP:
+    case TN_DM:
+    case TN_BRK:
+    case TN_IP:
+    case TN_AO:
+    case TN_AYT:
+    case TN_EC:
+    case TN_EL:
+    case TN_GA:
+      tns->tnsm.state = TNS_IDLE;
+      break;
+    case TN_SB:
+      tns->tnsm.state = TNS_SB;
+      break;
+    case TN_WILL:
+    case TN_WONT:
+    case TN_DO:
+    case TN_DONT:
+      tns->tnsm.cmd = b;
+      tns->tnsm.state = TNS_OPT;
+      break;
+    case TN_IAC:
+      tns->tnsm.state = TNS_IDLE;
+      ret = 1;
+      break;
+    default:
+      /* Drop unknown IACs */
+      tns->tnsm.state = TNS_IDLE;
+      break;
+    }
+    break;
+    case TNS_OPT:
+      HandleCommand(tns, tns->tnsm.cmd, b);
+      tns->tnsm.state = TNS_IDLE;
+      break;
+    case TNS_SB:
+      if (b == TN_IAC) {
+	tns->tnsm.state = TNS_SBIAC;
+      }
+      break;
+    case TNS_SBIAC:
+      if (b == TN_IAC) {
+	tns->tnsm.state = TNS_SB;
+      }
+      else if (b == TN_SE) {
+	tns->tnsm.state = TNS_IDLE;
+      }
+      else {
+	tns->tnsm.state = TNS_IDLE;
+      }
+      break;
+  }
+  return ret;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Initialize telnet machine
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+telnet_init(struct telnet_state* tns)
+{
+  int i;
+  for (i = 0; i < TNSM_MAX_OPTIONS; i++) {
+    tns->tnsm.myOpt[i].state = TNOS_NO;
+    tns->tnsm.myOpt[i].wants = 0;
+    tns->tnsm.hisOpt[i].state = TNOS_NO;
+    tns->tnsm.hisOpt[i].wants = 0;
+  }
+  tns->tnsm.state = TNS_IDLE;
+}
+
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Allocate a telnet session structure (including terminal state)
+ */
+/*-----------------------------------------------------------------------------------*/
+static struct telnet_state*
+alloc_state()
+{
+  for (i=0; i < NUM_CONNS; i++) {
+    if (states[i].state == TTS_FREE) {
+      states[i].termstate = ctk_term_alloc_state();
+      if (states[i].termstate != NULL) {
+	for (j = 0; j < TNQLEN; j++) {
+	  states[i].sendq[j] = 0;
+	}
+	telnet_init(&states[i]);
+        states[i].state = TTS_IDLE;
+        return &(states[i]);
+      }
+    }
+  }
+  return NULL;
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Free a telnet session structure (including terminal state)
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+free_state(struct telnet_state* tns)
+{
+  if (tns != NULL) {
+    ctk_term_dealloc_state(tns->termstate);
+    tns->state = TTS_FREE;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * A packet is successfully sent
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+acked(struct telnet_state* tns)
+{
+  /* Were we sending a telnet option packet? */
+  if (tns->state == TTS_SEND_TNDATA) {
+    /* Yes, free it and update queue */
+    if (tns->sendq[0] != 0) {
+      memb_free(&telnetbuf, (char*)(tns->sendq[0]));
+      for (i=1; i < TNQLEN; i++) {
+	tns->sendq[i-1] = tns->sendq[i];
+      }
+      tns->sendq[TNQLEN-1] = 0;
+      /* No options left. Go idle */
+      if (tns->sendq[0] == 0) {
+	tns->state = TTS_IDLE;
+      }
+    }
+  }
+  /* Or were we sending application date ? */
+  else if (tns->state == TTS_SEND_APPDATA) {
+    /* Inform application that data is sent successfully */
+    ctk_term_sent(tns->termstate);
+    tns->state = TTS_IDLE;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Send data on a connections
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+senddata(struct telnet_state* tns)
+{
+  /* Check if there are any option packets to send */
+  if (tns->state == TTS_IDLE || tns->state == TTS_SEND_TNDATA) {
+    if (tns->sendq[0] != 0) {
+      tns->state = TTS_SEND_TNDATA;
+      uip_send(tns->sendq[0],3);
+    }
+  }
+  /* Check if terminal wants to send any data */
+  if (tns->state == TTS_IDLE || tns->state == TTS_SEND_APPDATA) {
+    u16_t len = ctk_term_send(tns->termstate, (unsigned char*)uip_appdata, (unsigned short)uip_mss());
+    if (len > 0) {
+      tns->state = TTS_SEND_APPDATA;
+      uip_send(uip_appdata, len);
+    }
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * uIP callback
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+ctk_termtelnet_appcall(void *state)
+{
+  struct telnet_state *tns;
+
+  tns = (struct telnet_state*)(state);
+
+  if(uip_connected()) {
+    if(tns == NULL) {
+      tns = alloc_state();
+      if(tns == NULL) {
+	uip_close();
+	return;
+      }
+      tcp_markconn(uip_conn, (void *)tns);
+    }
+    /* Try to negotiate some options */
+    EnableHisOpt(tns, TNO_SGA);
+    EnableMyOpt(tns,TNO_SGA);
+    EnableMyOpt(tns,TNO_ECHO);
+    /* Request update of screen */
+    ctk_term_redraw(tns->termstate);
+    senddata(tns);
+  } else if(uip_closed() || uip_aborted()) {
+    free_state(tns);
+    return;
+  }
+
+  if (uip_acked()) {
+    acked(tns);
+  }
+
+  if (uip_newdata()) {
+    for(j = 0; j < uip_datalen(); j++) {
+      if (parse_input(tns, uip_appdata[j])) {
+	/* Pass it uppwards */
+	ctk_term_input(tns->termstate, uip_appdata[j]);
+      }
+    }
+  }
+
+  if(uip_rexmit() ||
+     uip_newdata() ||
+     uip_acked()) {
+    senddata(tns);
+  } else if(uip_poll()) {
+    if (tns->state == TTS_IDLE) {
+      senddata(tns);
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/* 
+ * Init function
+ */
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(ctk_termtelnet_init, arg)
+{
+  arg_free(arg);
+  if(id == EK_ID_NONE) {
+    memb_init(&telnetbuf);
+    for (i=0; i < NUM_CONNS; i++) {
+      states[i].state = TTS_FREE;
+    }
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  if(ev == EK_EVENT_INIT) {
+    tcp_listen(HTONS(PORT));
+  } else if(ev == tcpip_event) {
+    ctk_termtelnet_appcall(data);
+  }
+}
diff --git a/contiki/ctk/ctk-termtelnet.h b/contiki/ctk/ctk-termtelnet.h
new file mode 100644
index 0000000..0c1cd5f
--- /dev/null
+++ b/contiki/ctk/ctk-termtelnet.h
@@ -0,0 +1,6 @@
+#ifndef __CTK_TERMTELNET_H__
+#define __CTK_TERMTELNET_H__
+
+void ctk_termtelnet_init(char *arg);
+
+#endif /* __CTK_TERMTELNET_H__ */
diff --git a/contiki/ctk/ctk-vncarch.h b/contiki/ctk/ctk-vncarch.h
new file mode 100644
index 0000000..6b2a480
--- /dev/null
+++ b/contiki/ctk/ctk-vncarch.h
@@ -0,0 +1,69 @@
+/*
+ * 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. 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-vncarch.h,v 1.4 2004/08/09 20:24:17 adamdunkels Exp $
+ *
+ */
+#ifndef __CTK_VNCARCH_H__
+#define __CTK_VNCARCH_H__
+
+
+typedef char ctk_arch_key_t;
+
+unsigned char ctk_arch_keyavail(void);
+ctk_arch_key_t ctk_arch_getkey(void);
+
+#define CH_ENTER 0x0d
+#define CH_DEL 0x08
+
+#define CH_ESC 0x1b
+
+#define CH_HOME 0x50
+
+#define CH_TAB  0x09
+
+#define CH_CURS_LEFT  0x51
+#define CH_CURS_UP    0x52
+#define CH_CURS_RIGHT 0x53
+#define CH_CURS_DOWN  0x54
+
+
+#define CH_F1 0xbe
+#define CH_F2 0xbf
+#define CH_F3 0xc0
+#define CH_F4 0xc1
+#define CH_F5 0xc2
+#define CH_F6 0xc3
+#define CH_F7 0xc4
+
+
+
+#endif /* __CTK_VNCARCH_H__ */
diff --git a/contiki/ctk/ctk-vncfont.c b/contiki/ctk/ctk-vncfont.c
new file mode 100644
index 0000000..daa4a66
--- /dev/null
+++ b/contiki/ctk/ctk-vncfont.c
@@ -0,0 +1,1205 @@
+/*
+ * Copyright (c) 2003, 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. 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 VNC server
+ *
+ * $Id: ctk-vncfont.c,v 1.5 2004/08/09 20:25:45 adamdunkels Exp $
+ *
+ */
+
+#define _ 0x00
+#define o 0x01 /* 1001 0010 */
+#define X 0x02 /* 1111 0110 */
+
+#ifdef WITH_AVR
+#include <avr/pgmspace.h>
+#else
+#define prog_char const unsigned char
+#endif
+
+prog_char ctk_vncfont[] = {
+/* char 0 */
+X,o,_,_,_,_,
+o,X,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 1 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,X,X,o,_,_,
+_,o,o,X,_,_,
+o,X,X,X,_,_,
+X,o,o,X,_,_,
+o,X,X,X,_,_,
+_,_,_,_,_,_,
+/* char 2 */
+X,_,_,_,_,_,
+X,o,_,_,_,_,
+X,X,X,o,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+X,X,X,o,_,_,
+_,_,_,_,_,_,
+/* char 3 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+o,X,X,o,_,_,
+X,o,o,X,_,_,
+X,_,_,o,_,_,
+X,o,o,X,_,_,
+o,X,X,o,_,_,
+_,_,_,_,_,_,
+/* char 4 */
+_,_,_,X,_,_,
+_,_,o,X,_,_,
+o,X,X,X,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+o,X,X,X,_,_,
+_,_,_,_,_,_,
+/* char 5 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+o,X,X,o,_,_,
+X,o,o,X,_,_,
+X,X,X,X,_,_,
+X,o,o,_,_,_,
+o,X,X,_,_,_,
+_,_,_,_,_,_,
+/* char 6 */
+_,o,X,X,_,_,
+o,X,o,_,_,_,
+X,X,X,_,_,_,
+o,X,o,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,_,_,_,_,_,
+/* char 7 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+o,X,X,X,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+o,X,X,X,_,_,
+_,o,o,X,_,_,
+/* char 8 */
+X,_,_,_,_,_,
+X,o,_,_,_,_,
+X,X,X,o,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+_,_,_,_,_,_,
+/* char 9 */
+_,X,_,_,_,_,
+_,o,_,_,_,_,
+X,X,_,_,_,_,
+o,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,_,_,_,_,_,
+/* char 10 */
+_,_,X,_,_,_,
+_,_,o,_,_,_,
+_,X,X,_,_,_,
+_,o,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,o,X,_,_,_,
+/* char 11 */
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,o,X,_,_,
+X,o,X,o,_,_,
+X,X,o,_,_,_,
+X,o,X,o,_,_,
+X,_,o,X,_,_,
+_,_,_,_,_,_,
+/* char 12 */
+_,X,X,_,_,_,
+_,o,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 13 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,o,X,o,
+X,o,o,X,o,X,
+X,_,_,X,_,X,
+X,_,_,X,_,X,
+X,_,_,X,_,X,
+_,_,_,_,_,_,
+/* char 14 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,o,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+_,_,_,_,_,_,
+/* char 15 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+o,X,X,o,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+o,X,X,o,_,_,
+_,_,_,_,_,_,
+/* char 16 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,o,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+X,X,X,o,_,_,
+X,o,_,_,_,_,
+/* char 17 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+o,X,X,X,_,_,
+X,o,o,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+o,X,X,X,_,_,
+_,_,o,X,_,_,
+/* char 18 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,o,X,X,_,_,
+X,X,o,_,_,_,
+X,o,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 19 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+o,X,X,X,_,_,
+X,o,o,_,_,_,
+o,X,X,o,_,_,
+_,o,o,X,_,_,
+X,X,X,o,_,_,
+_,_,_,_,_,_,
+/* char 20 */
+_,_,X,_,_,_,
+_,o,X,o,_,_,
+_,X,X,X,_,_,
+_,o,X,o,_,_,
+_,_,X,_,_,_,
+_,_,X,o,_,_,
+_,_,o,X,_,_,
+_,_,_,_,_,_,
+/* char 21 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+o,X,X,X,_,_,
+_,_,_,_,_,_,
+/* char 22 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,o,_,o,X,_,
+o,X,o,X,o,_,
+_,X,o,X,_,_,
+_,o,X,o,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 23 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,o,_,_,o,X,
+o,X,o,X,o,X,
+o,X,o,X,o,X,
+_,o,X,o,X,o,
+_,_,X,o,X,_,
+_,_,_,_,_,_,
+/* char 24 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,o,_,o,X,_,
+o,X,o,X,o,_,
+_,o,X,o,_,_,
+o,X,o,X,o,_,
+X,o,_,o,X,_,
+_,_,_,_,_,_,
+/* char 25 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+X,_,_,X,_,_,
+X,o,o,X,_,_,
+o,X,X,X,_,_,
+_,o,o,X,_,_,
+/* char 26 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,X,_,_,
+_,o,X,o,_,_,
+o,X,o,_,_,_,
+X,o,_,_,_,_,
+X,X,X,X,_,_,
+_,_,_,_,_,_,
+/* char 27 */
+_,X,o,_,_,_,
+_,X,_,_,_,_,
+o,X,_,_,_,_,
+X,o,_,_,_,_,
+o,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,o,_,_,_,
+_,o,X,_,_,_,
+/* char 28 */
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+/* char 29 */
+o,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,o,_,_,_,
+_,o,X,_,_,_,
+_,X,o,_,_,_,
+_,X,_,_,_,_,
+o,X,_,_,_,_,
+X,o,_,_,_,_,
+/* char 30 */
+o,X,X,o,X,_,
+X,o,X,X,o,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 31 */
+_,X,X,_,_,_,
+_,X,X,_,_,_,
+_,X,X,_,_,_,
+_,X,X,_,_,_,
+_,X,X,_,_,_,
+_,X,X,_,_,_,
+_,X,X,_,_,_,
+_,X,X,_,_,_,
+/* char 32 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 33 */
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,o,_,_,_,_,
+_,X,_,_,_,_,
+_,_,_,_,_,_,
+/* char 34 */
+X,o,X,_,_,_,
+X,o,X,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 35 */
+X,X,X,X,X,_,
+o,X,o,X,o,_,
+X,X,X,X,X,_,
+o,X,o,X,o,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 36 */
+o,X,X,X,o,_,
+X,o,X,o,X,_,
+X,o,X,o,_,_,
+o,X,X,X,o,_,
+_,o,X,o,X,_,
+X,o,X,o,X,_,
+o,X,X,X,o,_,
+_,o,X,o,_,_,
+/* char 37 */
+o,X,X,X,X,X,
+X,o,o,X,o,o,
+X,o,o,X,o,X,
+o,X,X,o,X,X,
+_,_,o,X,X,o,
+_,o,X,o,X,o,
+o,X,o,_,o,X,
+_,_,_,_,_,_,
+/* char 38 */
+_,X,o,o,X,_,
+_,X,o,X,o,_,
+_,o,X,o,_,_,
+o,X,o,X,o,X,
+X,o,_,o,X,o,
+X,o,o,X,o,X,
+o,X,X,o,_,_,
+_,_,_,_,_,_,
+/* char 39 */
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 40 */
+o,X,o,_,_,_,
+X,o,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,o,_,_,_,_,
+o,X,o,_,_,_,
+_,o,X,_,_,_,
+/* char 41 */
+o,X,o,_,_,_,
+_,o,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,o,X,_,_,_,
+o,X,o,_,_,_,
+X,o,_,_,_,_,
+/* char 42 */
+_,X,o,X,_,_,
+_,o,X,o,_,_,
+X,X,X,X,X,_,
+_,o,X,o,_,_,
+_,X,o,X,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 43 */
+_,_,X,_,_,_,
+_,o,X,o,_,_,
+X,X,X,X,X,_,
+_,o,X,o,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 44 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,X,_,_,_,_,
+o,X,_,_,_,_,
+/* char 45 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,X,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 46 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 47 */
+_,_,o,X,_,_,
+_,_,X,o,_,_,
+_,o,X,_,_,_,
+_,X,o,_,_,_,
+o,X,_,_,_,_,
+X,o,_,_,_,_,
+X,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 48 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 49 */
+_,o,X,_,_,_,
+_,X,X,_,_,_,
+_,o,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 50 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+_,_,_,o,X,_,
+_,_,o,X,o,_,
+_,o,X,o,_,_,
+o,X,o,_,_,_,
+X,X,X,X,X,_,
+_,_,_,_,_,_,
+/* char 51 */
+X,X,X,X,X,_,
+_,_,o,X,o,_,
+_,o,X,o,_,_,
+_,X,X,X,o,_,
+_,_,_,o,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 52 */
+_,_,o,X,_,_,
+_,o,X,X,_,_,
+o,X,o,X,_,_,
+X,o,o,X,o,_,
+X,X,X,X,X,_,
+_,_,o,X,o,_,
+_,_,_,X,_,_,
+_,_,_,_,_,_,
+/* char 53 */
+X,X,X,X,X,_,
+X,o,o,o,_,_,
+X,X,X,X,o,_,
+_,_,_,o,X,_,
+_,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 54 */
+_,o,X,X,_,_,
+o,X,o,_,_,_,
+X,o,_,_,_,_,
+X,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 55 */
+X,X,X,X,X,_,
+_,_,_,o,X,_,
+_,_,_,X,o,_,
+_,_,o,X,_,_,
+_,_,X,o,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 56 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 57 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+o,X,X,X,X,_,
+_,_,_,o,X,_,
+_,_,o,X,o,_,
+_,X,X,o,_,_,
+_,_,_,_,_,_,
+/* char 58 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 59 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,X,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,X,_,_,_,_,
+o,X,_,_,_,_,
+/* char 60 */
+_,_,_,_,_,_,
+_,o,X,_,_,_,
+o,X,o,_,_,_,
+X,o,_,_,_,_,
+o,X,o,_,_,_,
+_,o,X,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 61 */
+_,_,_,_,_,_,
+X,X,X,X,X,_,
+o,o,o,o,o,_,
+X,X,X,X,X,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 62 */
+_,_,_,_,_,_,
+X,o,_,_,_,_,
+o,X,o,_,_,_,
+_,o,X,_,_,_,
+o,X,o,_,_,_,
+X,o,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 63 */
+o,X,X,o,_,_,
+X,o,o,X,_,_,
+_,_,o,X,_,_,
+_,o,X,o,_,_,
+_,X,o,_,_,_,
+_,o,_,_,_,_,
+_,X,_,_,_,_,
+_,_,_,_,_,_,
+/* char 64 */
+_,o,X,X,X,o,
+o,X,o,o,o,X,
+X,o,o,X,X,o,
+X,o,X,o,X,_,
+X,o,X,o,X,o,
+X,o,o,X,X,X,
+o,X,o,o,o,_,
+_,o,X,X,X,_,
+/* char 65 */
+_,_,X,_,_,_,
+_,o,X,o,_,_,
+_,X,o,X,_,_,
+o,X,o,X,o,_,
+X,X,X,X,X,_,
+X,o,_,o,X,_,
+X,_,_,_,X,_,
+_,_,_,_,_,_,
+/* char 66 */
+X,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+X,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+X,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 67 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 68 */
+X,X,X,o,_,_,
+X,o,o,X,o,_,
+X,_,_,o,X,_,
+X,_,_,_,X,_,
+X,_,_,o,X,_,
+X,o,o,X,o,_,
+X,X,X,o,_,_,
+_,_,_,_,_,_,
+/* char 69 */
+X,X,X,X,_,_,
+X,o,_,_,_,_,
+X,o,_,_,_,_,
+X,X,X,_,_,_,
+X,o,_,_,_,_,
+X,o,_,_,_,_,
+X,X,X,X,_,_,
+_,_,_,_,_,_,
+/* char 70 */
+X,X,X,X,_,_,
+X,o,_,_,_,_,
+X,o,_,_,_,_,
+X,X,X,_,_,_,
+X,o,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 71 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,_,_,_,o,_,
+X,_,_,X,X,_,
+X,_,_,o,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 72 */
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+X,X,X,X,X,_,
+X,o,_,o,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+_,_,_,_,_,_,
+/* char 73 */
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 74 */
+_,_,_,_,X,_,
+_,_,_,_,X,_,
+_,_,_,_,X,_,
+_,_,_,_,X,_,
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 75 */
+X,_,_,o,X,_,
+X,_,o,X,o,_,
+X,o,X,o,_,_,
+X,X,o,_,_,_,
+X,o,X,o,_,_,
+X,_,o,X,o,_,
+X,_,_,o,X,_,
+_,_,_,_,_,_,
+/* char 76 */
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,o,_,_,_,_,
+X,X,X,X,_,_,
+_,_,_,_,_,_,
+/* char 77 */
+X,o,_,_,o,X,
+X,X,o,_,o,X,
+X,o,X,o,X,X,
+X,_,o,X,o,X,
+X,_,_,_,_,X,
+X,_,_,_,_,X,
+X,_,_,_,_,X,
+_,_,_,_,_,_,
+/* char 78 */
+X,X,_,_,X,_,
+X,X,o,_,X,_,
+X,o,X,o,X,_,
+X,o,X,o,X,_,
+X,_,o,X,X,_,
+X,_,_,X,X,_,
+X,_,_,o,X,_,
+_,_,_,_,_,_,
+/* char 79 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 80 */
+X,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+X,X,X,X,o,_,
+X,o,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 81 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,o,X,o,X,_,
+o,X,X,X,o,_,
+_,_,o,X,_,_,
+/* char 82 */
+X,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,o,X,_,
+X,X,X,X,o,_,
+X,o,X,o,_,_,
+X,_,o,X,o,_,
+X,_,_,o,X,_,
+_,_,_,_,_,_,
+/* char 83 */
+o,X,X,X,o,_,
+X,o,_,o,X,_,
+X,o,_,_,_,_,
+o,X,X,X,o,_,
+_,_,_,o,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 84 */
+X,X,X,X,X,_,
+_,o,X,o,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 85 */
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,X,X,o,_,
+_,_,_,_,_,_,
+/* char 86 */
+X,_,_,_,X,_,
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,o,X,o,_,
+_,X,o,X,_,_,
+_,o,X,o,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 87 */
+X,_,_,_,_,X,
+X,o,_,_,_,X,
+o,X,o,X,o,X,
+o,X,o,X,o,X,
+_,o,X,o,X,o,
+_,_,X,o,X,_,
+_,_,X,o,X,_,
+_,_,_,_,_,_,
+/* char 88 */
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,o,X,o,_,
+_,o,X,o,_,_,
+o,X,o,X,o,_,
+X,o,_,o,X,_,
+X,_,_,_,X,_,
+_,_,_,_,_,_,
+/* char 89 */
+X,_,_,_,X,_,
+X,o,_,o,X,_,
+o,X,o,X,o,_,
+_,o,X,o,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,_,_,_,_,
+/* char 90 */
+X,X,X,X,_,_,
+_,_,o,X,_,_,
+_,o,X,o,_,_,
+o,X,o,_,_,_,
+X,o,_,_,_,_,
+X,o,_,_,_,_,
+X,X,X,X,_,_,
+_,_,_,_,_,_,
+/* char 91 */
+X,o,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,o,_,_,_,_,
+X,X,_,_,_,_,
+/* char 92 */
+X,o,_,_,_,_,
+o,X,_,_,_,_,
+_,X,o,_,_,_,
+_,o,X,_,_,_,
+_,_,X,o,_,_,
+_,_,o,X,_,_,
+_,_,_,X,_,_,
+_,_,_,_,_,_,
+/* char 93 */
+o,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+_,X,_,_,_,_,
+o,X,_,_,_,_,
+X,X,_,_,_,_,
+/* char 94 */
+o,X,o,_,_,_,
+X,o,X,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* char 95 */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,X,X,X,
+_,_,_,_,_,_,
+
+
+
+
+  
+/* Char 0x60 '`' */
+X,3,3,3,3,3,
+X,4,4,4,4,4,
+X,3,3,3,3,3,
+X,4,4,4,4,4,
+X,3,3,3,3,3,
+X,4,4,4,4,4,
+X,3,3,3,3,3,
+X,5,5,5,5,5,
+/* Char 0x61 'a' */
+3,3,3,3,3,3,
+4,4,4,4,4,4,
+3,3,3,3,3,3,
+4,4,4,4,4,4,
+3,3,3,3,3,3,
+4,4,4,4,4,4,
+3,3,3,3,3,3,
+5,5,5,5,5,5,
+/* Char 0x62 'b' */
+3,3,3,3,3,X,
+4,4,4,4,4,X,
+3,3,3,3,3,X,
+4,4,4,4,4,X,
+3,3,3,3,3,X,
+4,4,4,4,4,X,
+3,3,3,3,3,X,
+5,5,5,5,5,X,
+/* Char 0x63 'c' */
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+/* Char 0x64 'd' */
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+_,_,_,_,5,X,
+5,5,5,5,5,X,
+X,X,X,X,X,X,
+/* Char 0x65 'e' */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+5,5,5,5,5,5,
+X,X,X,X,X,X,
+/* Char 0x66 'f' */
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,5,5,5,5,5,
+X,X,X,X,X,X,
+/* Char 0x67 'g' */
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+/* Char 0x68 'h' */
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+_,_,X,_,_,_,
+/* Char 0x69 'i' */
+X,X,X,X,X,X,
+_,_,_,_,_,_,
+X,X,X,X,X,X,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x6a 'j' */
+X,X,X,X,X,X,
+_,_,_,_,_,X,
+X,X,X,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+/* Char 0x6b 'k' */
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+/* Char 0x6c 'l' */
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+_,_,_,X,_,X,
+X,X,X,X,_,X,
+_,_,_,_,_,X,
+X,X,X,X,X,X,
+/* Char 0x6d 'm' */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,X,X,X,
+_,_,_,_,_,_,
+X,X,X,X,X,X,
+/* Char 0x6e 'n' */
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,X,X,X,
+X,_,_,_,_,_,
+X,X,X,X,X,X,
+/* Char 0x6f 'o' */
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+/* Char 0x70 'p' */
+5,5,5,5,5,5,
+5,6,6,6,6,_,
+5,6,_,_,_,_,
+5,6,_,_,_,_,
+5,6,_,_,_,_,
+5,6,_,_,_,_,
+5,6,_,_,_,_,
+5,_,_,_,_,_,
+/* Char 0x71 'q' */
+_,_,_,_,_,4,
+_,_,_,_,3,4,
+_,_,_,_,3,4,
+_,_,_,_,3,4,
+_,_,_,_,3,4,
+_,_,_,_,3,4,
+_,3,3,3,3,4,
+4,4,4,4,4,4,
+/* Char 0x72 'r' */
+X,X,X,X,X,X,
+X,_,_,_,_,_,
+X,_,X,X,X,X,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+X,_,X,_,_,_,
+/* Char 0x73 's' */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,X,X,X,
+X,X,X,X,X,X,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x74 't' */
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+X,_,_,_,_,_,
+/* Char 0x75 'u' */
+X,X,_,_,_,_,
+X,X,_,_,_,_,
+X,X,_,_,_,_,
+X,X,_,_,_,_,
+X,X,_,_,_,_,
+X,X,_,_,_,_,
+X,X,_,_,_,_,
+X,X,_,_,_,_,
+/* Char 0x76 'v' */
+_,_,_,_,X,X,
+_,_,_,_,X,X,
+_,_,_,_,X,X,
+_,_,_,_,X,X,
+_,_,_,_,X,X,
+_,_,_,_,X,X,
+_,_,_,_,X,X,
+_,_,_,_,X,X,
+/* Char 0x77 'w' */
+X,X,X,X,X,X,
+X,X,X,X,X,X,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x78 'x' */
+X,X,X,X,X,X,
+X,X,X,X,X,X,
+X,X,X,X,X,X,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x79 'y' */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,X,X,X,
+X,X,X,X,X,X,
+X,X,X,X,X,X,
+/* Char 0x7a 'z' */
+_,_,_,_,_,_,
+_,_,_,_,o,X,
+_,_,_,o,X,X,
+X,X,o,X,X,o,
+X,X,X,X,o,_,
+X,X,X,o,_,_,
+X,X,o,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x7b '{' */
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+/* Char 0x7c '|' */
+_,_,_,X,X,X,
+_,_,_,X,X,X,
+_,_,_,X,X,X,
+_,_,_,X,X,X,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x7d '}' */
+_,_,X,X,_,_,
+_,_,X,X,_,_,
+_,o,X,X,_,_,
+X,X,X,X,_,_,
+X,X,X,X,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x7e '~' */
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+_,_,_,_,_,_,
+/* Char 0x7f '?' */
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+X,X,X,_,_,_,
+_,_,_,X,X,X,
+_,_,_,X,X,X,
+_,_,_,X,X,X,
+_,_,_,X,X,X,
+
+};
diff --git a/contiki/ctk/ctk-vncfont.h b/contiki/ctk/ctk-vncfont.h
new file mode 100644
index 0000000..e39127f
--- /dev/null
+++ b/contiki/ctk/ctk-vncfont.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003, 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. 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 VNC server
+ *
+ * $Id: ctk-vncfont.h,v 1.4 2004/08/09 20:26:06 adamdunkels Exp $
+ *
+ */
+#ifndef __CTK_VNCFONT_H__
+#define __CTK_VNCFONT_H__
+
+#define CTK_VNCFONT_WIDTH 6
+#define CTK_VNCFONT_HEIGHT 8
+
+
+extern unsigned char ctk_vncfont[CTK_VNCFONT_WIDTH *
+				 CTK_VNCFONT_HEIGHT *
+				 128];
+
+#endif /* __CTK_VNCFONT_H__ */
diff --git a/contiki/ctk/ctk-vncserver.c b/contiki/ctk/ctk-vncserver.c
new file mode 100644
index 0000000..74ba31f
--- /dev/null
+++ b/contiki/ctk/ctk-vncserver.c
@@ -0,0 +1,1112 @@
+/**
+ * \file
+ * The ctk-draw implementation for the CTK VNC server.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/**
+ * \defgroup CTKVNCServer The CTK VNC server
+ * @{
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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-vncserver.c,v 1.17 2006/05/28 20:38:19 oliverschmidt Exp $
+ *
+ */
+
+#include "ctk.h"
+#include "ctk-draw.h"
+
+#include "contiki.h"
+
+#include "ek.h"
+#include "loader.h"
+#include "vnc-server.h"
+#include "vnc-out.h"
+
+#include "ctk-vncfont.h"
+#include "ctk-vncserver.h"
+#include "ctk-vncserver-conf.h"
+
+static unsigned char sizex, sizey;
+
+#define CH_ULCORNER 0x00
+#define CH_TITLEBAR 0x01
+#define CH_URCORNER 0x02
+#define CH_WINDOWRBORDER 0x03
+#define CH_LRCORNER 0x04
+#define CH_WINDOWLOWERBORDER 0x05
+#define CH_LLCORNER 0x06
+#define CH_WINDOWLBORDER 0x07
+
+#define CH_DIALOG_ULCORNER 0x12
+#define CH_DIALOGUPPERBORDER 0x09
+#define CH_DIALOG_URCORNER 0x0a
+#define CH_DIALOGRBORDER 0x0b
+#define CH_DIALOG_LRCORNER 0x0c
+#define CH_DIALOGLOWERBORDER 0x0d
+#define CH_DIALOG_LLCORNER 0x0e
+#define CH_DIALOGLBORDER 0x0f
+
+#define CH_BUTTONLEFT  0x10
+#define CH_BUTTONRIGHT 0x11
+
+#define CH_SEPARATOR   0x13
+
+#include "libconio.h"
+
+#define SCREENCOLOR         0
+#define BORDERCOLOR         1
+
+#define WIDGETCOLOR         2
+#define WIDGETCOLOR_FWIN    3
+#define WIDGETCOLOR_FOCUS   4
+#define WIDGETCOLOR_DIALOG  5
+#define WIDGETCOLOR_HLINK   6
+#define WIDGETCOLOR_HLINK_FOCUS   7
+
+#define WINDOWCOLOR         8
+#define WINDOWCOLOR_FOCUS   9
+
+#define WINDOWBORDER        10
+#define WINDOWBORDER_FOCUS  11
+
+#define DIALOGCOLOR         12
+
+#define OPENMENUCOLOR       13
+
+#define ACTIVEMENUITEMCOLOR 14
+
+#define MENUCOLOR           15
+
+/*static DISPATCHER_UIPCALL(ctk_vncserver_appcall, state);
+
+static struct dispatcher_proc p =
+  {DISPATCHER_PROC("CTK VNC server", NULL, NULL,
+		   ctk_vncserver_appcall)};
+		   static ek_id_t id;*/
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(p, "CTK VNC server", EK_PRIO_NORMAL,
+	   eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+static struct vnc_server_state conns[CTK_VNCSERVER_CONF_NUMCONNS];
+
+#define PRINTF(x) 
+
+#define revers(x)
+
+unsigned char ctk_draw_windowborder_height = 1;
+unsigned char ctk_draw_windowborder_width = 1;
+unsigned char ctk_draw_windowtitle_height = 1;
+
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Add an update request from a client to the list of pending updates
+ * for the connection.
+ *
+ * This function is called from the vnc-out module.
+ *
+ * \param vs The VNC connection state.
+ * \param a The area that is requested to be updated.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_server_update_add(struct vnc_server_state *vs,
+		      struct vnc_server_update *a)
+{
+  /* XXX: test both head and tail placement!*/
+  a->next = vs->updates_pending;
+  vs->updates_pending = a;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Allocate an update request from the VNC connection state.
+ *
+ * This function is called from the vnc-out module.
+ *
+ * \param vs The VNC connection state.
+ *
+ * \return Memory for an update structure, or NULL if no update could
+ * be allocated.
+ */
+/*-----------------------------------------------------------------------------------*/
+struct vnc_server_update *
+vnc_server_update_alloc(struct vnc_server_state *vs)
+{
+  struct vnc_server_update *a;
+
+  a = vs->updates_free;
+  if(a == NULL) {
+    return NULL;
+  }
+  vs->updates_free = a->next;
+  a->next = NULL;
+  return a;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Deallocate an update request from the VNC connection state.
+ *
+ * This function is called from the vnc-out module.
+ *
+ * \param vs The VNC connection state.
+ *
+ * \param a The update structure to be deallocated.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_server_update_free(struct vnc_server_state *vs,
+		       struct vnc_server_update *a)
+{
+  a->next = vs->updates_free;
+  vs->updates_free = a;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Dequeue the first update on the queue of updates.
+ *
+ * This function is called from the vnc-out module.
+ *
+ * \param vs The VNC connection state.
+ *
+ * \return The first update on the queue, or NULL if the queue is empty.
+ */
+/*-----------------------------------------------------------------------------------*/
+struct vnc_server_update *
+vnc_server_update_dequeue(struct vnc_server_state *vs)
+{
+  struct vnc_server_update *a;
+
+  a = vs->updates_pending;
+  if(a == NULL) {
+    return a;
+  }
+  vs->updates_pending = a->next;
+  a->next = NULL;
+  return a;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Remove a specific update on the queue of updates.
+ *
+ * \param vs The VNC connection state.
+ * \param a The update to be removed.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_server_update_remove(struct vnc_server_state *vs,
+			 struct vnc_server_update *a)
+{
+  struct vnc_server_update *b, *c;
+
+  if(a == vs->updates_pending) {
+    vs->updates_pending = a->next;
+  } else {
+    b = vs->updates_pending;
+    for(c = vs->updates_pending; c != a; b = c, c = c->next);
+
+    b->next = a->next;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Flag an area to be updated for all open VNC server connections.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+update_area(u8_t x, u8_t y, u8_t w, u8_t h)
+{
+  u8_t i;
+  
+  if(h == 0 || w == 0) {
+    return;
+  }
+  
+  /* Update for all active VNC connections. */
+  for(i = 0; i < CTK_VNCSERVER_CONF_NUMCONNS; ++i) {
+    if(conns[i].state != VNC_DEALLOCATED) {
+      vnc_out_update_area(&conns[i],
+			  x, y, w, h);
+    }
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Allocate a VNC server connection state from the array of available
+ * VNC connection states.
+ */
+/*-----------------------------------------------------------------------------------*/
+static struct vnc_server_state *
+alloc_state(void)
+{
+  u8_t i;
+  for(i = 0; i < CTK_VNCSERVER_CONF_NUMCONNS; ++i) {
+    if(conns[i].state == VNC_DEALLOCATED) {
+      return &conns[i];
+    }
+  }
+
+  /* We are overloaded! XXX: we'll just kick all other connections! */
+  for(i = 0; i < CTK_VNCSERVER_CONF_NUMCONNS; ++i) {
+    conns[i].state = VNC_DEALLOCATED;
+  }
+  
+  return NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Deallocate a VNC connection state.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+dealloc_state(struct vnc_server_state *s)
+{
+  s->state = VNC_DEALLOCATED;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+cputsn(char *str, unsigned char len)
+{
+  char c;
+
+  while(len > 0) {
+    --len;
+    c = *str;
+    if(c == 0) {
+      break;
+    }
+    cputc(c);
+    ++str;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Initialize the VNC ctk-draw module. Called by the CTK module.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_init(void)
+{
+  bgcolor(SCREENCOLOR);
+  bordercolor(BORDERCOLOR);
+  screensize(&sizex, &sizey);
+  ctk_draw_clear(0, sizey);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_widget(struct ctk_widget *w,
+	    unsigned char x, unsigned char y,
+	    unsigned char clipx,
+	    unsigned char clipy,
+	    unsigned char clipy1, unsigned char clipy2,
+	    unsigned char focus)
+{
+  unsigned char xpos, ypos, xscroll;
+  unsigned char i, j;
+  unsigned char iconnum;
+  char c, *text;
+  unsigned char len;
+
+  /*
+  if(focus & CTK_FOCUS_WINDOW) {    
+    textcolor(WIDGETCOLOR_FWIN);
+    if(focus & CTK_FOCUS_WIDGET) {
+      textcolor(WIDGETCOLOR_FOCUS);
+    }
+  } else if(focus & CTK_FOCUS_DIALOG) {
+    textcolor(WIDGETCOLOR_DIALOG);
+    if(focus & CTK_FOCUS_WIDGET) {
+      textcolor(WIDGETCOLOR_FOCUS);
+    }
+  } else {
+    textcolor(WIDGETCOLOR);
+  }
+*/  
+  xpos = x + w->x;
+  ypos = y + w->y;
+    
+  switch(w->type) {
+  case CTK_WIDGET_SEPARATOR:
+    textcolor(VNC_OUT_SEPARATORCOLOR + focus);
+    if(ypos >= clipy1 && ypos < clipy2) {
+      /*      chlinexy(xpos, ypos, w->w);*/
+      gotoxy(xpos, ypos);
+      for(i = 0; i < w->w; ++i) {
+	cputc(CH_SEPARATOR);
+      }
+    }
+    break;
+  case CTK_WIDGET_LABEL:
+    textcolor(VNC_OUT_LABELCOLOR + focus);
+    text = w->widget.label.text;
+    for(i = 0; i < w->h; ++i) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	gotoxy(xpos, ypos);
+	cputsn(text, w->w);
+	if(w->w - (wherex() - xpos) > 0) {
+	  cclear(w->w - (wherex() - xpos));
+	}
+      }
+      ++ypos;
+      text += w->w;
+    }
+    break;
+  case CTK_WIDGET_BUTTON:
+    textcolor(VNC_OUT_BUTTONCOLOR + focus);
+    if(ypos >= clipy1 && ypos < clipy2) {
+      if(focus & CTK_FOCUS_WIDGET) {
+	revers(1);
+      } else {
+	revers(0);
+      }
+      cputcxy(xpos, ypos, CH_BUTTONLEFT);
+      cputsn(w->widget.button.text, w->w);
+      cputc(CH_BUTTONRIGHT);
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_HYPERLINK:
+    textcolor(VNC_OUT_HYPERLINKCOLOR + focus);
+    if(ypos >= clipy1 && ypos < clipy2) {
+      /*      if(focus & CTK_FOCUS_WIDGET) {
+	textcolor(WIDGETCOLOR_HLINK_FOCUS);
+	revers(0);	
+      } else {
+	textcolor(WIDGETCOLOR_HLINK);
+	revers(1);
+	}*/
+      gotoxy(xpos, ypos);
+      cputsn(w->widget.button.text, w->w);
+      revers(0);
+    }
+    break;
+  case CTK_WIDGET_TEXTENTRY:
+    textcolor(VNC_OUT_TEXTENTRYCOLOR + focus);
+    text = w->widget.textentry.text;
+    xscroll = 0;
+    if(w->widget.textentry.xpos >= w->w - 1) {
+      xscroll = w->widget.textentry.xpos - w->w + 1;
+    }
+    for(j = 0; j < w->h; ++j) {
+      if(ypos >= clipy1 && ypos < clipy2) {
+	if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
+	   w->widget.textentry.ypos == j) {
+	  revers(0);
+	  cputcxy(xpos, ypos, '>');
+	  c = 1;
+	  for(i = 0; i < w->w; ++i) {
+	    if(c != 0) {
+	      c = text[i + xscroll];
+	    }
+	    if(i == w->widget.textentry.xpos - xscroll) {
+	      textcolor(VNC_OUT_TEXTENTRYCOLOR + (focus ^ 0x01));
+	      revers(1);
+	    } else {
+	      revers(0);
+	    }
+	    if(c == 0) {
+	      cputc(' ');
+	    } else {
+	      cputc(c);
+	    }
+	    revers(0);
+	    textcolor(VNC_OUT_TEXTENTRYCOLOR + focus);
+	  }
+	  cputc('<');
+	} else {
+	  if(focus & CTK_FOCUS_WIDGET && j == w->widget.textentry.ypos) {
+	    revers(1);
+	  } else {
+	    revers(0);
+	  }
+	  cvlinexy(xpos, ypos, 1);
+	  gotoxy(xpos + 1, ypos);          
+	  cputsn(text, w->w);
+	  i = wherex();
+	  if(i - xpos - 1 < w->w) {
+	    cclear(w->w - (i - xpos) + 1);
+	  }
+	  cvline(1);
+	}
+      }
+      ++ypos;
+      text += w->widget.textentry.len + 1;
+    }
+    revers(0);
+    break;
+#if CTK_CONF_ICONS
+  case CTK_WIDGET_ICON:
+    if(ypos >= clipy1 && ypos < clipy2) {
+      textcolor(VNC_OUT_ICONCOLOR + focus);
+      if(focus & 1) {
+	revers(1);
+      } else {
+	revers(0);
+      }
+
+      x = xpos;
+      len = strlen(w->widget.icon.title);
+      if(x + len >= sizex) {
+	x = sizex - len;
+      }
+
+      gotoxy(x, ypos + 3);
+      if(ypos >= clipy1 && ypos < clipy2) {
+	cputs(w->widget.icon.title);
+      }
+
+#if CTK_CONF_ICON_BITMAPS
+      if(w->widget.icon.bitmap != NULL) {
+	iconnum = vnc_out_add_icon((struct ctk_icon *)w);
+	textcolor(iconnum | (focus << 6));
+	gotoxy(xpos, ypos);
+	cputc(0x80);
+	cputc(0x81);
+	cputc(0x82);
+	cputc(0x83);
+	++ypos;
+	gotoxy(xpos, ypos);
+	cputc(0x90);
+	cputc(0x91);
+	cputc(0x92);
+	cputc(0x93);
+	++ypos;
+	gotoxy(xpos, ypos);
+	cputc(0xa0);
+	cputc(0xa1);
+	cputc(0xa2);
+	cputc(0xa3);
+	++ypos;
+	textcolor(0);
+	/*	for(i = 0; i < 3; ++i) {
+
+	  if(ypos >= clipy1 && ypos < clipy2) {
+	    cputc(w->widget.icon.textmap[0 + 3 * i]);
+	    cputc(w->widget.icon.textmap[1 + 3 * i]);
+	    cputc(w->widget.icon.textmap[2 + 3 * i]);
+	  }
+	  ++ypos;
+	  }*/
+      }
+#endif /* CTK_CONF_ICON_BITMAPS */
+
+      revers(0);
+    }
+    break;
+#endif /* CTK_CONF_ICONS */
+
+  default:
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw a widget on the VNC screen. Called by the CTK module.
+ *
+ * \param w The widget to be drawn.
+ * \param focus The focus of the widget.
+ * \param clipy1 The lower y coordinate bound.
+ * \param clipy2 The upper y coordinate bound.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_widget(struct ctk_widget *w,
+		unsigned char focus,
+		unsigned char clipy1,
+		unsigned char clipy2)
+{
+  struct ctk_window *win = w->window;
+  struct ctk_icon *icon;
+  unsigned char posx, posy, x, len;
+
+  posx = win->x + 1;
+  posy = win->y + 2;
+
+  if(w == win->focused) {
+    focus |= CTK_FOCUS_WIDGET;
+  }
+  
+  draw_widget(w, posx, posy,
+	      posx + win->w,
+	      posy + win->h,
+	      clipy1, clipy2,
+	      focus);
+
+  if(w->type != CTK_WIDGET_ICON) {
+    update_area(posx + w->x,
+		posy + w->y, w->w + 2, w->h);
+  } else {
+    icon = (struct ctk_icon *)w;
+
+    len = strlen(icon->title);
+    x = posx + w->x;
+    if(x + len >= sizex) {
+      x = sizex - len;
+    }
+
+    update_area(x, posy + w->y, len > 4? len: 4, w->h);    
+  }
+  
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Clear a window on the VNC screen. Called by the CTK module.
+ *
+ * \param window The window to be cleared.
+ * \param focus The focus of the window.
+ * \param clipy1 The lower y coordinate bound.
+ * \param clipy2 The upper y coordinate bound.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear_window(struct ctk_window *window,
+		      unsigned char focus,
+		      unsigned char clipy1,
+		      unsigned char clipy2)
+{
+  unsigned char i;
+  unsigned char h;
+  /*
+  if(focus & CTK_FOCUS_WINDOW){
+    textcolor(WINDOWCOLOR_FOCUS);
+  } else {
+    textcolor(WINDOWCOLOR);
+    }*/
+  textcolor(VNC_OUT_WINDOWCOLOR + focus);
+  
+  h = window->y + 2 + window->h;
+  /* Clear window contents. */
+  for(i = window->y + 2; i < h; ++i) {
+    if(i >= clipy1 && i < clipy2) {
+      cclearxy(window->x + 1, i, window->w);
+    }
+  }
+
+  update_area(window->x + 1, window->y + 2, window->w, window->h);
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_window_contents(struct ctk_window *window, unsigned char focus,
+		     unsigned char clipy1, unsigned char clipy2,
+		     unsigned char x1, unsigned char x2,
+		     unsigned char y1, unsigned char y2)
+{
+  struct ctk_widget *w;
+  unsigned char wfocus;
+  
+  /* Draw inactive widgets. */
+  for(w = window->inactive; w != NULL; w = w->next) {
+    draw_widget(w, x1, y1, x2, y2,
+		clipy1, clipy2,
+		focus);
+  }
+  
+  /* Draw active widgets. */
+  for(w = window->active; w != NULL; w = w->next) {  
+    wfocus = focus;
+    if(w == window->focused) {
+      wfocus |= CTK_FOCUS_WIDGET;
+    }
+
+   draw_widget(w, x1, y1, x2, y2, 
+	       clipy1, clipy2,
+	       wfocus);
+  }
+
+#ifdef CTK_CONIO_CONF_UPDATE
+  CTK_CONIO_CONF_UPDATE();
+#endif /* CTK_CONIO_CONF_UPDATE */
+
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw a window on the VNC screen. Called by the CTK module.
+ *
+ * \param window The window to be drawn.
+ * \param focus The focus of the window.
+ * \param clipy1 The lower y coordinate bound.
+ * \param clipy2 The upper y coordinate bound.
+ * \param draw_borders The flag for border drawing.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_window(struct ctk_window *window, unsigned char focus,
+		unsigned char clipy1, unsigned char clipy2,
+		unsigned char draw_borders)
+{
+  unsigned char x, y;
+  unsigned char h;
+  unsigned char x1, y1, x2, y2;
+  unsigned char i;
+  
+
+  if(window->y + 1 >= clipy2) {
+    return;
+  }
+    
+  x = window->x;
+  y = window->y + 1;
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + window->w;
+  y2 = y1 + window->h;
+
+  if(draw_borders) {
+
+    /* Draw window frame. */  
+    textcolor(VNC_OUT_WINDOWCOLOR + focus);
+    /*  if(focus & CTK_FOCUS_WINDOW) {
+      textcolor(WINDOWCOLOR_FOCUS);
+    } else {
+      textcolor(WINDOWCOLOR);
+      }*/
+
+    if(y >= clipy1) {
+      cputcxy(x, y, CH_ULCORNER);
+      for(i = wherex() + window->titlelen + CTK_CONF_WINDOWMOVE * 2; i < x2; ++i) {
+	cputcxy(i, y, CH_TITLEBAR);
+      }
+      cputcxy(x2, y, CH_URCORNER);
+    }
+
+    h = window->h;
+  
+    if(clipy1 > y1) {
+      if(clipy1 - y1 < h) {
+	h = clipy1 - y1;
+	      y1 = clipy1;
+      } else {
+	h = 0;
+      }
+    }
+
+    if(clipy2 < y1 + h) {
+      if(y1 >= clipy2) {
+	h = 0;
+      } else {
+	h = clipy2 - y1;
+      }
+    }
+  
+    for(i = y1; i < y1 + h; ++i) {
+      cputcxy(x, i, CH_WINDOWLBORDER);
+      cputcxy(x2, i, CH_WINDOWRBORDER);
+    }
+
+    /*  cvlinexy(x, y1, h);
+	cvlinexy(x2, y1, h);  */
+
+    if(y + window->h >= clipy1 &&
+       y + window->h < clipy2) {
+      cputcxy(x, y2, CH_LLCORNER);
+      for(i = x1; i < x2; ++i) {
+	cputcxy(i, y2, CH_WINDOWLOWERBORDER);
+      }
+      /*    chlinexy(x1, y2, window->w);*/
+      cputcxy(x2, y2, CH_LRCORNER);
+    }
+  }
+
+  draw_window_contents(window, focus, clipy1, clipy2,
+		       x1, x2, y + 1, y2);
+
+  update_area(window->x, window->y, window->w + 2, window->h + 2);
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw a dialog on the VNC screen. Called by the CTK module.
+ *
+ * \param dialog The dialog to be drawn.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_dialog(struct ctk_window *dialog)
+{
+  unsigned char x, y;
+  unsigned char i;
+  unsigned char x1, y1, x2, y2;
+
+  /*  textcolor(DIALOGCOLOR);*/
+  textcolor(VNC_OUT_WINDOWCOLOR + CTK_FOCUS_DIALOG);
+
+  x = dialog->x;
+  y = dialog->y + 1;
+
+
+  x1 = x + 1;
+  y1 = y + 1;
+  x2 = x1 + dialog->w;
+  y2 = y1 + dialog->h;
+
+
+  /* Draw dialog frame. */
+  
+  for(i = y1; i < y1 + dialog->h; ++i) {
+    cputcxy(x, i, CH_DIALOGLBORDER);
+    cputcxy(x2, i, CH_DIALOGRBORDER);
+  }
+  /*  cvlinexy(x, y1,
+	   dialog->h);
+  cvlinexy(x2, y1,
+  dialog->h);*/
+
+  
+  for(i = x1; i < x2; ++i) {
+    cputcxy(i, y, CH_DIALOGUPPERBORDER);
+    cputcxy(i, y2, CH_DIALOGLOWERBORDER);
+  }
+    /*  chlinexy(x1, y,
+	   dialog->w);
+  chlinexy(x1, y2,
+  dialog->w);*/
+
+  cputcxy(x, y, CH_DIALOG_ULCORNER);
+  cputcxy(x, y2, CH_DIALOG_LLCORNER);
+  cputcxy(x2, y, CH_DIALOG_URCORNER);
+  cputcxy(x2, y2, CH_DIALOG_LRCORNER);
+  
+  
+  /* Clear dialog contents. */
+  for(i = y1; i < y2; ++i) {
+    cclearxy(x1, i, dialog->w);
+  }
+
+  draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
+		       x1, x2, y1, y2);
+
+  update_area(dialog->x, dialog->y, dialog->w + 4, dialog->h + 4);
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Clear parts of the VNC desktop. Called by the CTK module.
+ *
+ * \param y1 The lower y coordinate bound.
+ * \param y2 The upped y coordinate bound.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_clear(unsigned char y1, unsigned char y2)
+{
+  unsigned char i;
+
+  textcolor(VNC_OUT_BACKGROUNDCOLOR);
+  for(i = y1; i < y2; ++i) {
+    cclearxy(0, i, sizex);
+  }
+
+  update_area(0, y1, sizex, y2 - y1);
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Draw one menu on the VNC desktop.
+ *
+ * \param m The CTK menu to be drawn.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+draw_menu(struct ctk_menu *m)
+{
+  unsigned char x, x2, y;
+
+  textcolor(VNC_OUT_MENUCOLOR);
+  x = wherex();
+  cputs(m->title);
+  cputc(' ');
+  x2 = wherex();
+  if(x + CTK_CONF_MENUWIDTH > sizex) {
+    x = sizex - CTK_CONF_MENUWIDTH;
+  }
+  
+  
+  for(y = 0; y < m->nitems; ++y) {
+    if(y == m->active) {
+      textcolor(VNC_OUT_ACTIVEMENUCOLOR);
+      revers(0);
+    } else {
+      textcolor(VNC_OUT_MENUCOLOR);	  
+    }
+    gotoxy(x, y + 1);
+    if(m->items[y].title[0] == '-') {
+      chline(CTK_CONF_MENUWIDTH);
+    } else {
+      cputs(m->items[y].title);
+    }
+    if(x + CTK_CONF_MENUWIDTH > wherex()) {
+      cclear(x + CTK_CONF_MENUWIDTH - wherex());
+    }
+    revers(1);
+  }
+  
+  gotoxy(x2, 0);
+  textcolor(VNC_OUT_MENUCOLOR);  
+
+  update_area(x, 0, CTK_CONF_MENUWIDTH, m->nitems + 1);
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Draw the menus on the virtual VNC desktop. Called by the CTK module.
+ *
+ * \param menus The CTK menubar.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_draw_menus(struct ctk_menus *menus)
+{
+  struct ctk_menu *m;  
+
+  
+  /* Draw menus */
+  textcolor(VNC_OUT_MENUCOLOR);
+  gotoxy(0, 0);
+  revers(1);
+  cputc(' ');
+  for(m = menus->menus->next; m != NULL; m = m->next) {
+    if(m != menus->open) {
+      update_area(wherex(), 0, strlen(m->title) + 1, 1);
+      cputs(m->title);
+      cputc(' ');
+    } else {
+      draw_menu(m);
+    }
+  }
+
+
+  if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
+    gotoxy(sizex - strlen(menus->desktopmenu->title) - 1, 0);
+  } else {
+    cclear(sizex - wherex() -
+	   strlen(menus->desktopmenu->title) - 1);
+    update_area(wherex(), 0, sizex - wherex() -
+		strlen(menus->desktopmenu->title) - 1, 1);
+  }
+  
+  /* Draw desktopmenu */
+  if(menus->desktopmenu != menus->open) {
+    update_area(wherex(), 0, strlen(menus->desktopmenu->title) + 1, 1);
+    cputs(menus->desktopmenu->title);
+    cputc(' ');
+  } else {
+    draw_menu(menus->desktopmenu);
+  }
+
+  revers(0);
+
+
+
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Obtain the height of the VNC desktop. Called by the CTK module.
+ *
+ * \return The height of the VNC desktop, in characters.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_height(void)
+{
+  return sizey;
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Obtain the height of the VNC desktop. Called by the CTK module.
+ *
+ * \return The height of the VNC desktop, in characters.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_draw_width(void)
+{
+  return sizex;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_mouse_xtoc(unsigned short x)
+{
+  return x / CTK_VNCFONT_WIDTH;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_mouse_ytoc(unsigned short y)
+{
+  return y / CTK_VNCFONT_HEIGHT;
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Converts between ASCII and the VNC screen character encoding.
+ */
+/*-----------------------------------------------------------------------------------*/
+static unsigned char
+ascii2screen(unsigned char c)
+{
+  if(c == '|') {
+    return 0x68;
+  }
+  if(c < 0x20) {
+    return c + 0x60;
+  }
+  if(c > 0x20 && c < 0x40) {
+    return c;
+  }
+  if(c >= 0x40 && c < 0x60) {
+    return c;
+  }
+  if(c >= 0x60 && c < 0x80) {
+    return c - 0x60;
+  }
+  if(c >= 0x80) {
+    return c;
+  }
+
+  return 32;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Draws a character on the virtual VNC screen. Called by the libconio module.
+ *
+ * \param c The character to be drawn.
+ * \param xpos The x position of the character.
+ * \param ypos The y position of the character.
+ * \param reversedflag Determines if the character should be reversed or not.
+ * \param color The color of the character.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_arch_draw_char(char c,
+		   unsigned char xpos,
+		   unsigned char ypos,
+		   unsigned char reversedflag,
+		   unsigned char color)
+{
+
+  vnc_out_update_screen(xpos, ypos, ascii2screen(c),
+			color);
+  /*  vnc_out_update_screen(xpos, ypos, c |
+      (reversedflag? 0x80: 0));*/
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Checks the key press input queue to see if there are pending
+ * keys. Called by the CTK module.
+ *
+ * \return Zero if no key presses are in buffer, non-zero if there are
+ * key presses in input buffer.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_arch_keyavail(void)
+{
+  return vnc_out_keyavail();
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Retrieves key presses from the VNC client. Called by the CTK
+ * module.
+ *
+ * \return The next key in the input queue.
+ */
+/*-----------------------------------------------------------------------------------*/
+ctk_arch_key_t
+ctk_arch_getkey(void)
+{
+  return vnc_out_getkey() & 0x7f;
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * The uIP event handler.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_vncserver_appcall(void *state)
+{
+  static struct vnc_server_state *vs;
+
+  vs = (struct vnc_server_state *)(state);
+
+  if(uip_connected()) {
+
+    /* Since we've just been connected, the state pointer should be
+       NULL and we need to allocate a new state object. If we have run
+       out of memory for state objects, we'll have to abort the
+       connection and return. */
+    if(vs == NULL) {
+      vs = alloc_state();
+      if(vs == NULL) {
+	uip_close();
+	return;
+      }
+      tcp_markconn(uip_conn, (void *)vs);
+    }
+  } else if(uip_closed() || uip_aborted()) {
+    if(vs != NULL) {
+      dealloc_state(vs);
+    }
+    return;
+  }
+  vnc_server_appcall(vs);
+}
+/*-----------------------------------------------------------------------------------*/
+LOADER_INIT_FUNC(ctk_vncserver_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  u8_t i;
+  EK_EVENTHANDLER_ARGS(ev, data);
+
+  if(ev == EK_EVENT_INIT) {
+    tcp_listen(HTONS(5900));
+    
+    for(i = 0; i < CTK_VNCSERVER_CONF_NUMCONNS; ++i) {
+      conns[i].state = VNC_DEALLOCATED;
+    }
+  } else if(ev == tcpip_event) {
+    ctk_vncserver_appcall(data);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/** @} */
diff --git a/contiki/ctk/ctk-vncserver.h b/contiki/ctk/ctk-vncserver.h
new file mode 100644
index 0000000..1663748
--- /dev/null
+++ b/contiki/ctk/ctk-vncserver.h
@@ -0,0 +1,40 @@
+/*
+ * 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. 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-vncserver.h,v 1.4 2004/09/12 20:24:55 adamdunkels Exp $
+ *
+ */
+#ifndef __CTK_VNCSERVER_H__
+#define __CTK_VNCSERVER_H__
+
+void ctk_vncserver_init(char *arg);
+
+#endif /* __CTK_VNCSERVER_H__ */
diff --git a/contiki/ctk/ctk.c b/contiki/ctk/ctk.c
new file mode 100644
index 0000000..2523d1e
--- /dev/null
+++ b/contiki/ctk/ctk.c
@@ -0,0 +1,1900 @@
+/**
+ * \defgroup ctk The CTK graphical user interface.
+ * @{
+ * The Contiki Toolkit (CTK) provides the graphical user interface for
+ * the Contiki system.
+ *
+ */
+
+/**
+ * \file
+ * The Contiki Toolkit CTK, the Contiki GUI.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2002-2003, 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. 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 operating system.
+ *
+ * $Id: ctk.c,v 1.50 2005/05/05 20:54:16 oliverschmidt Exp $
+ *
+ */
+
+#include "ek.h"
+#include "cc.h"
+
+#include "ctk.h"
+#include "ctk-draw.h"
+#include "ctk-conf.h"
+#include "ctk-mouse.h"
+
+#include "timer.h"
+
+#include <string.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 - 6)
+#define ICONY_START  (height - 7)
+#define ICONX_DELTA  -16
+#define ICONY_DELTA  -5
+#define ICONY_MAX    height
+#define ICONY_MIN    0
+
+#ifndef ctk_arch_isprint
+unsigned char ctk_arch_isprint(char c);
+#endif /* ctk_arch_isprint */
+
+EK_POLLHANDLER(ctk_poll);
+EK_EVENTHANDLER(ctk_eventhandler, ev, data);
+EK_PROCESS(p, "CTK Contiki GUI", EK_PRIO_NORMAL, ctk_eventhandler,
+	   ctk_poll, NULL);
+/*static struct ek_proc p =
+  {DISPATCHER_PROC("CTK Contiki GUI", ctk_idle, NULL, NULL)};*/
+static ek_id_t ctkid;
+
+/** @} */
+
+/**
+ * \addtogroup signals System signals
+ * @{
+ */
+ek_event_t
+
+  /**
+   * Emitted for every key being pressed.
+   *
+   * The key is passed as signal data.*/
+  ctk_signal_keypress,
+  
+  /** Emitted when a widget is activated (pressed). A pointer to the
+      widget is passed as signal data. */
+  ctk_signal_widget_activate,
+  
+  /** Same as ctk_signal_widget_activate. */
+  ctk_signal_button_activate,
+
+  /** Emitted when a widget is selected. A pointer to the widget is
+      passed as signal data. */
+  ctk_signal_widget_select,
+  
+  /** Same as ctk_signal_widget_select. */  
+  ctk_signal_button_hover,
+
+  /** Emitted when a hyperlink is activated. The signal is broadcast
+      to all listeners. */
+  ctk_signal_hyperlink_activate,
+
+  /** Same as ctk_signal_widget_select. */  
+  ctk_signal_hyperlink_hover,
+
+  /** Emitted when a menu item is activated. The number of the menu
+      item is passed as signal data. */
+  ctk_signal_menu_activate,
+
+  /** Emitted when a window is closed. A pointer to the window is
+      passed as signal data. */
+  ctk_signal_window_close,
+
+  /** Emitted when the mouse pointer is moved. A NULL pointer is
+      passed as signal data and it is up to the listening process to
+      check the position of the mouse using the CTK mouse API.*/
+  ctk_signal_pointer_move,
+
+  /** Emitted when a mouse button is pressed. The button is passed as
+      signal data to the listening process. */
+  ctk_signal_pointer_button;
+
+#if CTK_CONF_SCREENSAVER
+/** Emitted when the user has been idle long enough for the
+    screensaver to start. */
+ek_event_t ctk_signal_screensaver_stop,
+  /** Emitted when the user presses a key or moves the mouse when the
+      screensaver is active. */
+  ctk_signal_screensaver_start;
+#endif /* CTK_CONF_SCREENSAVER */
+
+/** @} */
+
+/**
+ * \addtogroup ctk
+ * @{
+ */
+
+#if CTK_CONF_MOUSE_SUPPORT
+unsigned short mouse_x, mouse_y, mouse_button;
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+
+static unsigned short screensaver_timer = 0;
+unsigned short ctk_screensaver_timeout = (5*60);
+/*static ek_clock_t start, current;*/
+static struct timer timer;
+
+static void CC_FASTCALL 
+textentry_input(ctk_arch_key_t c,
+		CC_REGISTER_ARG struct ctk_textentry *t);
+#if CTK_CONF_MENUS
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Creates the Desktop menu.
+ *
+ * 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 */
+/*-----------------------------------------------------------------------------------*/
+static void
+arrange_icons(void)
+{
+  struct ctk_widget *icon;
+
+  iconx = ICONX_START;
+  icony = ICONY_START;
+  
+  for(icon = desktop_window.active; icon != NULL; icon = icon->next) {
+    
+    icon->x = iconx;
+    icon->y = icony;
+    
+    icony += ICONY_DELTA;
+    if(icony >= ICONY_MAX ||
+       icony < ICONY_MIN) {
+      icony = ICONY_START;
+      iconx += ICONX_DELTA;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/  
+void
+ctk_restore(void)
+{
+  ctk_draw_init();
+
+  height = ctk_draw_height();
+  width = ctk_draw_width();
+
+  arrange_icons();
+
+  redraw = REDRAW_ALL;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Initializes the Contiki Toolkit.
+ *
+ * This function must be called before any other CTK function, but
+ * after the inizialitation of the dispatcher module.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_init(void)
+{
+  ctkid = ek_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 */
+
+#if CTK_CONF_MOUSE_SUPPORT
+  ctk_mouse_init();
+  ctk_mouse_show();
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+  
+  ctk_draw_init();
+
+  height = ctk_draw_height();
+  width = ctk_draw_width();
+  
+  desktop_window.active = NULL;
+  desktop_window.owner = ctkid;
+  
+  ctk_signal_keypress = ek_alloc_event();
+  
+  ctk_signal_button_activate =
+    ctk_signal_widget_activate = ek_alloc_event();
+  
+  ctk_signal_button_hover =
+    ctk_signal_hyperlink_hover =
+    ctk_signal_widget_select = ek_alloc_event();
+  
+  ctk_signal_hyperlink_activate = ek_alloc_event();
+
+  ctk_signal_menu_activate = ek_alloc_event();
+  ctk_signal_window_close = ek_alloc_event();
+
+  ctk_signal_pointer_move = ek_alloc_event();
+  ctk_signal_pointer_button = ek_alloc_event();
+
+
+#if CTK_CONF_SCREENSAVER
+  ctk_signal_screensaver_start = ek_alloc_event();
+  ctk_signal_screensaver_stop = ek_alloc_event();
+#endif /* CTK_CONF_SCREENSAVER */
+    
+
+  mode = CTK_MODE_NORMAL;
+
+  iconx = ICONX_START;
+  icony = ICONY_START;
+
+  redraw = REDRAW_ALL;
+
+  /*  start = ek_clock();*/
+  timer_set(&timer, CLOCK_SECOND);
+}
+
+/**
+ * \addtogroup ctkappfunc
+ * @{
+ */
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Sets the current CTK mode.
+ *
+ * The CTK mode can be either CTK_MODE_NORMAL, CTK_MODE_SCREENSAVER or
+ * CTK_MODE_EXTERNAL. CTK_MODE_NORMAL is the normal mode, in which
+ * keypresses and mouse pointer movements are processed and the screen
+ * is redrawn. In CTK_MODE_SCREENSAVER, no screen redraws are
+ * performed and the first key press or pointer movement will cause
+ * the ctk_signal_screensaver_stop to be emitted. In the
+ * CTK_MODE_EXTERNAL mode, key presses and pointer movements are
+ * ignored and no screen redraws are made.
+ *
+ * \param m The mode. 
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_mode_set(unsigned char m) {
+  mode = m;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Retrieves the current CTK mode.
+ *
+ * \return The current CTK mode.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_mode_get(void) {
+  return mode;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Add an icon to the desktop.
+ *
+ * \param icon The icon to be added.
+ *
+ * \param id The process ID of the process that owns the icon.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_icon_add(CC_REGISTER_ARG 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;
+    }*/
+  icon->widget.icon.owner = id;
+  ctk_widget_add(&desktop_window, icon);
+  arrange_icons();
+#endif /* CTK_CONF_ICONS */
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Open a dialog box.
+ *
+ * \param d The dialog to be opened.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_dialog_open(struct ctk_window *d)
+{
+  dialog = d;
+  redraw |= REDRAW_FOCUS;
+} 
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Close the dialog box, if one is open.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_dialog_close(void)
+{
+  dialog = NULL;
+  redraw |= REDRAW_ALL;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Open a window, or bring window to front if already open.
+ *
+ * \param w The window to be opened.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_open(CC_REGISTER_ARG 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 */
+
+  redraw |= REDRAW_ALL;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Close a window if it is open.
+ *
+ * If the window is not open, this function does nothing.
+ *
+ * \param w The window to be closed.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_close(struct ctk_window *w)
+{
+  static 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 != NULL && w2->next != w; w2 = w2->next);
+
+    if(w2 == NULL) {
+      /* The window wasn't open, so there is nothing more for us to
+	 do. */
+      return;
+    }
+
+    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 */
+  redraw |= REDRAW_ALL;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Create the move and close buttons on the window titlebar.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+make_windowbuttons(CC_REGISTER_ARG struct ctk_window *window)
+{
+  unsigned char placement;
+
+  if(ctk_draw_windowtitle_height >= 2) {
+    placement = -1 - ctk_draw_windowtitle_height/2;
+  } else {
+    placement = -1;
+  }
+#if CTK_CONF_WINDOWMOVE
+  CTK_BUTTON_NEW(&window->titlebutton, 0, placement,
+		 window->titlelen, window->title);
+#else
+  CTK_LABEL_NEW(&window->titlebutton, 0, placement,
+		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, placement,
+		 1, "x");
+#else
+  CTK_LABEL_NEW(&window->closebutton, window->w - 4, placement,
+		3, 1, "   ");
+#endif /* CTK_CONF_WINDOWCLOSE */  
+  CTK_WIDGET_ADD(window, &window->closebutton);
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Remove all widgets from a window.
+ *
+ * \param w The window to be cleared.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_window_clear(struct ctk_window *w)
+{
+  w->active = w->inactive = w->focused = NULL;
+  
+  make_windowbuttons(w);
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Add a menu to the menu bar.
+ *
+ * \param menu The menu to be added.
+ *
+ * \note Do not call this function multiple times for the same menu,
+ * as no check is made to see if the menu already is in the menu bar.
+ */
+/*-----------------------------------------------------------------------------------*/
+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;
+
+  redraw |= REDRAW_MENUPART;
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Remove a menu from the menu bar.
+ *
+ * \param menu The menu to be removed.
+ */
+/*-----------------------------------------------------------------------------------*/
+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;
+      if(menu == lastmenu) {
+	lastmenu = NULL;
+      }
+      redraw |= REDRAW_MENUPART;      
+      return;
+    }
+  }
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Redraws everything on the screen within the clip
+ * interval.
+ *
+ * \param clipy1 The upper bound of the clip interval
+ * \param clipy2 The lower bound of the clip interval 
+ */
+/*-----------------------------------------------------------------------------------*/
+static void CC_FASTCALL 
+do_redraw_all(unsigned char clipy1, unsigned char clipy2)
+{
+  struct ctk_window *w;
+  static struct ctk_widget *widget;
+  unsigned char focus;
+
+  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, windows != NULL? 0: CTK_FOCUS_WINDOW, 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, 1);
+    }
+
+    /* Draw focused window */
+    focus = mode == CTK_MODE_WINDOWMOVE?
+	    CTK_FOCUS_WIDGET|CTK_FOCUS_WINDOW:
+	    CTK_FOCUS_WINDOW;
+    ctk_draw_clear_window(windows, focus, clipy1, clipy2);
+    ctk_draw_window(windows, focus, clipy1, clipy2, 1);
+  }
+
+  /* Draw dialog (if any) */
+  if(dialog != NULL) {
+    ctk_draw_dialog(dialog);
+  }
+
+#if CTK_CONF_MENUS
+  ctk_draw_menus(&menus);
+#endif /* CTK_CONF_MENUS */
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Redraw the entire desktop.
+ *
+ * \param d The desktop to be redrawn.
+ *
+ * \note Currently the parameter d is not used, but must be set to
+ * NULL.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_desktop_redraw(struct ctk_desktop *d)
+{
+  if(EK_CURRENT() == &p) {
+    if(mode == CTK_MODE_NORMAL ||
+       mode == CTK_MODE_WINDOWMOVE) {
+      do_redraw_all(1, height);
+    }
+  } else {
+    redraw |= REDRAW_ALL;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Redraw a window.
+ *
+ * This function redraws the window, but only if it is the foremost
+ * one on the desktop.
+ *
+ * \param w The window to be redrawn.
+ */
+/*-----------------------------------------------------------------------------------*/
+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, 0);
+  }  
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Creates a new window.
+ *
+ * \param window The window to be created.
+ * \param w The width of the window.
+ * \param h The height of the window.
+ * \param title The title of the window.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void 
+window_new(CC_REGISTER_ARG struct ctk_window *window,
+	   unsigned char w, unsigned char h,
+	   char *title)
+{
+  
+  if(w >= width - 2) {
+    window->x = 0;
+  } else {
+    window->x = (width - w - 2) / 2;
+  }
+  if(h >= height - 2 - ctk_draw_windowtitle_height) {
+    window->y = 0;
+  } else {
+    window->y = (height - h - 2 - ctk_draw_windowtitle_height) / 2;
+  }
+
+  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->owner = EK_PROC_ID(EK_CURRENT());
+  window->active = window->inactive = window->focused = NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Create a new window.
+ *
+ * Creates a new window. The memory for the window structure must
+ * already be allocated by the caller, and is usually done with a
+ * static declaration.
+ *
+ * This function sets up the internal structure of the ctk_window
+ * struct and creates the move and close buttons, but it does not open
+ * the window. The window must be explicitly opened by calling the
+ * ctk_window_open() function.
+ *
+ * \param window The window to be created.
+ * \param w The width of the new window.
+ * \param h The height of the new window.
+ * \param title The title of the new window.
+ */
+/*-----------------------------------------------------------------------------------*/
+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);  
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Creates a new dialog.
+ *
+ * This function only sets up the internal structure of the ctk_window
+ * struct but does not open the dialog. The dialog must be explicitly
+ * opened by calling the ctk_dialog_open() function.
+ *
+ * \param dialog The dialog to be created.
+ * \param w The width of the dialog.
+ * \param h The height of the dialog.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_dialog_new(CC_REGISTER_ARG struct ctk_window *dialog,
+	       unsigned char w, unsigned char h)
+{
+  window_new(dialog, w, h, NULL);
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Creates a new menu.
+ *
+ * This function sets up the internal structure of the menu, but does
+ * not add it to the menubar. Use the function ctk_menu_add() for that
+ * purpose.
+ *
+ * \param menu The menu to be created.
+ * \param title The title of the menu.
+ */
+/*-----------------------------------------------------------------------------------*/
+void 
+ctk_menu_new(CC_REGISTER_ARG 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 */
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Adds a menu item to a menu.
+ *
+ * In CTK, each menu item is identified by a number which is unique
+ * within each menu. When a menu item is selected, a
+ * ctk_menuitem_activated signal is emitted and the menu item number
+ * is passed as signal data with the signal.
+ *
+ * \param menu The menu to which the menu item should be added.
+ * \param name The name of the menu item.
+ * \return The number of the menu item.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_menuitem_add(CC_REGISTER_ARG 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 */
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Adds a widget to the list of widgets that should be
+ * redrawn.
+ *
+ * \param w The widget that should be redrawn.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void CC_FASTCALL 
+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;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Checks if a widget redrawn and adds it to the list of
+ * widgets to be redrawn.
+ *
+ * A widget can be redrawn only if the current CTK mode is
+ * CTK_MODE_NORMAL, if no menu is open, and the widget is in the
+ * foremost window.
+ *
+ * \param widget The widget that should be redrawn.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+widget_redraw(struct ctk_widget *widget)
+{
+  struct ctk_window *window;
+
+  if(mode != CTK_MODE_NORMAL || widget == NULL) {
+    return;
+  }
+
+  /* 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(dialog == NULL &&
+		(window == windows ||
+		 window == &desktop_window)) {
+	ctk_draw_widget(widget, CTK_FOCUS_WINDOW, 0, height);
+      }
+    }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Redraws a widget.
+ *
+ * This function will set a flag which causes the widget to be redrawn
+ * next time the CTK process is scheduled.
+ *
+ * \param widget The widget that is to be redrawn.
+ *
+ * \note This function should usually not be called directly since it
+ * requires typecasting of the widget parameter. The wrapper macro
+ * CTK_WIDGET_REDRAW() does the required typecast and should be used
+ * instead.
+ */
+/*-----------------------------------------------------------------------------------*/
+void 
+ctk_widget_redraw(struct ctk_widget *widget)
+{
+  if(mode != CTK_MODE_NORMAL || widget == NULL) {
+    return;
+  }
+
+  /* Since this function isn't called by CTK itself, we only queue the
+     redraw request. */
+  add_redrawwidget(widget);
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Adds a widget to a window.
+ *
+ * This function adds a widget to a window. The order of which the
+ * widgets are added is important, as it sets the order to which
+ * widgets are cycled with the widget selection keys.
+ *
+ * \param window The window to which the widhet should be added.
+ * \param widget The widget to be added.
+ */
+/*-----------------------------------------------------------------------------------*/
+void CC_FASTCALL
+ctk_widget_add(CC_REGISTER_ARG struct ctk_window *window,
+	       CC_REGISTER_ARG 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;
+      }*/
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Gets the width of the desktop.
+ *
+ * \param d The desktop.
+ * \return The width of the desktop, in characters.
+ *
+ * \note The d parameter is currently unused and must be set to NULL.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_desktop_width(struct ctk_desktop *d)
+{
+  return ctk_draw_width();
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Gets the height of the desktop.
+ *
+ * \param d The desktop.
+ * \return The height of the desktop, in characters.
+ *
+ * \note The d parameter is currently unused and must be set to NULL.
+ */
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_desktop_height(struct ctk_desktop *d)
+{
+  return ctk_draw_height();
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Selects a widget in the window of the widget.
+ *
+ * \param focus The widget to be focused.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void CC_FASTCALL 
+select_widget(struct ctk_widget *focus)
+{
+  struct ctk_window *window;
+
+  window = focus->window;
+  
+  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) {    
+      ek_post(window->owner, ctk_signal_hyperlink_hover, window->focused);
+    } else if(window->focused->type == CTK_WIDGET_BUTTON) {    
+      ek_post(window->owner, ctk_signal_button_hover, window->focused);      
+    } 
+    
+    add_redrawwidget(window->focused);
+
+    ek_post(focus->window->owner, ctk_signal_widget_select, focus);
+
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+#define UP 0
+#define DOWN 1
+#define LEFT 2
+#define RIGHT 3
+static void CC_FASTCALL 
+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;
+  if(focus == NULL) {
+    focus = window->active;
+    if(focus == NULL) {
+      return;
+    }
+  }
+  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;
+  }
+
+  select_widget(focus);
+}
+/*-----------------------------------------------------------------------------------*/
+#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;
+
+  /*  if(menus.open->nitems > maxnitems) {
+    maxnitems = menus.open->nitems;
+    }*/
+
+  /*  ctk_desktop_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 CC_FASTCALL 
+activate(CC_REGISTER_ARG struct ctk_widget *w)
+{
+  if(w->type == CTK_WIDGET_BUTTON) {
+    if(w == (struct ctk_widget *)&windows->closebutton) {
+#if CTK_CONF_WINDOWCLOSE
+      ek_post(w->window->owner, ctk_signal_window_close, windows);
+      ctk_window_close(windows);
+      return REDRAW_ALL;
+#endif /* CTK_CONF_WINDOWCLOSE */
+    } else if(w == (struct ctk_widget *)&windows->titlebutton) {
+#if CTK_CONF_WINDOWMOVE
+      mode = CTK_MODE_WINDOWMOVE;
+      return REDRAW_ALL;
+#endif /* CTK_CONF_WINDOWMOVE */
+    } else {
+      ek_post(w->window->owner, ctk_signal_widget_activate, w);
+    }
+#if CTK_CONF_ICONS
+  } else if(w->type == CTK_WIDGET_ICON) {
+    if(w->widget.icon.owner != EK_ID_NONE) {
+      ek_post(w->widget.icon.owner, ctk_signal_widget_activate, w);
+    } else {
+      ek_post(w->window->owner, ctk_signal_widget_activate, w);
+    }
+#endif /* CTK_CONF_ICONS */
+  } else if(w->type == CTK_WIDGET_HYPERLINK) {    
+    ek_post(EK_BROADCAST, ctk_signal_hyperlink_activate, w);
+  } else if(w->type == CTK_WIDGET_TEXTENTRY) {
+    if(w->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {      
+      w->widget.textentry.state = CTK_TEXTENTRY_EDIT;
+      textentry_input(0, (struct ctk_textentry *)w);
+    } else {
+      w->widget.textentry.state = CTK_TEXTENTRY_NORMAL;
+      ek_post(w->window->owner, ctk_signal_widget_activate, w);
+    }
+    add_redrawwidget(w);
+    return REDRAW_WIDGETS;
+  } else {
+    ek_post(w->window->owner, ctk_signal_widget_activate, w);
+  }
+  return REDRAW_NONE;
+}
+/*-----------------------------------------------------------------------------------*/
+static void CC_FASTCALL 
+textentry_input(ctk_arch_key_t c,
+		CC_REGISTER_ARG struct ctk_textentry *t)
+{
+  register char *cptr, *cptr2;
+  static unsigned char len, txpos, typos, tlen;
+
+  if(t->input != NULL && t->input(c, t)) {
+    return;
+  }
+
+  txpos = t->xpos;
+  typos = t->ypos;
+  tlen = t->len;
+
+  cptr = &t->text[txpos + typos * (tlen + 1)];
+      
+  switch(c) {
+  case CH_CURS_LEFT:
+    if(txpos > 0) {
+      --txpos;
+    }
+    break;
+    
+  case CH_CURS_RIGHT:    
+    if(txpos < tlen - 1 && *cptr != 0) {
+      ++txpos;
+    }
+    break;
+
+  case CH_CURS_UP:
+    txpos = 0;
+    break;
+    
+  case 0:
+  case CH_CURS_DOWN:
+    txpos = strlen(t->text);
+    if(txpos == tlen) {
+      --txpos;
+    }
+    break;
+    
+  case CH_ENTER:
+    /*    t->state = CTK_TEXTENTRY_NORMAL;*/
+    activate((struct ctk_widget *)t);
+    switch_focus_widget(DOWN);
+    break;
+    
+  case CTK_CONF_WIDGETDOWN_KEY:
+    t->state = CTK_TEXTENTRY_NORMAL;
+    switch_focus_widget(DOWN);
+    break;
+  case CTK_CONF_WIDGETUP_KEY:
+    t->state = CTK_TEXTENTRY_NORMAL;
+    switch_focus_widget(UP);
+    break;
+    
+  default:
+    len = tlen - txpos;
+    if(c == CH_DEL) {
+      if(len == 1 && *cptr != 0) {
+	*cptr = 0;
+      } else {
+        if(txpos > 0) {
+	  --txpos;
+	  strcpy(cptr - 1, cptr);
+	}
+      }
+    } else {
+      if(ctk_arch_isprint(c)) {
+	if(len > 1) {
+	  cptr2 = cptr + len - 1;
+	  while(cptr2 > cptr) {
+	    *cptr2 = *(cptr2 - 1);
+	    --cptr2;
+	  }
+	  ++txpos;
+	}
+	*cptr = c;
+      }
+    }
+    break;
+  }
+
+  t->xpos = txpos;
+  t->ypos = typos;
+}
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_MENUS
+static unsigned char 
+activate_menu(void)
+{
+  struct ctk_window *w;
+  
+  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 {
+    ek_post(EK_BROADCAST, ctk_signal_menu_activate, menus.open);
+  }
+  menus.open = NULL;
+  return REDRAW_MENUPART;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char 
+menus_input(ctk_arch_key_t c)
+{
+
+  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:
+    return activate_menu();
+
+  case CTK_CONF_MENU_KEY:
+    lastmenu = menus.open;
+    menus.open = NULL;
+    return REDRAW_MENUPART;
+  }
+
+  return REDRAW_NONE;
+}
+#endif /* CTK_CONF_MENUS */
+/*-----------------------------------------------------------------------------------*/
+static void
+handle_timer(void)
+{
+  if(mode == CTK_MODE_NORMAL) {
+    ++screensaver_timer;
+    if(screensaver_timer >= ctk_screensaver_timeout) {
+#if CTK_CONF_SCREENSAVER
+      ek_post(EK_BROADCAST, ctk_signal_screensaver_start, NULL);
+#ifdef CTK_SCREENSAVER_INIT
+      CTK_SCREENSAVER_INIT();
+#endif /* CTK_SCREENSAVER_INIT */
+
+#endif /* CTK_CONF_SCREENSAVER */
+      screensaver_timer = 0;
+    }
+  }  
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+unfocus_widget(CC_REGISTER_ARG struct ctk_widget *w)
+{
+  if(w != NULL) {
+    redraw |= REDRAW_WIDGETS;
+    add_redrawwidget(w);
+    if(CTK_WIDGET_TYPE(w) == CTK_WIDGET_TEXTENTRY) {
+      ((struct ctk_textentry *)w)->state =
+	CTK_TEXTENTRY_NORMAL;
+    }
+    w->window->focused = NULL;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+EK_POLLHANDLER(ctk_poll)
+{
+  static ctk_arch_key_t c;
+  static unsigned char i;
+  register struct ctk_window *window;
+  register struct ctk_widget *widget;
+  register struct ctk_widget **widgetptr;
+#if CTK_CONF_MOUSE_SUPPORT 
+  static unsigned char mxc, myc, mouse_button_changed, mouse_moved,
+    mouse_clicked;
+  static unsigned char menux;
+  register struct ctk_menu *menu;
+
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+
+
+  /*  current = ek_clock();
+  
+  if((current - start) >= CLK_TCK) {
+    timer();
+    start = current;
+    } */
+  if(timer_expired(&timer)) {
+    timer_reset(&timer);
+    handle_timer();
+  }
+
+#if CTK_CONF_MENUS
+  if(menus.open != NULL) {
+    maxnitems = menus.open->nitems;
+  } else {
+    maxnitems = 0;
+  }
+#endif /* CTK_CONF_MENUS */
+
+#if CTK_CONF_MOUSE_SUPPORT
+  mouse_button_changed = mouse_moved = mouse_clicked = 0;
+
+  /* See if there is any change in the buttons. */
+  if(ctk_mouse_button() != mouse_button) {
+    mouse_button = ctk_mouse_button();
+    mouse_button_changed = 1;
+    if(mouse_button == 0) {
+      mouse_clicked = 1;
+    }
+  }
+  
+  /* Check if the mouse pointer has moved. */
+  if(ctk_mouse_x() != mouse_x ||
+     ctk_mouse_y() != mouse_y) {
+    mouse_x = ctk_mouse_x();
+    mouse_y = ctk_mouse_y();
+    mouse_moved = 1;
+  }
+
+  mxc = ctk_mouse_xtoc(mouse_x);
+  myc = ctk_mouse_ytoc(mouse_y); 
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+
+
+#if CTK_CONF_SCREENSAVER
+  if(mode == CTK_MODE_SCREENSAVER) {
+    if(ctk_arch_keyavail()
+#if CTK_CONF_MOUSE_SUPPORT
+       || mouse_moved || mouse_button_changed
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+       ) {      
+      ek_post(EK_BROADCAST, ctk_signal_screensaver_stop, NULL);
+      mode = CTK_MODE_NORMAL;
+    }
+  } else
+#endif /* CTK_CONF_SCREENSAVER */
+    if(mode == CTK_MODE_NORMAL) {
+#if CTK_CONF_MOUSE_SUPPORT 
+    /* If there is any change in the mouse conditions, find out in
+       which window the mouse pointer currently is in order to send
+       the correct signals, or bring a window to focus. */
+    if(mouse_moved || mouse_button_changed) {
+      ctk_mouse_show();
+      screensaver_timer = 0;
+      
+      if(myc == 0) {
+	/* Here we should do whatever needs to be done when the mouse
+	   moves around and clicks in the menubar. */
+	if(mouse_clicked) {
+	  static unsigned char titlelen;
+	  
+	  /* Find out which menu that the mouse pointer is in. Start
+	     with the ->next menu after the desktop menu. We assume
+	     that the menus start one character from the left screen
+	     side and that the desktop menu is farthest to the
+	     right. */
+	  menux = 1;
+	  for(menu = menus.menus->next;
+	      menu != NULL; menu = menu->next) {
+	    titlelen = menu->titlelen;
+	    if(mxc >= menux && mxc <= menux + titlelen) {
+	      break;
+	    }
+	    menux += titlelen;
+	  }
+	  
+	  /* Also check desktop menu. */
+	  if(mxc >= width - 7 &&
+	     mxc <= width - 1) {
+	    menu = &desktopmenu;
+	  }
+	  
+	  menus.open = menu;
+	  redraw |= REDRAW_MENUPART;
+	}
+      } else {
+	--myc;
+
+	if(menus.open != NULL) {
+	  static unsigned char nitems;
+	  
+	  /* Do whatever needs to be done when a menu is open. */
+
+	  /* First check if the mouse pointer is in the currently open
+	     menu. */
+	  if(menus.open == &desktopmenu) {
+	    menux = width - CTK_CONF_MENUWIDTH;
+	  } else {
+	    menux = 1;
+	    for(menu = menus.menus->next; menu != menus.open;
+		menu = menu->next) {
+	      menux += menu->titlelen;
+	    }
+	  }
+
+	  nitems = menus.open->nitems;
+	  /* Find out which of the menu items the mouse is pointing
+	     to. */
+	  if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH) {    
+	    if(myc <= nitems) {
+	      menus.open->active = myc;
+	    } else {
+	      menus.open->active = nitems - 1;
+	    }
+	  }
+	  
+	  if(mouse_clicked) {
+	    if(mxc >= menux && mxc <= menux + CTK_CONF_MENUWIDTH &&
+	       myc <= nitems) {
+	      redraw |= activate_menu();
+	    } else {
+	      lastmenu = menus.open;
+	      menus.open = NULL;
+	      redraw |= REDRAW_MENUPART;
+	    }
+	  } else {
+	    redraw |= REDRAW_MENUS;	  
+	  }
+	} else {
+
+	  /* Walk through the windows from top to bottom to see in
+	     which window the mouse pointer is. */
+	  if(dialog != NULL) {
+	    window = dialog;
+	  } else {	  	 	  
+	    for(window = windows; window != NULL;
+		window = window->next) {
+	      
+	      /* Check if the mouse is within the window. */
+	      if(mxc >= window->x &&
+		 mxc <= window->x + window->w +
+		        2 * ctk_draw_windowborder_width &&
+		 myc >= window->y &&
+		 myc <= window->y + window->h +
+		 ctk_draw_windowtitle_height +
+		 ctk_draw_windowborder_height) {
+		break;       	
+	      }
+	    }
+	  }
+
+
+	  /* If we didn't find any window, and there are no windows
+	     open, the mouse pointer will definately be within the
+	     background desktop window. */
+	  if(window == NULL) {
+	    window = &desktop_window;
+	  }
+
+	  /* If the mouse pointer moves around outside of the
+	     currently focused window (or dialog), we should not have
+	     any focused widgets in the focused window so we make sure
+	     that there are none. */
+	  if(windows != NULL &&
+	     window != windows &&
+	     windows->focused != NULL){	  
+	    /*add_redrawwidget(windows->focused);
+	    windows->focused = NULL;
+	    redraw |= REDRAW_WIDGETS;*/
+	    unfocus_widget(windows->focused);
+	  }
+
+	  if(window != NULL) {
+	    /* If the mouse was clicked outside of the current window,
+	       we bring the clicked window to front. */
+	    if(dialog == NULL &&
+	       window != &desktop_window &&	   
+	       window != windows &&
+	       mouse_clicked) {
+	      /* Bring window to front. */
+	      ctk_window_open(window);
+	      redraw |= REDRAW_ALL;
+	    } else {
+	  
+	      /* Find out which widget currently is under the mouse
+		 pointer and give it focus, unless it already has
+		 focus. */
+	      mxc = mxc - window->x - ctk_draw_windowborder_width;
+	      myc = myc - window->y - ctk_draw_windowtitle_height;
+	    
+	      /* See if the mouse pointer is on a widget. If so, it
+		 should be selected and, if the button is clicked,
+		 activated. */
+	      for(widget = window->active; widget != NULL;
+		  widget = widget->next) {
+		
+		if(mxc >= widget->x &&
+		   mxc <= widget->x + widget->w &&
+		   (myc == widget->y ||
+		    ((widget->type == CTK_WIDGET_BITMAP ||
+		      /*widget->type == CTK_WIDGET_TEXTMAP ||*/
+		      widget->type == CTK_WIDGET_ICON) &&
+		     (myc >= widget->y &&
+		      myc <= widget->y +
+		      ((struct ctk_bitmap *)widget)->h)))) {
+		  break;
+		}
+	      }
+	    
+
+	      /* if the mouse is moved in the focused window, we emit
+		 a ctk_signal_pointer_move signal to the owner of the
+		 window. */
+	      if(mouse_moved &&
+		 (window != &desktop_window ||
+		  windows == NULL)) {
+
+		ek_post(window->owner, ctk_signal_pointer_move, NULL);
+
+		/* If there was a focused widget that is not below the
+		   mouse pointer, we remove focus from the widget and
+		   redraw it. */
+		if(window->focused != NULL &&
+		   widget != window->focused) {
+		  /*		  add_redrawwidget(window->focused);
+		  if(CTK_WIDGET_TYPE(window->focused) ==
+		     CTK_WIDGET_TEXTENTRY) {
+		    ((struct ctk_textentry *)(window->focused))->state =
+		      CTK_TEXTENTRY_NORMAL;
+		  }
+		  window->focused = NULL;*/
+		  unfocus_widget(window->focused);
+		}
+		redraw |= REDRAW_WIDGETS;
+		if(widget != NULL) {
+		  select_widget(widget);
+		}
+	      }
+	    
+	      if(mouse_button_changed) {
+		ek_post(window->owner, ctk_signal_pointer_button,
+			(ek_data_t)mouse_button);
+		if(mouse_clicked && widget != NULL) {
+		  select_widget(widget);
+		  redraw |= activate(widget);
+		}
+	      }
+	    }
+	  }    
+	}
+      }
+    }
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+    
+    while(ctk_arch_keyavail()) {
+
+      ctk_mouse_hide();
+      
+      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 CTK_CONF_WIDGETDOWN_KEY:
+	  switch_focus_widget(DOWN);
+	  break;
+	case CTK_CONF_WIDGETUP_KEY:
+	  switch_focus_widget(UP);
+	  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);
+	  }
+	  break;
+	default:
+
+	  if(c == CH_ENTER &&
+	     widget != NULL) {
+	    redraw |= activate(widget);
+	  } else {
+	    if(widget != NULL &&
+	       widget->type == CTK_WIDGET_TEXTENTRY) {
+	      if(widget->widget.textentry.state == CTK_TEXTENTRY_NORMAL) {
+		widget->widget.textentry.state = CTK_TEXTENTRY_EDIT;
+		textentry_input(0, (struct ctk_textentry *)widget);
+	      }
+	      textentry_input(c, (struct ctk_textentry *)widget);
+	      add_redrawwidget(widget);
+	    } else {
+	      /*	      window->focused = NULL;*/
+	      unfocus_widget(window->focused);
+	      ek_post_synch(window->owner, ctk_signal_keypress, (ek_data_t)c);
+	    }
+	  }
+	  break;
+	}
+      }
+
+#if 0
+      if(redraw & REDRAW_WIDGETS) {
+	widgetptr = redraw_widgets;
+	for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
+	  widget_redraw(*widgetptr);
+	  *widgetptr = NULL;
+	  ++widgetptr;
+	}
+	redraw &= ~REDRAW_WIDGETS;
+	redraw_widgetptr = 0;
+      }
+#endif /* 0 */
+    }
+#if CTK_CONF_WINDOWMOVE
+  } else if(mode == CTK_MODE_WINDOWMOVE) {
+
+    redraw = 0;
+
+    window = windows;
+
+#if CTK_CONF_MOUSE_SUPPORT
+
+    /* If the mouse has moved, we move the window as well. */
+    if(mouse_moved) {
+
+      if(window->w + mxc + 2 >= width) {
+	window->x = width - 2 - window->w;
+      } else {
+	window->x = mxc;
+      }
+
+      if(window->h + myc + ctk_draw_windowtitle_height +
+	 ctk_draw_windowborder_height >= height) {
+	window->y = height - window->h -
+	  ctk_draw_windowtitle_height - ctk_draw_windowborder_height;
+      } else {
+	window->y = myc;
+      }
+      if(window->y > 0) {
+	--window->y;
+      }
+
+      redraw = REDRAW_ALL;
+    }		  
+    
+    /* Check if the mouse has been clicked, and stop moving the window
+       if so. */
+    if(mouse_button_changed &&
+       mouse_button == 0) {
+      mode = CTK_MODE_NORMAL;
+      redraw = REDRAW_ALL;      
+    }
+#endif /* CTK_CONF_MOUSE_SUPPORT */
+    
+    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;
+      default:
+	mode = CTK_MODE_NORMAL;
+	redraw = REDRAW_ALL;
+	break;
+      }
+    }
+#endif /* CTK_CONF_WINDOWMOVE */
+  }
+
+  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) {
+    widgetptr = redraw_widgets;
+    for(i = 0; i < MAX_REDRAWWIDGETS; ++i) {
+      widget_redraw(*widgetptr);
+      *widgetptr = NULL;
+      ++widgetptr;
+    }
+  }    
+  redraw = 0;
+  redraw_widgetptr = 0;
+  
+}
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(ctk_eventhandler, ev, data)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+/** @} */
+/** @} */
+
diff --git a/contiki/ctk/ctk.h b/contiki/ctk/ctk.h
new file mode 100644
index 0000000..9707791
--- /dev/null
+++ b/contiki/ctk/ctk.h
@@ -0,0 +1,959 @@
+/**
+ * \addtogroup ctk
+ * @{
+ */
+
+/**
+ * \file
+ * CTK header file.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * The CTK header file contains functioin declarations and definitions
+ * of CTK structures and macros.
+ */
+
+/*
+ * Copyright (c) 2002-2003, 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. 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 OS.
+ *
+ * $Id: ctk.h,v 1.24 2005/05/05 20:54:16 oliverschmidt Exp $
+ *
+ */
+
+#ifndef __CTK_H__
+#define __CTK_H__
+
+
+#include "ctk-conf.h"
+#include "ctk-arch.h"
+#include "ek.h"
+
+#include "cc.h"
+
+/* Defintions for the CTK widget types. */
+
+/**
+ * \addtogroup ctkdraw
+ * @{
+ */
+
+/** Widget number: The CTK separator widget. */
+#define CTK_WIDGET_SEPARATOR 1
+/** Widget number: The CTK label widget. */
+#define CTK_WIDGET_LABEL     2
+/** Widget number: The CTK button widget. */
+#define CTK_WIDGET_BUTTON    3
+/** Widget number: The CTK hyperlink widget. */
+#define CTK_WIDGET_HYPERLINK 4
+/** Widget number: The CTK textentry widget. */
+#define CTK_WIDGET_TEXTENTRY 5
+/** Widget number: The CTK bitmap widget. */
+#define CTK_WIDGET_BITMAP    6
+/** Widget number: The CTK icon widget. */
+#define CTK_WIDGET_ICON      7
+
+/** @} */
+
+struct ctk_widget;
+
+#if CTK_CONF_WIDGET_FLAGS
+#define CTK_WIDGET_FLAG_INITIALIZER(x) x,
+#else
+#define CTK_WIDGET_FLAG_INITIALIZER(x)
+#endif
+
+/**
+ * \defgroup ctkappfunc CTK application functions
+ * @{
+ *
+ * The CTK functions used by an application program.
+ */
+
+/**
+ * Instantiating macro for the ctk_separator widget.
+ *
+ * This macro is used when instantiating a ctk_separator widget and is
+ * intended to be used together with a struct assignment like this:
+ \code
+  struct ctk_separator sep =
+         {CTK_SEPARATOR(0, 0, 23)};
+ \endcode
+ * \param x The x position of the widget, relative to the widget's
+ * window.
+ * \param y The y position of the widget, relative to the widget's
+ * window.
+ * \param w The widget's width.
+ */
+#define CTK_SEPARATOR(x, y, w) \
+ NULL, NULL, x, y, CTK_WIDGET_SEPARATOR, w, 1, CTK_WIDGET_FLAG_INITIALIZER(0) 
+struct ctk_separator {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+};
+
+/**
+ * Instantiating macro for the ctk_button widget.
+ *
+ * This macro is used when instantiating a ctk_button widget and is
+ * intended to be used together with a struct assignment like this:
+ \code
+  struct ctk_button but =
+         {CTK_BUTTON(0, 0, 2, "Ok")};
+ \endcode
+ * \param x The x position of the widget, relative to the widget's
+ * window.
+ * \param y The y position of the widget, relative to the widget's
+ * window.
+ * \param w The widget's width.
+ * \param text The button text.
+ */
+#define CTK_BUTTON(x, y, w, text) \
+ NULL, NULL, x, y, CTK_WIDGET_BUTTON, w, 1, CTK_WIDGET_FLAG_INITIALIZER(0) text
+struct ctk_button {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  char *text;
+};
+
+/**
+ * Instantiating macro for the ctk_label widget.
+ *
+ * This macro is used when instantiating a ctk_label widget and is
+ * intended to be used together with a struct assignment like this:
+ \code
+  struct ctk_label lab =
+         {CTK_LABEL(0, 0, 5, 1, "Label")};
+ \endcode
+ * \param x The x position of the widget, relative to the widget's
+ * window.
+ * \param y The y position of the widget, relative to the widget's
+ * window.
+ * \param w The widget's width.
+ * \param h The height of the label. 
+ * \param text The label text.
+ */
+#define CTK_LABEL(x, y, w, h, text) \
+ NULL, NULL, x, y, CTK_WIDGET_LABEL, w, h, CTK_WIDGET_FLAG_INITIALIZER(0) text,
+struct ctk_label {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  char *text;
+};
+
+/**
+ * Instantiating macro for the ctk_hyperlink widget.
+ *
+ * This macro is used when instantiating a ctk_hyperlink widget and is
+ * intended to be used together with a struct assignment like this:
+ \code
+  struct ctk_hyperlink hlink =
+         {CTK_HYPERLINK(0, 0, 7, "Contiki", "http://dunkels.com/adam/contiki/")};
+ \endcode
+ * \param x The x position of the widget, relative to the widget's
+ * window.
+ * \param y The y position of the widget, relative to the widget's
+ * window.
+ * \param w The widget's width.
+ * \param text The hyperlink text.
+ * \param url The hyperlink URL.
+ */
+#define CTK_HYPERLINK(x, y, w, text, url) \
+ NULL, NULL, x, y, CTK_WIDGET_HYPERLINK, w, 1, CTK_WIDGET_FLAG_INITIALIZER(0) text, url
+struct ctk_hyperlink {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  char *text;
+  char *url;
+};
+
+/* Editing modes of the CTK textentry widget. */
+#define CTK_TEXTENTRY_NORMAL 0 /**< \internal Textentry state: not
+				  edited. */
+#define CTK_TEXTENTRY_EDIT   1 /**< \internal Textentry state:
+				  currenly being edited. */
+
+/**
+ * Clears a text entry widget and sets the cursor to the start of the
+ * text line.
+ *
+ * \param e The text entry widget to be cleared.
+ */
+#define CTK_TEXTENTRY_CLEAR(e) \
+	do { memset((e)->text, 0, (e)->h * ((e)->len + 1)); \
+	     (e)->xpos = 0; (e)->ypos = 0; } while(0)
+
+typedef unsigned char (* ctk_textentry_input)(ctk_arch_key_t c,
+					      struct ctk_textentry *t);
+
+/**
+ * Instantiating macro for the ctk_textentry widget.
+ *
+ * This macro is used when instantiating a ctk_textentry widget and is
+ * intended to be used together with a struct assignment like this:
+ \code
+  struct ctk_textentry tentry =
+         {CTK_TEXTENTRY(0, 0, 30, 1, textbuffer, 50)};
+ \endcode
+ * \note The height of the text entry widget is obsolete and not
+ * intended to be used.
+ *
+ * \param x The x position of the widget, relative to the widget's
+ * window.
+ * \param y The y position of the widget, relative to the widget's
+ * window.
+ * \param w The widget's width.
+ * \param h The text entry height (obsolete).
+ * \param text A pointer to the buffer that should be edited.
+ * \param len The length of the text buffer
+ */
+#define CTK_TEXTENTRY(x, y, w, h, text, len) \
+  NULL, NULL, x, y, CTK_WIDGET_TEXTENTRY, w, 1, CTK_WIDGET_FLAG_INITIALIZER(0) text, len, \
+  CTK_TEXTENTRY_NORMAL, 0, 0, NULL
+#define CTK_TEXTENTRY_INPUT(x, y, w, h, text, len, input) \
+  NULL, NULL, x, y, CTK_WIDGET_TEXTENTRY, w, h, CTK_WIDGET_FLAG_INITIALIZER(0) text, len, \
+  CTK_TEXTENTRY_NORMAL, 0, 0, (ctk_textentry_input)input
+struct ctk_textentry {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  char *text;
+  unsigned char len;
+  unsigned char state;
+  unsigned char xpos, ypos;
+  ctk_textentry_input input;
+};
+
+
+#if CTK_CONF_ICON_BITMAPS
+#define CTK_ICON_BITMAP(bitmap)	  bitmap
+#else
+#define CTK_ICON_BITMAP(bitmap)	  NULL
+#endif
+
+#if CTK_CONF_ICON_TEXTMAPS
+#define CTK_ICON_TEXTMAP(textmap) textmap
+#else
+#define CTK_ICON_TEXTMAP(textmap) NULL
+#endif
+
+/**
+ * Instantiating macro for the ctk_icon widget.
+ *
+ * This macro is used when instantiating a ctk_icon widget and is
+ * intended to be used together with a struct assignment like this:
+ \code
+  struct ctk_icon icon =
+         {CTK_ICON("An icon", bitmapptr, textmapptr)};
+ \endcode
+ * \param title The icon's text.
+ * \param bitmap A pointer to the icon's bitmap image.
+ * \param textmap A pointer to the icon's text version of the bitmap.
+ */
+#define CTK_ICON(title, bitmap, textmap) \
+ NULL, NULL, 0, 0, CTK_WIDGET_ICON, 2, 4, CTK_WIDGET_FLAG_INITIALIZER(0) \
+ title, EK_ID_NONE, \
+ CTK_ICON_BITMAP(bitmap), CTK_ICON_TEXTMAP(textmap)
+struct ctk_icon {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  char *title;
+  ek_id_t owner;
+  unsigned char *bitmap;
+  char *textmap;
+};
+
+#define CTK_BITMAP(x, y, w, h, bitmap, bitmap_width, bitmap_height) \
+  NULL, NULL, x, y, CTK_WIDGET_BITMAP, w, h, \
+  CTK_WIDGET_FLAG_INITIALIZER(0) bitmap, bitmap_width, bitmap_height
+struct ctk_bitmap {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  unsigned char *bitmap;
+  unsigned short bw, bh;
+};
+
+#define CTK_TEXTMAP_NORMAL 0
+#define CTK_TEXTMAP_ACTIVE 1
+
+#define CTK_TEXTMAP(x, y, w, h, textmap) \
+ NULL, NULL, x, y, CTK_WIDGET_LABEL, w, h, CTK_WIDGET_FLAG_INITIALIZER(0) text, CTK_TEXTMAP_NORMAL
+struct ctk_textmap {
+  struct ctk_widget *next;
+  struct ctk_window *window;
+  unsigned char x, y;
+  unsigned char type;
+  unsigned char w, h;
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  char *textmap;
+  unsigned char state;
+};
+
+
+/**
+ * \internal The CTK button widget structure.
+ */
+struct ctk_widget_button {
+  char *text;  /**< The button text. */
+};
+
+/**
+ * \internal The CTK label widget structure.
+ */
+struct ctk_widget_label {
+  char *text; /**< The label text. */
+};
+
+/**
+ * \internal The CTK hyperlink widget structure.
+ */
+struct ctk_widget_hyperlink {
+  char *text; /**< The text of the hyperlink. */
+  char *url;  /**< The hyperlink's URL. */
+};
+
+struct ctk_widget_textentry {
+  char *text;
+  unsigned char len;
+  unsigned char state;
+  unsigned char xpos, ypos;
+  ctk_textentry_input input;
+};
+
+struct ctk_widget_icon {
+  char *title;
+  ek_id_t owner;
+  unsigned char *bitmap;
+  char *textmap;
+};
+
+struct ctk_widget_bitmap {
+  unsigned char *bitmap;
+  unsigned short bw, bh;  
+};
+/** @} */
+
+/**
+ * \addtogroup ctkdraw
+ * @{
+ */
+
+/**
+ * The generic CTK widget structure that contains all other widget
+ * structures.
+ *
+ * Since the widgets of a window are arranged on a linked list, the
+ * widget structure contains a next pointer which is used for this
+ * purpose. The widget structure also contains the placement and the
+ * size of the widget.
+ *
+ * Finally, the actual per-widget structure is contained in this
+ * top-level widget structure.
+ */
+struct ctk_widget {
+  struct ctk_widget *next;   /**< The next widget in the linked list
+				of widgets that is contained in the
+				ctk_window structure. */
+  struct ctk_window *window; /**< The window in which the widget is
+				contained. */
+  unsigned char x,           /**< The x position of the widget within
+				the containing window, in character
+				coordinates. */
+    y;                       /**< The y position of the widget within
+				the containing window, in character
+				coordinates. */
+  unsigned char type;        /**< The type of the widget:
+				CTK_WIDGET_SEPARATOR,
+				CTK_WIDGET_LABEL, CTK_WIDGET_BUTTON,
+				CTK_WIDGET_HYPERLINK,
+				CTK_WIDGET_TEXTENTRY,
+				CTK_WIDGET_BITMAP or
+				CTK_WIDGET_ICON. */
+  unsigned char w,           /**< The width of the widget in character
+				coordinates. */
+    h;                       /**< The height of the widget in
+				character coordinates. */
+#if CTK_CONF_WIDGET_FLAGS
+  unsigned char flags;
+#endif /* CTK_CONF_WIDGET_FLAGS */
+  
+  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;
+    struct ctk_widget_bitmap bitmap;
+  } widget;                  /**< The union which contains the actual
+				widget structure, as determined by the
+				type field. */
+};
+
+
+struct ctk_desktop;
+
+#define CTK_WIDGET_FLAG_NONE      0
+#define CTK_WIDGET_FLAG_MONOSPACE 1
+#define CTK_WIDGET_FLAG_CENTER    2
+
+#if CTK_CONF_WIDGET_FLAGS
+#define CTK_WIDGET_SET_FLAG(w, f) ((struct ctk_widget *)(w))->flags = (f)
+#else /* CTK_CONF_WIDGET_FLAGS */
+#define CTK_WIDGET_SET_FLAG(w, f)
+#endif /* CTK_CONF_WIDGET_FLAGS */
+
+/**
+ * Representation of a CTK window.
+ *
+ * For the CTK, each window is repessented by a ctk_window
+ * structure. All open windows are kept on a doubly linked list,
+ * linked by the next and prev fields in the ctk_window struct. The
+ * window structure holds all widgets that is contained in the window
+ * as well as a pointer to the currently selected widget.
+ * 
+ */
+struct ctk_window {
+  struct ctk_window *next,  /**< The next window in the doubly linked
+			       list of open windows. */
+
+    *prev;                  /**< The previous window in the doubly
+			       linked list of open windows. */
+  struct ctk_desktop *desktop;/**< The desktop on which this window is
+				 open. */
+  
+  ek_id_t owner;            /**< The process that owns the
+			       window. This process will be the
+			       receiver of all CTK signals that
+			       pertain to this window. */
+  
+  char *title;              /**< The title of the window. Used for
+			       constructing the "Dekstop" menu. */
+  unsigned char titlelen;   /**< The length of the title, cached for
+			       speed reasons. */
+
+#if CTK_CONF_WINDOWCLOSE
+  struct ctk_button closebutton; /**< The closebutton. This is also
+				    present in the list of active
+				    widgets. */
+#else /* CTK_CONF_WINDOWCLOSE */
+  struct ctk_label closebutton;
+#endif /* CTK_CONF_WINDOWCLOSE */
+  
+#if CTK_CONF_WINDOWMOVE
+  struct ctk_button titlebutton;/**< The titlebutton which is used for
+				     moving the window. This is also
+				     present in the list of active
+				     widgets. */
+#else /* CTK_CONF_WINDOWMOVE */
+  struct ctk_label titlebutton;
+#endif /* CTK_CONF_WINDOWMOVE */
+
+  unsigned char x,             /**< The x coordinate of the window, in
+				  characters. */    
+    y;                         /**< The y coordinate of the window, in
+				  characters. */
+  unsigned char w,             /**< The width of the window, excluding
+				  window borders. */
+    h;                         /**< The height of the window,
+				  excluding window borders. */
+
+
+  struct ctk_widget *inactive; /**< The list if widgets that cannot be
+				  selected by the user. Labels and
+				  separator widgets are placed on this
+				  list. */
+  struct ctk_widget *active;   /**< The list of widgets that can be
+				  selected by the user. Buttons,
+				  hyperlinks, text entry fields, etc.,
+				  are placed on this list. */
+  struct ctk_widget *focused;  /**< A pointer to the widget on the
+				  active list that is currently
+				  selected, or NULL if no widget is
+				  selected. */
+};
+
+/**
+ * Representation of an individual menu item.
+ */
+struct ctk_menuitem {
+  char *title;           /**< The menu items text. */
+  unsigned char titlelen;/**< The length of the item text, cached for
+			    speed. */
+};
+
+/**
+ * Representation of an individual menu.
+ */
+struct ctk_menu {
+  struct ctk_menu *next; /**< Apointer to the next menu, or is NULL if
+			    this is the last menu, and should be used
+			    by the ctk-draw module when stepping
+			    through the menus when drawing them on
+			    screen. */
+  char *title;           /**< The menu title. */
+  unsigned char titlelen;/**< The length of the title in
+			    characters. Cached for speed reasons. */
+#if CC_UNSIGNED_CHAR_BUGS
+  unsigned int nitems;
+  unsigned int active;
+#else /* CC_UNSIGNED_CHAR_BUGS */
+  unsigned char nitems;  /**< The total number of menu items in the
+			    menu. */
+  unsigned char active;  /**< The currently active menu item. */
+#endif /* CC_UNSIGNED_CHAR_BUGS */
+  struct ctk_menuitem items[CTK_CONF_MAXMENUITEMS];
+                         /**< The array which contains all the menu
+			    items. */
+};
+
+/**
+ * Representation of the menu bar.
+ */
+struct ctk_menus {
+  struct ctk_menu *menus;       /**< A pointer to a linked list of all
+				   menus, including the open menu and
+				   the desktop menu.*/
+  struct ctk_menu *open;        /**< The currently open menu, if
+				   any. If all menus are closed, this
+				   item is NULL: */
+  struct ctk_menu *desktopmenu; /**< A pointer to the "Desktop" menu
+				   that can be used for drawing the
+				   desktop menu in a special way (such
+				   as drawing it at the rightmost
+				   position). */ 
+};
+
+/** @} */
+
+
+/**
+ * \internal The structure describing a Contiki desktop.
+ */
+struct ctk_desktop {
+  char *name; /**< The name of the desktop. */
+   
+  struct ctk_window desktop_window; /**< The background window which
+				       contains tha desktop icons. */
+  struct ctk_window *windows; /**< The list of open windows. */
+  struct ctk_window *dialog;  /**< A pointer to the open dialog, or
+				 NULL if no dialog is open. */
+  
+#if CTK_CONF_MENUS
+  struct ctk_menus menus;     /**< The list of desktop menus. */
+  struct ctk_menu *lastmenu;  /**< Pointer to the menu that was last open. */
+  struct ctk_menu desktopmenu;/**< The desktop menu. */
+#endif /* CTK_CONF_MENUS */
+
+  unsigned char height, /**< The height of the desktop, in characters. */
+    width; /**< The width of the desktop, in characters. */
+
+  
+#define CTK_REDRAW_NONE         0 /**< \internal Redraw flag: nothing
+				     to be redrawn. */
+#define CTK_REDRAW_ALL          1 /**< \internal Redraw flag:
+				     everything should be redrawn. */
+#define CTK_REDRAW_WINDOWS      2 /**< \internal Redraw flag: redraw
+				     windows in queue.*/
+#define CTK_REDRAW_WIDGETS      4 /**< \internal Redraw flag: redraw
+				     widgets in queue. */
+#define CTK_REDRAW_MENUS        8 /**< \internal Redraw flag: redraw
+				     menus. */
+#define CTK_REDRAW_PART        16 /**< \internal Redraw flag: redraw
+				     parts of the desktop. */
+
+#ifndef CTK_CONF_MAX_REDRAWWIDGETS
+#define CTK_CONF_MAX_REDRAWWIDGETS 8
+#endif /* CTK_CONF_MAX_REDRAWWIDGETS */
+#ifndef CTK_CONF_MAX_REDRAWWINDOWS
+#define CTK_CONF_MAX_REDRAWWINDOWS 8
+#endif /* CTK_CONF_MAX_REDRAWWINDOWS */
+  
+  unsigned char redraw; /**< The redraw flag. */
+  
+  struct ctk_widget *redraw_widgets[CTK_CONF_MAX_REDRAWWIDGETS]; /**< The list of widgets to be redrawn. */
+  unsigned char redraw_widgetptr; /**< Pointer to the last widget on the redraw_widgets list. */
+
+  struct ctk_window *redraw_windows[CTK_CONF_MAX_REDRAWWINDOWS]; /**< The list of windows to be redrawn. */
+  unsigned char redraw_windowptr; /**< Pointer to the last window on the redraw_windows list. */
+
+   unsigned char redraw_y1, /**< The lower y bound of the area to be redrawn if CTK_REDRAW_PART is flagged. */
+    redraw_y2; /**< The upper y bound of the area to be redrawn if CTK_REDRAW_PART is flagged. */
+};
+
+
+/* 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_restore(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. */
+
+/**
+ * \addtogroup ctkappfunc
+ * @{
+ */
+/**
+ * Add an icon to the desktop.
+ *
+ * \param icon The icon to be added.
+ *
+ * \param id The process ID of the process that owns the icon.
+ */
+#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. */
+
+/**
+ * Add a widget to a window.
+ *
+ * \param win The window to which the widget should be added.
+ * \param widg The widget to be added.
+ */
+#define CTK_WIDGET_ADD(win, widg) \
+ ctk_widget_add(win, (struct ctk_widget *)widg)
+void CC_FASTCALL ctk_widget_add(struct ctk_window *window,
+				struct ctk_widget *widget);
+
+/**
+ * Set focus to a widget. 
+ *
+ * \param win The widget's window.
+ * \param widg The widget
+ */
+#define CTK_WIDGET_FOCUS(win, widg) \
+  (win)->focused = (struct ctk_widget *)(widg)
+
+/**
+ * Add a widget to the redraw queue.
+ *
+ * \param widg The widget to be redrawn.
+ */
+#define CTK_WIDGET_REDRAW(widg) \
+ ctk_widget_redraw((struct ctk_widget *)widg)
+void ctk_widget_redraw(struct ctk_widget *w);
+
+/**
+ * Obtain the type of a widget.
+ *
+ * \param w The widget.
+ */
+#define CTK_WIDGET_TYPE(w) ((w)->type)
+
+
+/**
+ * Sets the width of a widget.
+ *
+ * \param widget The widget.
+ * \param width The width of the widget, in characters.
+ */
+#define CTK_WIDGET_SET_WIDTH(widget, width) do { \
+    ((struct ctk_widget *)(widget))->w = (width); } while(0)
+
+/**
+ * Retrieves the x position of a widget, relative to the window in
+ * which the widget is contained.
+ *
+ * \param w The widget.
+ * \return The x position of the widget.
+ */
+#define CTK_WIDGET_XPOS(w) (((struct ctk_widget *)(w))->x)
+
+/**
+ * Sets the x position of a widget, relative to the window in
+ * which the widget is contained.
+ *
+ * \param w The widget.
+ * \param xpos The x position of the widget.
+ */
+#define CTK_WIDGET_SET_XPOS(w, xpos) \
+        ((struct ctk_widget *)(w))->x = (xpos)
+/**
+ * Retrieves the y position of a widget, relative to the window in
+ * which the widget is contained.
+ *
+ * \param w The widget.
+ * \return The y position of the widget.
+ */
+#define CTK_WIDGET_YPOS(w) (((struct ctk_widget *)(w))->y)
+
+/**
+ * Sets the y position of a widget, relative to the window in
+ * which the widget is contained.
+ *
+ * \param w The widget.
+ * \param ypos The y position of the widget.
+ */
+#define CTK_WIDGET_SET_YPOS(w, ypos) \
+        ((struct ctk_widget *)(w))->y = (ypos)
+
+/* XXX: should be removed.
+#define ctk_textentry_set_height(w, height) \
+                           (w)->widget.textentry.h = (height)
+*/
+
+/** \def ctk_label_set_height(w, height)
+ * \brief Set the height of a label.
+ *
+ * \param w The CTK label widget.
+ * \param height The new height of the label.
+ */
+#define ctk_label_set_height(w, height) \
+                           (w)->widget.label.h = (height)
+
+/**
+ * Set the text of a label.
+ *
+ * \param l The CTK label widget.
+ * \param t The new text of the label.
+ */
+#define ctk_label_set_text(l, t) (l)->text = (t)
+
+/**
+ * Set the text of a button.
+ *
+ * \param b The CTK button widget.
+ * \param t The new text of the button.
+ */
+#define ctk_button_set_text(b, t) (b)->text = (t)
+
+#define ctk_bitmap_set_bitmap(b, m) (b)->bitmap = (m)
+
+#define CTK_BUTTON_NEW(widg, xpos, ypos, width, buttontext) \
+ do { (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_BUTTON; \
+ (widg)->x = (xpos); \
+ (widg)->y = (ypos); \
+ (widg)->w = (width); \
+ (widg)->h = 1; \
+ (widg)->text = (buttontext); \
+ } while(0)
+
+#define CTK_LABEL_NEW(widg, xpos, ypos, width, height, labeltext) \
+ do { (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); \
+ } while(0)
+
+#define CTK_BITMAP_NEW(widg, xpos, ypos, width, height, bmap) \
+ do { (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_BITMAP; \
+ (widg)->x = (xpos); \
+ (widg)->y = (ypos); \
+ (widg)->w = (width); \
+ (widg)->h = (height); \
+ (widg)->bitmap = (bmap); \
+ } while(0)
+
+#define CTK_TEXTENTRY_NEW(widg, xxpos, yypos, width, height, textptr, textlen) \
+ do { (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_TEXTENTRY; \
+ (widg)->x = (xxpos); \
+ (widg)->y = (yypos); \
+ (widg)->w = (width); \
+ (widg)->h = 1; \
+ (widg)->text = (textptr); \
+ (widg)->len = (textlen); \
+ (widg)->state = CTK_TEXTENTRY_NORMAL; \
+ (widg)->xpos = 0; \
+ (widg)->ypos = 0; \
+ (widg)->input = NULL; \
+ } while(0)
+
+#define CTK_TEXTENTRY_INPUT_NEW(widg, xxpos, yypos, width, height, textptr, textlen, iinput) \
+ do { (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; \
+ (widg)->input = (ctk_textentry_input)(iinput); \
+ } while(0)
+
+#define CTK_HYPERLINK_NEW(widg, xpos, ypos, width, linktext, linkurl) \
+ do { (widg)->window = NULL; \
+ (widg)->next = NULL; \
+ (widg)->type = CTK_WIDGET_HYPERLINK; \
+ (widg)->x = (xpos); \
+ (widg)->y = (ypos); \
+ (widg)->w = (width); \
+ (widg)->h = 1; \
+ (widg)->text = (linktext); \
+ (widg)->url = (linkurl); \
+ } while(0)
+
+/* Desktop interface. */
+void ctk_desktop_redraw(struct ctk_desktop *d);
+unsigned char ctk_desktop_width(struct ctk_desktop *d);
+unsigned char ctk_desktop_height(struct ctk_desktop *d);
+
+/* Signals. */
+extern ek_event_t ctk_signal_keypress,
+  ctk_signal_widget_activate,
+  ctk_signal_widget_select,
+  ctk_signal_timer,
+  ctk_signal_menu_activate,
+  ctk_signal_window_close,
+  ctk_signal_pointer_move,
+  ctk_signal_pointer_button;
+
+#if CTK_CONF_SCREENSAVER
+extern ek_event_t ctk_signal_screensaver_stop,
+  ctk_signal_screensaver_start;
+
+extern unsigned short ctk_screensaver_timeout;
+/**
+ * Set the screensaver timeout, in seconds.
+ *
+ * \param t The timeout in seconds.
+ */
+#define CTK_SCREENSAVER_SET_TIMEOUT(t) ctk_screensaver_timeout = (t)
+/**
+ * Obtain the screensaver timeout, in seconds.
+ *
+ * \raturn The timeout in seconds.
+ */
+#define CTK_SCREENSAVER_TIMEOUT() ctk_screensaver_timeout
+#endif /* CTK_CONF_SCREENSAVER */
+
+/* These should no longer be used: */
+extern ek_event_t ctk_signal_button_activate,
+  ctk_signal_button_hover,
+  ctk_signal_hyperlink_activate,
+  ctk_signal_hyperlink_hover;
+/** @} */
+
+/**
+ * \addtogroup ctkdraw
+ * @{
+ */
+
+/* Focus flags */
+/** Widget focus flag: no focus. */
+#define CTK_FOCUS_NONE     0
+/** Widget focus flag: widget has focus. */
+#define CTK_FOCUS_WIDGET   1
+/** Widget focus flag: widget's window is the foremost one. */
+#define CTK_FOCUS_WINDOW   2
+/** Widget focus flag: widget is in a dialog. */
+#define CTK_FOCUS_DIALOG   4
+
+/** @} */
+/** @} */
+#endif /* __CTK_H__ */
diff --git a/contiki/ctk/vnc-out.c b/contiki/ctk/vnc-out.c
new file mode 100644
index 0000000..efc46c1
--- /dev/null
+++ b/contiki/ctk/vnc-out.c
@@ -0,0 +1,983 @@
+/*
+ * 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. 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: vnc-out.c,v 1.7 2004/09/01 18:18:39 adamdunkels Exp $
+ *
+ */
+
+#include "uip.h"
+#include "vnc-server.h"
+#include "vnc-out.h"
+
+#include "libconio.h"
+
+#include "ctk-vncserver-conf.h"
+
+#include "ctk-vncfont.h"
+
+#include "ctk-arch.h"
+
+#include "ctk-mouse.h"
+
+#ifdef WITH_AVR
+#include <avr/pgmspace.h>
+#else
+#define memcpy_P memcpy
+#endif /* WITH_AVR */
+
+#define CHARS_WIDTH    LIBCONIO_CONF_SCREEN_WIDTH
+#define CHARS_HEIGHT   LIBCONIO_CONF_SCREEN_HEIGHT
+
+#define SCREEN_X       10
+#define SCREEN_Y       8
+
+#define SCREEN_WIDTH  (CHARS_WIDTH * CTK_VNCFONT_WIDTH + 2 * SCREEN_X) /*420*/
+#define SCREEN_HEIGHT (CHARS_HEIGHT * CTK_VNCFONT_HEIGHT + 2 * SCREEN_Y) /*300*/
+#define BORDER_COLOR 0x00
+#define SCREEN_COLOR 0x00 /*0xc0*/
+
+#ifndef CH_HOME
+#define CH_HOME 0x50
+#endif 
+
+#ifndef CH_TAB
+#define CH_TAB  0x09
+#endif
+
+
+#define BGR(b,g,r) (((b) << 6) | (g) << 3 | (r))
+
+
+static const u8_t menucolor[] = {
+  BGR(3,7,7), /* Background. */           
+  BGR(2,6,6), /* Anti-alias font color. */ 
+  BGR(0,0,0), /* Font color. */            
+};
+
+
+static const u8_t activemenucolor[] = {
+  BGR(0,0,0), /* Background. */           
+  BGR(2,5,5), /* Anti-alias font color. */ 
+  BGR(3,7,7), /* Font color. */            
+};
+
+#define W  BGR(3,7,7)
+#define B  BGR(0,0,0)
+#define G0 BGR(0,2,2)
+#define G1 BGR(1,2,2)
+#define G2 BGR(1,3,3)
+#define G3 BGR(2,4,4)
+#define G4 BGR(2,5,5)
+#define G5 BGR(2,6,6)
+
+#define BG BGR(3,4,4)
+
+static const unsigned char backgroundcolor[] = {BG};
+
+static const unsigned char wincol[] =
+  {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),G2,G3,G4};
+  /*  {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),BGR(1,0,0),BGR(2,0,0),BGR(2,1,1)}; */
+static const unsigned char wincol_f[] =
+  {BGR(3,7,7),BGR(1,2,2),BGR(0,1,1),G4,G5,W};
+  /*  {BGR(3,7,7),BGR(1,2,2),BGR(0,1,1),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)}; */
+static const unsigned char wincol_d[] =
+  {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)};
+
+static const unsigned char sepcol[] =
+ {BGR(2,5,5),BGR(2,6,6),BGR(3,6,6)};
+static const unsigned char sepcol_f[] =
+ {BGR(3,7,7),BGR(3,5,5),BGR(2,5,5)};
+static const unsigned char sepcol_d[] =
+ {BGR(3,7,7),BGR(1,5,7),BGR(0,0,0)};
+
+static const unsigned char labcol[] =
+ {BGR(2,5,5),BGR(1,3,3),BGR(0,1,1)};
+static const unsigned char labcol_f[] =
+ {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0)};
+static const unsigned char labcol_d[] =
+ {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0)};
+
+
+static const unsigned char butcol[] =
+ {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
+  BGR(2,5,5),BGR(2,5,5)};
+static const unsigned char butcol_w[] =
+ {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
+  BGR(2,5,5),BGR(2,5,5)};
+static const unsigned char butcol_f[] =
+ {G5,G4,B,BGR(3,5,5),BGR(3,6,6),BGR(3,7,7),
+  BGR(3,6,6),BGR(2,5,5)};
+static const unsigned char butcol_fw[] =
+ {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0),BGR(1,3,3),BGR(2,7,7),BGR(3,7,7),
+  BGR(3,6,6),BGR(3,7,7)};
+static const unsigned char butcol_d[] =
+ {BGR(2,3,3),BGR(2,5,5),BGR(3,6,6),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
+  BGR(3,7,7),BGR(2,5,5)};
+static const unsigned char butcol_dw[] =
+ {BGR(0,0,0),BGR(2,5,5),BGR(3,7,7),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
+  BGR(3,7,7),BGR(2,5,5)};
+
+
+static const unsigned char hlcol[] =
+ {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
+static const unsigned char hlcol_w[] =
+ {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
+static const unsigned char hlcol_f[] =
+ {BGR(3,7,7),BGR(3,5,5),BGR(3,0,0)};
+static const unsigned char hlcol_fw[] =
+ {BGR(3,7,7),BGR(3,6,7),BGR(3,7,7)};
+static const unsigned char hlcol_d[] =
+ {BGR(3,7,7),BGR(3,5,5),BGR(2,0,0)};
+static const unsigned char hlcol_dw[] =
+ {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0)};
+
+static const unsigned char iconcol[] =
+  {BG,G4,W,B,G1};
+static const unsigned char iconcol_w[] =
+ {BGR(0,1,1),BGR(1,3,3),BGR(3,7,7), B,W};
+
+
+
+static const u8_t * const colortheme[] =
+  {
+    backgroundcolor,
+    
+    /* Window colors */
+    wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d,
+
+    /* Separator colors. */
+    sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d,    
+
+    /* Label colors. */
+    labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d,    
+
+    /* Button colors. */
+    butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,    
+
+    /* Hyperlink colors. */
+    hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw,
+
+    /* Textentry colors. */
+    butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
+
+    /* Icon colors */
+    iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w,
+    
+    /* Menu colors. */
+    menucolor, activemenucolor, activemenucolor
+  };
+
+
+static int mouse_x, mouse_y, mouse_button;
+
+#ifdef CTK_VNCSERVER_CONF_SCREEN
+static u8_t *screen = CTK_VNCSERVER_CONF_SCREEN;
+#else
+static u8_t screen[CHARS_WIDTH * CHARS_HEIGHT];
+#endif
+
+#ifdef CTK_VNCSERVER_CONF_COLORSCREEN
+staitc u8_t *colorscreen = CTK_VNCSERVER_CONF_COLORSCREEN;
+#else
+static u8_t colorscreen[CHARS_WIDTH * CHARS_HEIGHT];
+#endif
+
+
+#define PRINTF(x)
+
+/*-----------------------------------------------------------------------------------*/
+#define MAX_ICONS CTK_VNCSERVER_CONF_MAX_ICONS
+struct ctk_icon *icons[MAX_ICONS];
+
+unsigned char
+vnc_out_add_icon(struct ctk_icon *icon)
+{
+  u8_t i;
+  signed int empty;
+
+  empty = -1;
+  for(i = 0; i < MAX_ICONS; ++i) {
+    if(icon == icons[i]) {
+      return i;
+    }
+    if(icons[i] == NULL && empty < 0){
+      empty = i;
+    }
+  }
+
+  if(empty == -1) {
+    empty = 0;
+  }
+  icons[empty] = icon;
+  return empty;
+}
+
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_init(void)
+{
+  u16_t i;
+  for(i = 0; i < CHARS_WIDTH * CHARS_HEIGHT; ++i) {
+    screen[i] = 0x20;
+  }
+}
+
+void
+vnc_out_update_screen(u8_t xpos, u8_t ypos, u8_t c, u8_t color)
+{
+  screen[xpos + ypos * CHARS_WIDTH] = c;
+  colorscreen[xpos + ypos * CHARS_WIDTH] = color;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_update_area(struct vnc_server_state *vs,
+		    u8_t x, u8_t y, u8_t w, u8_t h)
+{
+  u8_t x2, y2, ax2, ay2;
+  register struct vnc_server_update *a, *b;
+
+  PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",
+	 x, y, w, h));
+  
+  /* First check if we already have a full update queued. If so, there
+     is no need to put this update on the list. If there is a full
+     update, it is always the first one on the list, so there is no
+     need to go step the list in search for it. */
+
+  if(vs->updates_pending != NULL &&
+     vs->updates_pending->type == VNC_SERVER_UPDATE_FULL) {
+    PRINTF(("Update_area_connecion: full update already queued...\n"));
+    return;
+  }
+
+ again:
+  
+  /* Check that we don't update the same area twice by going through
+     the list and search for an update with the same coordinates. */
+  for(a = vs->updates_pending; a != NULL; a = a->next) {
+    if(a->x == x && a->y == y &&
+       a->w == w && a->h == h) {
+      PRINTF(("Update_area_connecion: found equal area\n"));
+      return;
+    }    
+  }
+
+  /* Next we check if this update covers an existing update. If so, we
+     remove the old update, expand this update so that it covers both
+     areas to be updated and run through the process again. */
+  b = NULL;
+  for(a = vs->updates_pending; a != NULL; a = a->next) {      
+    x2 = x + w;
+    y2 = y + h;
+    
+    ax2 = a->x + a->w;
+    ay2 = a->y + a->h;
+
+    /* Test the corners of both updates to see if they are inside the
+       other area. */
+#define INSIDE(x,y,x1,y1,x2,y2) ((x1) <= (x) && \
+                                 (x2) >= (x) && \
+                                 (y1) <= (y) && \
+                                 (y2) >= (y))
+    if(INSIDE(x, y, a->x, a->y, ax2, ay2) ||
+       INSIDE(x, y2, a->x, a->y, ax2, ay2) ||
+       INSIDE(x2, y2, a->x, a->y, ax2, ay2) ||
+       INSIDE(x2, y, a->x, a->y, ax2, ay2) ||
+       INSIDE(a->x, a->y, x, y, x2, y2) ||
+       INSIDE(a->x, ay2, x, y, x2, y2) ||
+       INSIDE(ax2, ay2, x, y, x2, y2) ||
+       INSIDE(ax2, a->y, x, y, x2, y2)) {
+
+      /* Remove the old update from the list. */
+      vnc_server_update_remove(vs, a);
+
+      /* Put it on the free list. */
+      vnc_server_update_free(vs, a);
+
+      PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",
+	     a->x, a->y, ax2, ay2));
+      
+      /* Find the area that covers both updates. */
+#define MIN(a,b) ((a) < (b)? (a): (b))
+#define MAX(a,b) ((a) > (b)? (a): (b))
+      x = MIN(a->x, x);
+      y = MIN(a->y, y);
+      ax2 = MAX(ax2, x2);
+      ay2 = MAX(ay2, y2);
+      w = ax2 - x;
+      h = ay2 - y;
+
+      /* This should really be done by a recursive call to this
+	 function: update_area_connection(vs, x, y, w, h); but because
+	 some compilers might not be able to optimize away the
+	 recursive call, we do it using a goto instead. */
+      PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));
+      goto again;
+    }
+    if(b != NULL) {
+      b = b->next;
+    }
+  }
+  
+  /* Allocate an update object by pulling it off the free list. If
+     there are no free objects, we go for a full update instead. */
+
+  /*  a = vs->updates_free;*/
+  a = vnc_server_update_alloc(vs);
+  if(a == NULL) {
+    PRINTF(("Update_area_connecion: no free updates, doing full\n"));
+    /* Put all pending updates, except for one, on the free list. Use
+       the remaining update as a full update. */
+    while(vs->updates_pending != NULL) {
+      a = vs->updates_pending;
+      vnc_server_update_remove(vs, a);
+      vnc_server_update_free(vs, a);
+    }
+
+    a = vnc_server_update_alloc(vs);
+    a->type = VNC_SERVER_UPDATE_FULL;
+    vnc_server_update_add(vs, a);
+					
+
+  } else {
+    
+    PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));
+  /* Else, we put the update object at the end of the pending
+     list. */
+    a->type = VNC_SERVER_UPDATE_PARTS;
+    a->x = x;
+    a->y = y;
+    a->w = w;
+    a->h = h;
+    vnc_server_update_add(vs, a);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+init_send_screen(register struct vnc_server_state *vs)
+{
+  vs->sendmsg = SEND_SCREEN;
+  vs->x = vs->y = 0;
+  vs->x1 = vs->y1 = 0;
+  vs->x2 = vs->y2 = 0;
+  vs->w = CHARS_WIDTH;
+  vs->h = CHARS_HEIGHT;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+check_updates(register struct vnc_server_state *vs)
+{
+  
+  if(vs->state == VNC_RUNNING &&
+     vs->sendmsg == SEND_NONE &&
+     vs->updates_current == NULL) {
+    if(vs->updates_pending != NULL &&
+       vs->update_requested != 0) {
+      vs->update_requested = 0;
+      /*      vs->updates_current = vs->updates_pending;
+      vs->updates_pending = vs->updates_pending->next;
+      vs->updates_current->next = NULL;*/
+
+      vs->updates_current = vnc_server_update_dequeue(vs);
+      
+      if(vs->updates_current->type == VNC_SERVER_UPDATE_PARTS) {
+	vs->x = vs->x1 = vs->x2 = vs->updates_current->x;
+	vs->y = vs->y1 = vs->y2 = vs->updates_current->y;
+	vs->w = vs->updates_current->w;
+	vs->h = vs->updates_current->h;
+	vs->sendmsg = SEND_UPDATE;
+	
+	PRINTF(("New update from (%d:%d) (%d:%d) to (%d:%d)\n",
+	       vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
+	       vs->y + vs->h));
+      } else if(vs->updates_current->type == VNC_SERVER_UPDATE_FULL) {
+	init_send_screen(vs);
+	PRINTF(("New full update\n"));
+      }
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static u8_t tmp[CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT];
+static void
+makechar(CC_REGISTER_ARG char *ptr, u8_t x, u8_t y)
+{
+  u8_t i, *tmpptr;
+  register u8_t *colorscheme;
+  unsigned char *bitmap;
+  u8_t b, b2;
+  u8_t xmove, ymove;
+  unsigned char c, color;
+
+  color = colorscreen[x + y * CHARS_WIDTH];
+  c = screen[x + y * CHARS_WIDTH];
+
+  colorscheme = (u8_t *)colortheme[color];
+      
+  /* First check if the character is a special icon character. These
+     are to be interpreted in a special manner: the first character of
+     the icon (the top left corner) has the highest bit set, but not
+     bit 6. All other characters have bit 6 set, and also count the
+     number of positions away from the top left corner. Only the top
+     left corner contains enough information to identify the icon, all
+     other chars only contain the number of steps to reach the
+     identifying icon. */
+  if((c & 0x80) != 0) {
+    xmove = c & 0x0f;
+    ymove = (c & 0x30) >> 4;
+    
+    c = colorscreen[x + y * CHARS_WIDTH];
+
+    if(icons[c % MAX_ICONS] == NULL) {
+      c = 0;
+    }
+    bitmap = icons[c % MAX_ICONS]->bitmap;
+
+    if(bitmap != NULL) {
+      bitmap = bitmap + ymove * 8*3;
+      colorscheme = (u8_t *)colortheme[VNC_OUT_ICONCOLOR + (c >> 6)];
+      switch(xmove) {
+      case 0:
+	for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
+	  b = bitmap[i];
+	  *ptr++ = colorscheme[((b >> 7) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 6) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 5) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 4) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];		
+	}
+	break;
+      case 1:
+	for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
+	  b = bitmap[i];
+	  b2 = bitmap[i + 8];
+	  *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b2 >> 7) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b2 >> 6) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b2 >> 5) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b2 >> 4) & 0x01) << 2];		
+	}
+	break;
+      case 2:
+	for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
+	  b = bitmap[i + 8];
+	  b2 = bitmap[i + 16];
+	  *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b2 >> 7) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b2 >> 6) & 0x01) << 2];		
+	}
+	break;
+      case 3:
+	for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
+	  b = bitmap[i + 16];
+	  *ptr++ = colorscheme[((b >> 5) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 4) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
+	  *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];		
+	}
+	break;
+      }
+    }
+  } else {
+    memcpy_P(tmp, &ctk_vncfont[c * (CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT)],
+	     CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT);
+    
+    tmpptr = tmp;
+
+    
+    for(i = 0; i < CTK_VNCFONT_HEIGHT * CTK_VNCFONT_WIDTH; ++i) {
+      *ptr++ = colorscheme[*tmpptr++];
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_new(register struct vnc_server_state *vs)
+{
+  u8_t i;
+  
+  vs->width = SCREEN_WIDTH;
+  vs->height = SCREEN_HEIGHT;
+  vs->x = vs->y = vs->x1 = vs->y1 = vs->x2 = vs->y2 = 0;
+  vs->w = CHARS_WIDTH;
+  vs->h = CHARS_HEIGHT;
+
+  /* Initialize the linked list of updates. */
+  for(i = 0; i < VNC_SERVER_MAX_UPDATES - 1; ++i) {
+    vs->updates_pool[i].next = &vs->updates_pool[i + 1];    
+  }
+  vs->updates_pool[VNC_SERVER_MAX_UPDATES].next = NULL;
+
+  vs->updates_free = &vs->updates_pool[0];
+  vs->updates_pending = vs->updates_current = NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_send_blank(register struct vnc_server_state *vs)
+{
+  register struct rfb_fb_update *umsg;
+  u8_t *ptr;
+  u16_t len;
+  u8_t msglen;
+      
+  vs->x = vs->y = 0;
+  vs->x2 = vs->y2 = 0;
+	  
+  umsg = (struct rfb_fb_update *)uip_appdata;
+  
+  umsg->type = RFB_FB_UPDATE;
+  umsg->rects = HTONS(2);
+
+  ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
+  len = sizeof(struct rfb_fb_update);
+  
+  msglen = vnc_server_draw_rect(ptr, 0, 0,
+				HTONS(SCREEN_WIDTH),
+				HTONS(SCREEN_HEIGHT),
+				BORDER_COLOR);
+
+  
+  ptr += msglen;
+  len += msglen;
+
+  msglen = vnc_server_draw_rect(ptr,
+				HTONS(SCREEN_X), HTONS(SCREEN_Y),
+				HTONS(SCREEN_WIDTH - SCREEN_X * 2),
+				HTONS(SCREEN_HEIGHT - SCREEN_Y * 2),
+				SCREEN_COLOR);
+
+  uip_send(uip_appdata, len + msglen);
+
+  vs->sendmsg = SENT_BLANK;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_send_screen(struct vnc_server_state *vs)
+{
+  vnc_out_send_update(vs);
+}
+/*-----------------------------------------------------------------------------------*/
+static short tmpbuf[30];
+void
+vnc_out_send_update(register struct vnc_server_state *vs)
+{
+  u8_t x, y, x0;
+  u8_t msglen;
+  u16_t len, n;
+  u8_t *ptr;
+  struct rfb_fb_update *umsg;
+  register struct rfb_fb_update_rect_hdr *recthdr;
+  struct rfb_rre_hdr *rrehdr;
+  u8_t c, color, lastcolor;
+  u8_t numblanks;
+
+  /* First, check if we need to feed the update function with a new
+     pending update. */
+  check_updates(vs);
+
+  /*  PRINTF(("Sending Update from (%d:%d) (%d:%d) to (%d:%d)\n",
+	 vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
+	 vs->y + vs->h));*/
+  
+  umsg = (struct rfb_fb_update *)uip_appdata;
+
+  umsg->type = RFB_FB_UPDATE;
+
+  x0 = vs->x1;
+  n = 0;
+  msglen = 0;
+  ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
+  len = sizeof(struct rfb_fb_update);
+  
+  /* Loop over all characters that are covered by this update. */
+  for(y = vs->y1; y < vs->y + vs->h; ++y) {
+    for(x = x0; x < vs->x + vs->w; ++x) {
+
+
+      /* First check if there are any blank space characters, and if
+	 so, find out how many of them there are in a row. Instead of
+	 sending the individual space characters as raw bitmaps, we
+	 can send the entire string of blanks as a single color
+	 rectangle instead. */
+      
+      c = screen[x + y * CHARS_WIDTH];
+      numblanks = 0;
+      lastcolor = color = colorscreen[x + y * CHARS_WIDTH];
+
+      /* If the character is a blank, we continue reading characters
+	 until we find one that has a different color, or one that is
+	 not a blank. We must keep within the update rectangle, so we
+	 make sure that the "x" variable does not increase beyond the
+	 edge. The "numblanks" variable is used to keep track of how
+	 many blank characters we have found. */
+      while(lastcolor == color &&
+	    c == 0x20 &&
+	    x < vs->x + vs->w) {
+	++numblanks;
+
+	
+	++x;
+	lastcolor = color;
+	color = colorscreen[x + y * CHARS_WIDTH];
+	c = screen[x + y * CHARS_WIDTH];
+      }
+
+      if(numblanks > 0) {
+	
+	/*	PRINTF(("Found %d blanks (%d:%d -> %d:%d)\n",
+		numblanks, x - numblanks, y, x, y));*/
+	
+	/* There were one or more blank characters, so we send out a
+	   single color rectangle with the right width. But first we
+	   make sure that there is enough space in the current TCP
+	   segment to put the rectangle. If there isn't we have to
+	   backtrack the "x" variable to where we found the first
+	   blank character so that the next TCP segment will be able
+	   to update this area instead. */	
+
+	msglen = sizeof(struct rfb_fb_update_rect_hdr) +
+	  /*sizeof(struct rfb_rre_hdr)*/5;
+
+	if(msglen >= uip_mss() - len) {
+	  /*	  PRINTF(("Not enouch space for blanks (%d, left %d)\n",
+		  msglen, uip_mss() - len));*/
+	  /* There is not enough space in the segment, so we remember
+	     where we were ... */
+	  vs->x2 = x - numblanks;
+	  vs->y2 = y;
+
+	  /* ... and we break out of the loop. */
+	  goto loopend;	  
+	}
+
+	/* We construct a rectangle with the right width and color. */
+	/*	recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
+	recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
+	rrehdr = (struct rfb_rre_hdr *)((char *)recthdr +
+		 sizeof(struct rfb_fb_update_rect_hdr));
+
+	/*	PRINTF(("Blankign (%d:%d) to (%d:%d)\n",
+	       (x - numblanks) * CTK_VNCFONT_WIDTH,
+	       y * CTK_VNCFONT_HEIGHT,
+	       CTK_VNCFONT_WIDTH * numblanks,
+	       CTK_VNCFONT_HEIGHT));*/
+	recthdr->rect.x = htons(SCREEN_X + (x - numblanks) *
+				CTK_VNCFONT_WIDTH);
+	recthdr->rect.y = htons(SCREEN_Y + y * CTK_VNCFONT_HEIGHT);
+	recthdr->rect.w = htons(CTK_VNCFONT_WIDTH * numblanks);
+	recthdr->rect.h = HTONS(CTK_VNCFONT_HEIGHT);
+	recthdr->encoding[0] =
+	  recthdr->encoding[1] =
+	  recthdr->encoding[2] = 0;
+	recthdr->encoding[3] = RFB_ENC_RRE;
+	
+	rrehdr->subrects[0] =
+	  rrehdr->subrects[1] = 0;
+	rrehdr->bgpixel = colortheme[lastcolor][0];
+
+	--x;
+      } else {
+
+	/* So there were no blank characters. */
+
+	/*	PRINTF(("An char at (%d:%d)\n", x, y));*/
+	/* First we must make sure that there is enough space in the
+	   outgoing TCP segment. */
+
+	msglen = sizeof(struct rfb_fb_update_rect_hdr) +
+	  CTK_VNCFONT_HEIGHT * CTK_VNCFONT_WIDTH;
+	if(msglen >= uip_mss() - len) {
+	  /*	  PRINTF(("Not enouch space for char (%d, left %d)\n",
+		  msglen, uip_mss() - len));*/
+	  
+	  /* There is not enough space in the segment, so we remember
+	     where we were ... */
+	  vs->x2 = x;
+	  vs->y2 = y;
+
+	  /* ... and we break out of the loop. */
+	  goto loopend;	  
+	}
+
+	/*	PRINTF(("ptr %p\n",ptr);*/
+	/*	recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
+	recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
+
+	recthdr->rect.x = htons(SCREEN_X + x * CTK_VNCFONT_WIDTH);
+	recthdr->rect.y = htons(SCREEN_Y + y * CTK_VNCFONT_HEIGHT);
+	recthdr->rect.w = HTONS(CTK_VNCFONT_WIDTH);
+	recthdr->rect.h = HTONS(CTK_VNCFONT_HEIGHT);
+	recthdr->encoding[0] =
+	  recthdr->encoding[1] =
+	  recthdr->encoding[2] = 0;
+	recthdr->encoding[3] = RFB_ENC_RAW;
+
+	makechar((u8_t *)recthdr +
+		 sizeof(struct rfb_fb_update_rect_hdr),
+		 x, y);
+      }
+      memcpy(ptr, tmpbuf, msglen);
+      PRINTF(("Msglen %d (%d:%d)\n", msglen, x, y));
+      len += msglen;
+      ptr += msglen;
+      ++n;
+    }
+    x0 = vs->x;
+  }
+  
+ loopend:
+
+  umsg->rects = htons(n);
+	
+  if(y == vs->y + vs->h && x == vs->x + vs->w) {
+    vs->x2 = vs->y2 = 0;
+  }
+
+  if(n > 0) {
+    /*    printf("Sending %d rects, %d bytes (%p, %p, %p)\n", n, len,
+	  uip_appdata, umsg, ptr);*/
+    uip_send(uip_appdata, len);
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+#define NUMKEYS 20
+static char keys[NUMKEYS];
+static int firstkey, lastkey;
+
+
+char
+vnc_out_keyavail(void)
+{
+  return firstkey != lastkey;
+}
+
+char
+vnc_out_getkey(void)
+{
+  char key;
+  key = keys[firstkey];
+  
+  if(firstkey != lastkey) {
+    ++firstkey;
+    if(firstkey >= NUMKEYS) {
+      firstkey = 0;
+    }
+  }
+  
+  return key;  
+}
+
+void
+vnc_out_key_event(struct vnc_server_state *vs)
+{
+  register struct rfb_key_event *ev;
+  
+  ev = (struct rfb_key_event *)uip_appdata;
+
+  if(ev->down != 0) {
+    if(vs->sendmsg == SEND_NONE) {
+      vs->sendmsg = SEND_UPDATE;
+    }
+
+
+    if(ev->key[2] == 0 ||
+       (ev->key[2] == 0xff &&	
+	(ev->key[3] == CH_HOME ||
+	 ev->key[3] == CH_TAB ||
+	 ev->key[3] == CH_ESC ||
+	 ev->key[3] == CH_DEL ||
+	 ev->key[3] == CH_ENTER ||
+	 ev->key[3] == CH_CURS_LEFT ||
+	 ev->key[3] == CH_CURS_UP ||
+	 ev->key[3] == CH_CURS_RIGHT ||
+	 ev->key[3] == CH_CURS_DOWN))) {
+      
+      keys[lastkey] = ev->key[3];
+      ++lastkey;
+      if(lastkey >= NUMKEYS) {
+	lastkey = 0;
+      }
+    }
+  }
+
+  check_updates(vs);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_pointer_event(struct vnc_server_state *vs)
+{
+  struct rfb_pointer_event *ev;
+  u16_t evx, evy;
+  
+  ev = (struct rfb_pointer_event *)uip_appdata;
+
+  evx = htons(ev->x);
+  evy = htons(ev->y);
+  
+  if(evx > SCREEN_X && evx < SCREEN_WIDTH - 2 * SCREEN_X &&
+     evy > SCREEN_Y && evy < SCREEN_HEIGHT - 2 * SCREEN_Y) {
+
+    mouse_button = ev->buttonmask & RFB_BUTTON_MASK1;
+    
+    mouse_x = evx - SCREEN_X;
+    mouse_y = evy - SCREEN_Y;
+
+    check_updates(vs);    
+  }    
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_acked(register struct vnc_server_state *vs)
+{
+  if(vs->state != VNC_RUNNING) {
+    return;
+  }
+  if(vs->sendmsg == SENT_BLANK) {
+    init_send_screen(vs);
+  } else if(vs->sendmsg == SEND_BLANK) {
+    /* Do nothing until sendmsg == SENT_BLANK. */
+  } else if(vs->sendmsg == SEND_SCREEN) {
+    /* When the screen has been fully drawn, ->x2 and ->y2 are both
+       set to 0 to indicate this.*/
+    if(vs->x2 == 0 && vs->y2 == 0) {
+      vs->sendmsg = SEND_NONE;
+      
+      /* If there was an updaterequest for the entire screen, we can
+	 clear that flag now. */
+      if(vs->updates_current != NULL) {	
+	vnc_server_update_free(vs, vs->updates_current);
+	vs->updates_current = NULL;
+      }
+      check_updates(vs);
+    } else {
+      vs->x1 = vs->x2;
+      vs->y1 = vs->y2;
+    }
+	      
+  } else if(vs->sendmsg == SEND_UPDATE) {
+    if(vs->x2 == 0 && vs->y2 == 0) {
+      /* So, we have updated the area that we needed. We now check if
+	 there have been any recent full screen update requests. If
+	 so, we need to go to the SEND_SCREEN state. Else, we see if
+	 there were more areas that needed to be updated and if so,
+	 we'll continue with those. */
+
+      vs->sendmsg = SEND_NONE;
+
+      if(vs->updates_current != NULL) {
+	vnc_server_update_free(vs, vs->updates_current);
+	vs->updates_current = NULL;
+
+      }
+      check_updates(vs);
+#if 0
+      if(vs->updaterequest == VNC_SERVER_UPDATE_FULL) {
+	check_updates(vs);
+      } else {
+	vs->updatesptr2 = (vs->updatesptr2 + 1) %
+	  VNC_SERVER_MAX_UPDATES;
+
+	/* If there are no more updates to do, we'll go back to the
+	   SEND_NONE state. */	
+	if(vs->updatesptr2 == vs->updatesptr) {
+	  vs->updatetype = VNC_SERVER_UPDATE_NONE;
+	} else {	 
+	  /* Otherwise, we continue to update the next area. */
+	  vs->updaterequest = VNC_SERVER_UPDATE_PARTS;
+	  check_updates(vs);
+	}
+      }
+#endif /* 0 */
+    } else {	     
+      vs->x1 = vs->x2;
+      vs->y1 = vs->y2;
+    }    
+  } else {
+    vs->sendmsg = SEND_NONE;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_out_poll(struct vnc_server_state *vs)
+{
+  /*  PRINTF(("vs->state %d, sendmsg %d, updatetype %d, updatereq %d\n",
+      vs->state, vs->sendmsg, vs->updatetype, vs->updaterequest);*/
+  
+  if(vs->state == VNC_RUNNING &&
+     vs->sendmsg == SEND_NONE) {
+    check_updates(vs);
+    vnc_server_send_data(vs);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+#if CTK_CONF_MOUSE_SUPPORT
+void
+ctk_mouse_init(void)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned short
+ctk_mouse_x(void)
+{
+  return mouse_x;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned short
+ctk_mouse_y(void)
+{
+  return mouse_y;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_mouse_button(void)
+{
+  return mouse_button;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_mouse_hide(void)
+{
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_mouse_show(void)
+{
+}
+/*-----------------------------------------------------------------------------------*/
+#endif /* CTK_CONF_MOUSE_SUPPORT */
diff --git a/contiki/ctk/vnc-out.h b/contiki/ctk/vnc-out.h
new file mode 100644
index 0000000..94cfb95
--- /dev/null
+++ b/contiki/ctk/vnc-out.h
@@ -0,0 +1,92 @@
+/*
+ * 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. 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: vnc-out.h,v 1.4 2004/09/12 20:24:55 adamdunkels Exp $
+ *
+ */
+
+#ifndef __VNC_OUT_H__
+#define __VNC_OUT_H__
+
+
+void vnc_out_init(void);
+void vnc_out_new(struct vnc_server_state *vs);
+
+void vnc_out_send_blank(struct vnc_server_state *vs);
+void vnc_out_send_screen(struct vnc_server_state *vs);
+void vnc_out_send_update(struct vnc_server_state *vs);
+
+void vnc_out_key_event(struct vnc_server_state *vs);
+void vnc_out_pointer_event(struct vnc_server_state *vs);
+
+void vnc_out_acked(struct vnc_server_state *vs);
+
+void vnc_out_poll(struct vnc_server_state *vs);
+
+
+void vnc_out_update_screen(u8_t x, u8_t y, u8_t c, u8_t color);
+char vnc_out_getkey(void);
+char vnc_out_keyavail(void);
+
+void vnc_out_update_area(struct vnc_server_state *vs,
+			 u8_t x, u8_t y, u8_t w, u8_t h);
+
+#include "ctk.h"
+
+unsigned char vnc_out_add_icon(struct ctk_icon *icon);
+
+#if 1
+#define VNC_OUT_BACKGROUNDCOLOR 0
+#define VNC_OUT_WINDOWCOLOR    1
+#define VNC_OUT_SEPARATORCOLOR 7 /*(VNC_OUT_WINDOWCOLOR + 6)*/
+#define VNC_OUT_LABELCOLOR     13 /*(VNC_OUT_SEPARATORCOLOR + 6)*/
+#define VNC_OUT_BUTTONCOLOR    19 /*(VNC_OUT_LABELCOLOR + 6)*/
+#define VNC_OUT_HYPERLINKCOLOR 25 /*(VNC_OUT_BUTTONCOLOR + 6)*/
+#define VNC_OUT_TEXTENTRYCOLOR 31 /*(VNC_OUT_HYPERLINKCOLOR + 6)*/
+#define VNC_OUT_ICONCOLOR      37 /*(VNC_OUT_TEXTENTRYCOLOR + 6)*/
+#define VNC_OUT_MENUCOLOR      43 /*(VNC_OUT_ICONCOLOR + 6)*/
+#define VNC_OUT_OPENMENUCOLOR  44/*(VNC_OUT_MENUCOLOR + 1)*/
+#define VNC_OUT_ACTIVEMENUCOLOR 45 /*(VNC_OUT_OPENMENUCOLOR + 1) */
+#else
+#define VNC_OUT_BACKGROUNDCOLOR 0
+#define VNC_OUT_WINDOWCOLOR    1
+#define VNC_OUT_SEPARATORCOLOR (VNC_OUT_WINDOWCOLOR + 6)
+#define VNC_OUT_LABELCOLOR     (VNC_OUT_SEPARATORCOLOR + 6)
+#define VNC_OUT_BUTTONCOLOR    (VNC_OUT_LABELCOLOR + 6)
+#define VNC_OUT_HYPERLINKCOLOR (VNC_OUT_BUTTONCOLOR + 6)
+#define VNC_OUT_TEXTENTRYCOLOR (VNC_OUT_HYPERLINKCOLOR + 6)
+#define VNC_OUT_ICONCOLOR      (VNC_OUT_TEXTENTRYCOLOR + 6)
+#define VNC_OUT_MENUCOLOR      (VNC_OUT_ICONCOLOR + 6)
+#define VNC_OUT_OPENMENUCOLOR  (VNC_OUT_MENUCOLOR + 1)
+#define VNC_OUT_ACTIVEMENUCOLOR (VNC_OUT_OPENMENUCOLOR + 1)
+
+#endif
+
+#endif /* __VNC_OUT_H__ */
diff --git a/contiki/ctk/vnc-server.c b/contiki/ctk/vnc-server.c
new file mode 100644
index 0000000..62a4680
--- /dev/null
+++ b/contiki/ctk/vnc-server.c
@@ -0,0 +1,487 @@
+/*
+ * 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. 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: vnc-server.c,v 1.4 2004/08/09 20:32:28 adamdunkels Exp $
+ *
+ */
+
+/* A micro implementation of a VNC server. VNC is a protocol for
+   remote network displays. See http://www.uk.research.att.com/vnc/
+   for information about VNC.
+
+   Initialization states:
+
+   VNC_VERSION (send version string)
+   VNC_AUTH    (send auth message)
+   VNC_INIT    (send init message)
+
+   Steady state:
+   
+   VNC_RUNNING (send RFB updates, parse incoming messages)
+
+   What kind of message should be sent:
+
+   SEND_NONE   (No message)
+   SEND_BLANK  (Blank screen initially)
+   SEND_SCREEN (Send entire screen, initially)
+   SEND_UPDATE (Send incremental update)
+
+*/
+
+#include "uip.h"
+#include "vnc-server.h"
+#include "vnc-out.h"
+
+#include <string.h>
+
+/* RFB server initial handshaking string. */
+#define RFB_SERVER_VERSION_STRING rfb_server_version_string
+
+/* "RFB 003.003" */
+static u8_t rfb_server_version_string[12] = {82,70,66,32,48,48,51,46,48,48,51,10};
+
+/* uVNC */
+static u8_t uvnc_name[4] = {117,86,78,67};
+#if 1
+#define PRINTF(x)
+#else
+#define PRINTF(x) printf x
+#endif
+
+/*-----------------------------------------------------------------------------------*/
+u8_t
+vnc_server_draw_rect(u8_t *ptr, u16_t x, u16_t y, u16_t w, u16_t h, u8_t c)
+{
+  register struct rfb_fb_update_rect_hdr *recthdr;
+  struct rfb_rre_hdr *rrehdr;
+
+  recthdr = (struct rfb_fb_update_rect_hdr *)ptr;
+  rrehdr = (struct rfb_rre_hdr *)(ptr + sizeof(struct rfb_fb_update_rect_hdr));
+  
+  recthdr->rect.x = x;
+  recthdr->rect.y = y;
+  recthdr->rect.w = w;
+  recthdr->rect.h = h; 
+  recthdr->encoding[0] =
+    recthdr->encoding[1] =
+    recthdr->encoding[2] = 0;
+  recthdr->encoding[3] = RFB_ENC_RRE;
+      
+  rrehdr->subrects[0] =
+    rrehdr->subrects[1] = 0;
+  rrehdr->bgpixel = c;
+      
+  return sizeof(struct rfb_fb_update_rect_hdr) + sizeof(struct rfb_rre_hdr);
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_server_init(void)
+{
+  vnc_out_init();
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+vnc_send_blank(struct vnc_server_state *vs)
+{
+  switch(vs->type) {
+  case 0:	
+    vnc_out_send_blank(vs);
+    break;
+    /*  case 1:
+    vnc_stats_send_blank(vs);
+    break;   */
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+vnc_send_screen(struct vnc_server_state *vs)
+{
+  switch(vs->type) {
+  case 0:	
+    vnc_out_send_screen(vs);
+    break;
+    /*  case 1:
+    vnc_stats_send_screen(vs);
+    break;*/
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+vnc_send_update(struct vnc_server_state *vs)
+{
+  switch(vs->type) {
+  case 0:	
+    vnc_out_send_update(vs);
+    break;
+    /*  case 1:
+    vnc_stats_send_update(vs);
+    break;*/
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_server_send_data(struct vnc_server_state *vs)
+{
+  register struct rfb_server_init *initmsg;
+  
+  switch(vs->state) {
+  case VNC_VERSION:
+    uip_send(RFB_SERVER_VERSION_STRING, sizeof(RFB_SERVER_VERSION_STRING));
+    break;
+  case VNC_AUTH:
+    uip_appdata[0] = 0;
+    uip_appdata[1] = 0;
+    uip_appdata[2] = 0;
+    uip_appdata[3] = RFB_AUTH_NONE;
+    uip_send(uip_appdata, 4);
+    break;
+  case VNC_INIT:
+    initmsg = (struct rfb_server_init *)uip_appdata;
+    initmsg->width = htons(vs->width);
+    initmsg->height = htons(vs->height);
+    /* BGR233 pixel format. */
+    initmsg->format.bps = 8;
+    initmsg->format.depth = 8;
+    initmsg->format.endian = 1;
+    initmsg->format.truecolor = 1;
+    initmsg->format.red_max = htons(7);
+    initmsg->format.green_max = htons(7);
+    initmsg->format.blue_max = htons(3);
+    initmsg->format.red_shift = 0;
+    initmsg->format.green_shift = 3;
+    initmsg->format.blue_shift = 6;
+    initmsg->namelength[0] = 0;
+    initmsg->namelength[1] = 0;
+    initmsg->namelength[2] = 0;	    
+    initmsg->namelength[3] = 4;
+    memcpy(&uip_appdata[sizeof(struct rfb_server_init)], uvnc_name, 4);
+    /*    uip_appdata[sizeof(struct rfb_server_init)+0] = 'u';
+    uip_appdata[sizeof(struct rfb_server_init)+1] = 'V';
+    uip_appdata[sizeof(struct rfb_server_init)+2] = 'N';
+    uip_appdata[sizeof(struct rfb_server_init)+3] = 'C';*/
+    uip_send(uip_appdata, sizeof(struct rfb_server_init) + 4);
+    break;
+  case VNC_RUNNING:
+    switch(vs->sendmsg) {
+    case SEND_NONE:
+      PRINTF(("Sending none\n"));
+      break;
+      
+    case SEND_BLANK:
+    case SENT_BLANK:
+      PRINTF(("Sending blank\n"));
+      vnc_send_blank(vs);
+      break;
+      
+    case SEND_SCREEN:
+      PRINTF(("Sending screen\n"));
+      vnc_send_screen(vs);
+      break;
+
+    case SEND_UPDATE:
+      PRINTF(("Sending update\n"));
+      vnc_send_update(vs);
+      break;
+    }
+    break;
+    
+  default:
+    break;
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+vnc_key_event(struct vnc_server_state *vs)
+{
+  switch(vs->type) {
+  case 0:	
+    vnc_out_key_event(vs);
+    break;
+    /*  case 1:
+    vnc_stats_key_event(vs);
+    break;*/
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+vnc_pointer_event(struct vnc_server_state *vs)
+{
+  switch(vs->type) {
+  case 0:	
+    vnc_out_pointer_event(vs);
+    break;
+    /*  case 1:
+    vnc_stats_pointer_event(vs);
+    break;*/
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static u8_t
+vnc_read_data(register struct vnc_server_state *vs)
+{
+  u8_t *appdata;
+  u16_t len;
+  struct rfb_fb_update_request *req;
+  /*  u8_t niter;*/
+  
+  len = uip_datalen();
+  appdata = (u8_t *)uip_appdata;
+  
+  /* First, check if there is data left to discard since last read. */
+  if(vs->readlen > 0) {
+    appdata += vs->readlen;
+    if(len > vs->readlen) {
+      len -= vs->readlen;
+      vs->readlen = 0;
+    } else {
+      vs->readlen -= len;
+      len = 0;
+    }
+  }
+
+  if(vs->readlen != 0) {
+    return 1;
+  }
+
+  /* All data read and ignored, parse next message. */
+  /*  for(niter = 32; niter > 0 && len > 0; --niter) {*/
+  while(len > 0) {
+    switch(vs->state) {
+    case VNC_VERSION:
+    case VNC_VERSION2:
+      PRINTF(("Read in version\n"));
+      /* Receive and ignore client version string (12 bytes). */
+      vs->state = VNC_AUTH;
+      vs->readlen = 12;
+      break;
+      
+    case VNC_AUTH:
+    case VNC_AUTH2:
+      PRINTF(("Read in auth \n"));
+      /* Read and discard initialization from client (1 byte). */
+      vs->readlen = 1;
+      vs->state = VNC_INIT;
+      break;
+      
+    case VNC_INIT:
+    case VNC_INIT2:
+      PRINTF(("Read in init \n"));
+      vs->readlen = 0;
+      vs->state = VNC_RUNNING;
+      
+    case VNC_RUNNING:
+      /* Handle all client events. */
+      switch(*appdata) {
+      case RFB_SET_PIXEL_FORMAT:
+	PRINTF(("Set pixel format\n"));
+	vs->readlen = sizeof(struct rfb_set_pixel_format);
+	/* Check if client runs with BGR233 format. If not, abort the
+	   connection. */
+	/* XXX: not implemented yet. */
+	break;
+	
+      case RFB_FIX_COLORMAP_ENTRIES:
+	PRINTF(("Fix colormap entries\n"));
+	return 0;
+	
+      case RFB_SET_ENCODINGS:
+	PRINTF(("Set encodings\n"));
+	vs->readlen = sizeof(struct rfb_set_encoding);
+	vs->readlen += htons(((struct rfb_set_encoding *)appdata)->encodings) * 4;
+	/* Make sure that client supports the encodings we use. */
+	/* XXX: not implemented yet. */
+	break;
+	
+      case RFB_FB_UPDATE_REQ:
+	PRINTF(("Update request\n"));
+	vs->update_requested = 1;
+	vs->readlen = sizeof(struct rfb_fb_update_request);
+	/* blank the screen initially */
+	req = (struct rfb_fb_update_request *)appdata;
+	if(req->incremental == 0) {
+	  /*	  vs->sendmsg = SEND_BLANK;*/
+	  vnc_out_update_area(vs, 0, 0, vs->w, vs->h);
+	}
+	break;
+	
+      case RFB_KEY_EVENT:
+	vs->readlen = sizeof(struct rfb_key_event);
+	vnc_key_event(vs);
+	break;
+	
+      case RFB_POINTER_EVENT:
+	vs->readlen = sizeof(struct rfb_pointer_event);
+	vnc_pointer_event(vs);
+	break;
+	
+      case RFB_CLIENT_CUT_TEXT:
+	PRINTF(("Client cut text\n"));
+
+	if(((struct rfb_client_cut_text *)appdata)->len[0] != 0 ||
+	   ((struct rfb_client_cut_text *)appdata)->len[1] != 0) {
+	  return 0;
+	  
+	}
+	vs->readlen = sizeof(struct rfb_client_cut_text) +
+	  (((struct rfb_client_cut_text *)appdata)->len[2] << 8) +
+	  ((struct rfb_client_cut_text *)appdata)->len[3];
+	/*	return 0;*/
+	break;
+	
+      default:
+	PRINTF(("Unknown message %d\n", *appdata));
+	return 0;
+      }
+      break;
+      
+    default:
+      return 0;
+    }
+
+    if(vs->readlen > 0) {
+      if(len > vs->readlen) {
+	len -= vs->readlen;
+	appdata += vs->readlen;
+	vs->readlen = 0;
+      } else {
+	vs->readlen -= len;
+	len = 0;
+      }
+    } else {
+      /* Lost data. */
+      break;
+    }
+    
+  }
+
+  /*  if(vs->readlen > 0) {
+    printf("More data %d\n", vs->readlen);
+    }*/
+  
+  /*  uip_appdata = appdata;*/
+
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+vnc_new(register struct vnc_server_state *vs)
+{
+  vs->counter = 0;
+  vs->readlen = 0;
+  vs->sendmsg = SEND_NONE;
+  vs->update_requested = 1;
+  switch(vs->type) {
+  case 0:	
+    vnc_out_new(vs);
+    break;
+    /*  case 1:
+    vnc_stats_new(vs);
+    break;*/
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+vnc_acked(register struct vnc_server_state *vs)
+{
+  switch(vs->state) {
+  case VNC_VERSION:
+    vs->state = VNC_VERSION2;
+    break;
+    
+  case VNC_AUTH:
+    vs->state = VNC_AUTH2;
+    break;
+    
+  case VNC_INIT:
+    vs->state = VNC_INIT2;
+    break;
+
+  case VNC_RUNNING:
+    switch(vs->type) {
+    case 0:	
+      vnc_out_acked(vs);
+      break;
+      /*    case 1:
+      vnc_stats_acked(vs);
+      break;*/
+    }
+    break;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+vnc_server_appcall(struct vnc_server_state *vs)
+{
+  
+  vs->type = htons(uip_conn->lport) - 5900;
+  
+  if(uip_connected()) {      
+    vnc_new(vs);
+    vs->state = VNC_VERSION;
+    vnc_server_send_data(vs);
+    return;
+  }
+  if(uip_acked()) {
+    PRINTF(("Acked\n"));
+    vnc_acked(vs);
+  }
+  
+  if(uip_newdata()) {
+    PRINTF(("Newdata\n"));
+    vs->counter = 0;
+    if(vnc_read_data(vs) == 0) {
+      uip_abort();
+      return;
+    }
+  }
+  
+  if(uip_rexmit()) {
+    PRINTF(("Rexmit\n"));
+  }
+  
+  
+  if(uip_newdata() ||
+     uip_rexmit() ||
+     uip_acked()) {
+    vnc_server_send_data(vs);
+  } else if(uip_poll()) {
+    ++vs->counter;
+    /* Abort connection after about 20 seconds of inactivity. */
+    if(vs->counter >= 40) {
+      uip_abort();
+      return;
+    }
+    
+    vnc_out_poll(vs);
+  }
+  
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/ctk/vnc-server.h b/contiki/ctk/vnc-server.h
new file mode 100644
index 0000000..79cd033
--- /dev/null
+++ b/contiki/ctk/vnc-server.h
@@ -0,0 +1,296 @@
+/*
+ * 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. 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: vnc-server.h,v 1.4 2004/09/12 20:24:55 adamdunkels Exp $
+ *
+ */
+
+#ifndef __VNC_SERVER_H__
+#define __VNC_SERVER_H__
+
+
+/*struct vnc_server_updatearea {
+  u8_t active;
+  u8_t x, y;
+  u8_t w, h;
+  };*/
+
+struct vnc_server_update {
+  struct vnc_server_update *next;
+
+#define VNC_SERVER_UPDATE_NONE  0
+#define VNC_SERVER_UPDATE_PARTS 1
+#define VNC_SERVER_UPDATE_FULL  2
+
+  u8_t type;
+
+  u8_t x, y;
+  u8_t w, h;  
+};
+
+struct vnc_server_state {
+  u16_t counter;
+  u8_t type;
+  u8_t state;
+  u16_t height, width;
+
+  u8_t update_requested;
+  
+  /* Variables used when sending screen updates. */
+  u8_t x, y, x1, y1, x2, y2;
+  u8_t w, h;
+
+  
+
+  u16_t readlen;
+  u8_t sendmsg;
+  u8_t button;
+
+  
+  struct vnc_server_update *updates_current;
+  struct vnc_server_update *updates_pending;
+  struct vnc_server_update *updates_free;
+
+#define VNC_SERVER_MAX_UPDATES 8  
+  struct vnc_server_update updates_pool[VNC_SERVER_MAX_UPDATES];
+
+};
+
+struct vnc_server_update *
+     vnc_server_update_alloc(struct vnc_server_state *vs);
+void vnc_server_update_free(struct vnc_server_state *vs,
+			    struct vnc_server_update *a);
+void vnc_server_update_remove(struct vnc_server_state *vs,
+			      struct vnc_server_update *a);
+
+void vnc_server_update_add(struct vnc_server_state *vs,
+			   struct vnc_server_update *a);
+struct vnc_server_update *
+     vnc_server_update_dequeue(struct vnc_server_state *vs);
+
+
+
+
+void vnc_server_init(void);
+void vnc_server_appcall(struct vnc_server_state *state);
+
+
+extern struct vnc_server_state *vs;
+
+enum {
+  VNC_DEALLOCATED,
+  VNC_VERSION,
+  VNC_VERSION2,
+  VNC_AUTH,
+  VNC_AUTH2,
+  VNC_INIT,
+  VNC_INIT2,
+  VNC_RUNNING
+};
+
+/* Sendmsg */
+enum {
+  SEND_NONE,
+  SEND_BLANK,
+  SENT_BLANK,
+  SEND_SCREEN,
+  SEND_UPDATE
+};
+
+
+/* Definitions of the RFB (Remote Frame Buffer) protocol
+   structures and constants. */
+
+#include "uipopt.h"
+
+void vnc_server_send_data(struct vnc_server_state *vs);
+u8_t vnc_server_draw_rect(u8_t *ptr, u16_t x, u16_t y, u16_t w, u16_t h, u8_t c);
+
+
+/* Generic rectangle - x, y coordinates, width and height. */
+struct rfb_rect {
+  u16_t x;
+  u16_t y;
+  u16_t w;
+  u16_t h;
+};
+
+/* Pixel format definition. */
+struct rfb_pixel_format {
+  u8_t bps;       /* Bits per pixel: 8, 16 or 32. */
+  u8_t depth;     /* Color depth: 8-32 */
+  u8_t endian;    /* 1 - big endian (motorola), 0 - little endian
+		     (x86) */
+  u8_t truecolor; /* 1 - true color is used, 0 - true color is not used. */
+
+  /* The following fields are only used if true color is used. */
+  u16_t red_max, green_max, blue_max;
+  u8_t red_shift, green_shift, blue_shift;
+  u8_t pad1;
+  u16_t pad2;
+};
+
+
+/* RFB authentication constants. */
+
+#define RFB_AUTH_FAILED      0
+#define RFB_AUTH_NONE        1
+#define RFB_AUTH_VNC         2
+
+#define RFB_VNC_AUTH_OK      0
+#define RFB_VNC_AUTH_FAILED  1
+#define RFB_VNC_AUTH_TOOMANY 2
+
+/* RFB message types. */
+
+/* From server to client: */
+#define RFB_FB_UPDATE            0
+#define RFB_SET_COLORMAP_ENTRIES 1
+#define RFB_BELL                 2
+#define RFB_SERVER_CUT_TEXT      3
+
+/* From client to server. */
+#define RFB_SET_PIXEL_FORMAT     0
+#define RFB_FIX_COLORMAP_ENTRIES 1
+#define RFB_SET_ENCODINGS        2
+#define RFB_FB_UPDATE_REQ        3
+#define RFB_KEY_EVENT            4
+#define RFB_POINTER_EVENT        5
+#define RFB_CLIENT_CUT_TEXT      6
+
+/* Encoding types. */
+#define RFB_ENC_RAW      0
+#define RFB_ENC_COPYRECT 1
+#define RFB_ENC_RRE      2
+#define RFB_ENC_CORRE    3
+#define RFB_ENC_HEXTILE  4
+
+/* Message definitions. */
+
+/* Server to client messages. */
+
+struct rfb_server_init {
+  u16_t width;
+  u16_t height;
+  struct rfb_pixel_format format;
+  u8_t namelength[4];
+  /* Followed by name. */
+};
+
+struct rfb_fb_update {
+  u8_t type;
+  u8_t pad;
+  u16_t rects; /* Number of rectanges (struct rfb_fb_update_rect_hdr +
+		  data) that follows. */
+};
+
+struct rfb_fb_update_rect_hdr {
+  struct rfb_rect rect;
+  u8_t encoding[4];
+};
+
+struct rfb_copy_rect {
+  u16_t srcx;
+  u16_t srcy;
+};
+
+struct rfb_rre_hdr {
+  u16_t subrects[2];  /* Number of subrectangles (struct
+			 rfb_rre_subrect) to follow. */
+  u8_t bgpixel;
+};
+
+struct rfb_rre_subrect {
+  u8_t pixel;
+  struct rfb_rect rect;
+};
+
+struct rfb_corre_rect {
+  u8_t x;
+  u8_t y;
+  u8_t w;
+  u8_t h;
+};
+
+/* Client to server messages. */
+
+struct rfb_set_pixel_format {
+  u8_t type;
+  u8_t pad;
+  u16_t pad2;
+  struct rfb_pixel_format format;
+};
+
+struct rfb_fix_colormap_entries {
+  u8_t type;
+  u8_t pad;
+  u16_t firstcolor;
+  u16_t colors;
+};
+
+struct rfb_set_encoding {
+  u8_t type;
+  u8_t pad;
+  u16_t encodings;
+};
+
+struct rfb_fb_update_request {
+  u8_t type;
+  u8_t incremental;
+  u16_t x;
+  u16_t y;
+  u16_t w;
+  u16_t h;
+};
+
+struct rfb_key_event {
+  u8_t type;
+  u8_t down;
+  u16_t pad;
+  u8_t key[4];
+};
+
+#define RFB_BUTTON_MASK1 1
+#define RFB_BUTTON_MASK2 2
+#define RFB_BUTTON_MASK3 4
+struct rfb_pointer_event {
+  u8_t type;
+  u8_t buttonmask;
+  u16_t x;
+  u16_t y;
+};
+
+struct rfb_client_cut_text {
+  u8_t type;
+  u8_t pad[3];
+  u8_t len[4];
+};
+
+#endif /* __VNC_SERVER_H__ */
diff --git a/contiki/doc/Doxyfile b/contiki/doc/Doxyfile
new file mode 100644
index 0000000..33ce07e
--- /dev/null
+++ b/contiki/doc/Doxyfile
@@ -0,0 +1,1147 @@
+# Doxyfile 1.3.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = "Contiki 1.2"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, 
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en 
+# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, 
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is used 
+# as the annotated text. Otherwise, the brief description is used as-is. If left 
+# blank, the following values are used ("$name" is automatically replaced with the 
+# name of the entity): "The $name class" "The $name widget" "The $name file" 
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = ../
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = ../ek/ek.c \
+                         ../ek/arg.c \
+                         ../ek/ek.h \
+                         ../ek/ek-service.h \
+                         ../ek/dsc.h \
+                         ../ek/loader.h \
+			 pt-doc.txt \
+                         ../ek/pt.h \
+                         ../ek/lc.h \
+                         ../ek/lc-switch.h \
+                         ../ek/lc-addrlabels.h \
+                         ../ek/pt-sem.h \
+                         ../apps/program-handler.c \
+                         ../ctk/ctk.h \
+                         ../ctk/ctk.c \
+                         ../ctk/ctk-draw.h \
+                         uip-doc.txt \
+                         ../uip/uip.h \
+                         ../uip/uip.c \
+                         ../uip/uip_arp.h \
+                         ../uip/uip_arp.c \
+                         ../uip/uip-split.h \
+                         ../uip/uip-split.c \
+                         ../uip/uip-fw.h \
+                         ../uip/uip-fw.c \
+                         ../uip/uiplib.h \
+                         ../uip/uiplib.c \
+                         ../uip/resolv.h \
+                         ../uip/resolv.c \
+                         ../uip/psock.h \
+                         ../uip/tcpip.h \
+                         ../lib/cc.h \
+                         ../lib/petsciiconv.h \
+                         ../lib/ctk-textedit.h \
+                         ../lib/ctk-textedit.c \
+                         ../lib/memb.h \
+                         ../lib/memb.c \
+                         ../lib/timer.h \
+                         ../lib/timer.c \
+                         ../lib/list.h \
+                         ../lib/list.c \
+                         ../lib/clock.h \
+                         ../ek/mt.h \
+                         ../ek/mt.c \
+                         ../conf/uip-conf.h.example \
+                         ../conf/www-conf.h.example \
+                         contiki-mainpage.txt
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.
+
+INPUT_FILTER           = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = CC_FUNCTION_POINTER_ARGS \
+                         UIP_UDP \
+                         WITH_LOADER_ARCH \
+			 DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes that 
+# lay further from the root node will be omitted. Note that setting this option to 
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also 
+# note that a graph may be further truncated if the graph's image dimensions are 
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). 
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/contiki/doc/FILES b/contiki/doc/FILES
new file mode 100644
index 0000000..8c22d12
--- /dev/null
+++ b/contiki/doc/FILES
@@ -0,0 +1,25 @@
+The contiki/doc/ directory contains files for automatic generation of
+documentation from the Contiki source code. Documentation is generated
+with the doxygen tool (http://www.doxygen.org/).
+
+Doxyfile
+
+  Configuration file for the doxygen tool.
+
+contiki-mainpage.txt
+
+  The text for the first page in the documentation.
+
+ctk.txt
+
+  General documentation about CTK, the Contiki GUI toolkit. This file
+  is mostly obsolete, as the information has been moved into the
+  source code.
+
+release.txt
+
+  Release checklist.
+
+uip-doc.txt
+
+  Documentation for the uIP TCP/IP stack.
diff --git a/contiki/doc/contiki-mainpage.txt b/contiki/doc/contiki-mainpage.txt
new file mode 100644
index 0000000..b8825af
--- /dev/null
+++ b/contiki/doc/contiki-mainpage.txt
@@ -0,0 +1,52 @@
+/**
+
+\mainpage The Contiki Operating System
+
+\author Adam Dunkels <adam@dunkels.com>
+
+The Contiki operating system is a highly portable, minimalistic
+operating system for a variety of constrained systems ranging from
+modern 8-bit microcontrollers for embedded systems to old 8-bit
+homecomputers. Contiki provides a simple event driven kernel with
+optional preemptive multithreading, interprocess communication using
+message passing signals, a dynamic process structure and support for
+loading and unloading programs, native TCP/IP support using the uIP
+TCP/IP stack, and a graphical subsystem with either direct graphic
+support for directly connected terminals or networked virtual display
+with VNC or Telnet.
+
+Contiki is written in the C programming language and is freely
+available as open source under a BSD-style license. More information
+about Contiki can be found at the Contiki home page:
+http://www.sics.se/~adam/contiki/
+
+\section contiki-mainpage-tcpip TCP/IP support
+
+Contiki includes the uIP TCP/IP stack (http://www.sics.se/~adam/uip/)
+that provides Contiki with TCP/IP networking support. uIP provides the
+protocols TCP, UDP, IP, and ARP.
+
+\sa \ref uip "The uIP TCP/IP stack documentation"
+\sa \ref tcpip "The Contiki/uIP interface"
+\sa \ref socket "Socket-like library"
+
+\section contiki-mainpage-threads Multi-threading and protothreads
+
+Contiki is based on an event-driven kernel but provides support for
+both multi-threading and a lightweight stackless thread-like construct
+called protothreads.
+
+\sa \ref ek "The Contiki event-driven kernel"
+\sa \ref mt "Contiki multi-threading"
+\sa \ref pt "Protothreads"
+
+\section contiki-mainpage-lib Libraries
+
+Contiki provides a set of convenience libraries for memory management
+and linked list operations.
+
+\sa \ref timer "Timer library"
+\sa \ref memb "Memory block management"
+\sa \ref list "Linked list library"
+
+*/
\ No newline at end of file
diff --git a/contiki/doc/ctk.txt b/contiki/doc/ctk.txt
new file mode 100644
index 0000000..a2fa85c
--- /dev/null
+++ b/contiki/doc/ctk.txt
@@ -0,0 +1,557 @@
+This file describes the interface between the generic part of the
+Contiki toolkit (CTK) and the architecture specific parts of CTK (the
+so-called ctk-draw and ctk-arch layers).
+
+Author: Adam Dunkels <adam@dunkels.com>
+Version: $Id: ctk.txt,v 1.3 2005/03/15 15:53:51 oliverschmidt Exp $
+
+
+* Introduction *
+----------------
+
+The purpose of the ctk-arch and the ctk-draw is to act as an interface
+between the CTK and the actual hardware of the system on which Contiki
+is run. The ctk-arch takes care of the keyboard input from the user,
+and the ctk-draw is responsible for drawing the CTK desktop, windows
+and user interface widgets onto the actual screen.
+
+In order to aid in implementing a ctk-draw module, a text-based
+ctk-draw called ctk-conio has already been implemented. It conforms to
+the Borland conio C library, and a skeleton implementation of said
+library exists in lib/libconio.c. If a more machine specific ctk-draw
+module is to be implemented, the instructions in this file should be
+followed.
+
+
+* Keyboard input *
+------------------
+
+Keyboard input is implemented using two functions:
+
+  unsigned char ctk_arch_keyavail(void);
+
+and
+
+  ctk_arch_key_t ctk_arch_getkey(void);
+
+The ctk_arch_keyavail() function should return zero if there are no
+keys in the keyboard input queue, and non-zero if there are key presses
+waiting in the input queue. The ctk_arch_getkey() function should
+remove the first key press on the input queue, and return it to the
+caller. The ctk_arch_key_t type should usually be typedef'ed to be
+"char", but some architectures use other C types for representing
+key presses (such as the 16-bit short type).
+
+The usual typedef looks like the following:
+
+   typedef char ctk_arch_key_t;
+
+and should be put into a file named "ctk-arch.h", together with the C
+#defines described below.
+
+Apart from the C functions that handles keyboard input, CTK requires a
+few special characters such as the cursor keys and the enter
+key. These are #defined as C macros in the "ctk-arch.h" file. The
+following macros must be defined:
+
+   CH_CURS_DOWN
+   CH_CURS_LEFT
+   CH_CURS_RIGHT
+   CH_CURS_UP
+   CH_DEL
+   CH_ENTER
+   CH_ESC
+   CH_KEY
+
+
+* Screen drawing *
+------------------
+
+The ctk-draw module takes care of the actual screen drawing for CTK by
+implementing a handful of functions that are called by CTK. The
+functions will be described in detail below, but are listed here for
+convenience:
+
+   void ctk_draw_init(void);
+   unsigned char ctk_draw_width(void);
+   unsigned char ctk_draw_height(void);
+   void ctk_draw_clear(unsigned char clipy1, unsigned char clipy2);
+   void ctk_draw_menus(struct ctk_menus *menus);
+   void ctk_draw_clear_window(struct ctk_window *window,
+                              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,
+			unsigned char draw_borders);
+   void ctk_draw_dialog(struct ctk_window *dialog);
+   void ctk_draw_widget(struct ctk_widget *w,
+                        unsigned char focus,
+                        unsigned char clipy1,
+                        unsigned char clipy2);
+
+
+* Initialization *
+------------------
+
+The ctk-draw initializes itself by the function:
+
+   void ctk_draw_init(void);
+
+This function is supposed to get the screen ready for drawing, and may
+be called at more than one time during the operation of the system.
+
+
+* Screen coordinates *
+----------------------
+
+In order to work efficiently even on limited systems, CTK uses a
+simple coordinate system, where the screen is addressed using
+character coordinates instead of pixel coordinates. This makes it
+trivial to implement the coordinate system on a text-based screen,
+and significantly reduces complexity for pixel based screen systems.
+
+The top left of the screen is (0,0) with x and y coordinates growing
+downwards and to the right.
+
+It is the responsibility of the ctk-draw module to keep track of the
+screen size and must implement two functions which are used by the CTK
+for querying the screen size:
+
+   unsigned char ctk_draw_width(void);
+   unsigned char ctk_draw_height(void);
+
+The functions must return the width and the height of the ctk-draw
+screen in character coordinates.
+
+
+* Clearing the screen *
+-----------------------
+
+The ctk-draw is required to implement a function for clearing parts of
+the screen. This function is called by the CTK before an area of the
+screen is to be redrawn. The function prototype is:
+
+   void ctk_draw_clear(unsigned char clipy1, unsigned char clipy2);
+
+The function should clear the screen between the y coordinates
+"clipy1" and "clipy2", including the line at y coordinate "clipy1",
+but not the line at y coordinate "clipy2".
+
+Note that this function may be used to draw a background image
+(wallpaper) on the desktop; it does not necessarily "clear" the
+screen. 
+
+
+* Drawing menus *
+-----------------
+
+Drawing the menus is the responsibility of the ctk-draw, and is done
+from the function:
+
+   void ctk_draw_menus(struct ctk_menus *menus);
+
+The ctk_draw_menus() function takes a pointer to a struct ctk_menus as
+its argument and draws the menus at the top of the screen. The struct
+ctk_menus is defined in the file ctk/ctk.h as:
+
+   struct ctk_menus {
+     struct ctk_menu *menus;
+     struct ctk_menu *open;
+     struct ctk_menu *desktopmenu;
+   };
+
+The "open" item points to the currently active menu, if any. If all
+menus are closed, the "open" item is NULL. The "desktopmenu" item
+points to the "Desktop" menu, and can be used for drawing the desktop
+menu in a special way (such as drawing it at the rightmost
+position). The "menus" item points to a linked list of all menus,
+including the open menu and the desktop menu.
+
+The struct ctk_menu is also defined in ctk/ctk.h:
+
+   struct ctk_menu {
+     struct ctk_menu *next;
+     char *title;
+     unsigned char titlelen;
+     unsigned char nitems;
+     unsigned char active;
+     struct ctk_menuitem items[CTK_CONF_MAXMENUITEMS];
+   };
+
+The "next" pointer points to the next menu, or is NULL if this is the
+last menu, and should be used for stepping through the menus when
+drawing them on screen. The "title" is the title of the menu, and the
+length of the title is given in the "titlelen" field. The "nitems"
+field specifies the total number of menu items in the menu and the
+"active" item specifies the active item in the menu. The active item
+should be drawn differently from the other items (it usually is drawn
+inverted). Finally, the list of menu items is present in the "items"
+list. This list consists of struct ctk_menuitem items; the struct
+ctk_menuitem is defined in the file ctk/ctk.h as:
+
+   struct ctk_menuitem {
+     char *title;
+     unsigned char titlelen;
+   };
+
+Where the "title" field is the title of the menu item and the
+"titlelen" the length of the title in characters.
+
+
+* Drawing window background *
+-----------------------------
+
+The ctk-draw layer must implement a function for "clearing" the
+window, i.e., draw the window background. This function will be called
+by the CTK before a window will be completely redrawn, and looks like:
+
+   void ctk_draw_clear_window(struct ctk_window *window,
+                              unsigned char focus,
+                              unsigned char clipy1, unsigned char clipy2);
+
+The function is supposed to draw the window background, excluding
+window borders as these should be drawn by the function that actually
+draws the window, between "clipy1" and "clipy2".
+
+
+* Drawing windows *
+-------------------
+
+The CTK will call upon the ctk-draw layer to actually draw windows
+onto the screen. The ctk-draw layer is free to choose how the window
+will appear on screen; with or without window borders and the style of
+the borders, with or without transparent window background and how the
+background shall look, etc.
+
+The function called by the CTK for drawing a window is:
+
+   void ctk_draw_window(struct ctk_window *window,
+                        unsigned char focus,
+                        unsigned char clipy1,
+                        unsigned char clipy2,
+			unsigned char draw_borders);
+
+The "clipy1" and "clipy2" parameters specify the first and last + 1
+lines on screen that actually should be drawn (if clipy1 = 2 and
+clipy2 = 3, only line 2 should be drawn). The clip parameters are
+given in screen coordinates, so line 1 is the first line below the
+menus.
+
+The focus parameter specifies if the window should be drawn in
+foreground or background colors and can be either CTK_FOCUS_NONE or
+CTK_FOCUS_WINDOW. Windows with a focus of CTK_FOCUS_WINDOW is usually
+drawn in a brighter color than those with CTK_FOCUS_NONE.
+
+The draw_borders parameter specifies if the window frame should be drawn.
+
+Finally, the "window" parameter gives the actual window to be
+drawn. This is specified as a struct ctk_window, which is defined in
+the file ctk/ctk.h as:
+
+   struct ctk_window {
+     struct ctk_window *next, *prev;
+     ek_id_t owner;
+     char *title;
+     unsigned char titlelen;
+     struct ctk_button closebutton;
+     struct ctk_button titlebutton;
+
+     unsigned char x, y;
+     unsigned char w, h;
+
+     struct ctk_widget *inactive;
+     struct ctk_widget *active;
+     struct ctk_widget *focused;
+   };
+
+The first "next" and "prev" fields are pointers used by the CTK for
+keeping the windows on a doubly linked list and are not used by the
+ctk-draw. Likewise, the "owner" field is used by the CTK to keep track
+of the process that created the window, and is not used by
+ctk-draw. The "title" and "titlelen" fields are used by the CTK when
+constructing the desktop menu, and should usually not be used by the
+ctk-draw.
+
+The "closebutton" and "titlebutton" fields are the CTK buttons used in
+the title bar. These should not be used directly by the ctk-draw
+module, as they are already present in the "active" widgets field
+described below. They may be used as a comparison to give special
+treatment to these two widgets however (e.g., if the close button
+should be drawn at the upper left corner instead of the default upper
+right corner), but may otherwise be ignored by the ctk-draw module.
+
+The "x" and "y" fields specify the x and y coordinates of the top left
+corner of the window and the "w" and "h" fields give the width and
+height of the window (excluding any window borders).
+
+Finally, the "inactive" and "active" widget pointers points to linked
+lists of CTK widgets. The "focused" pointer points either to one of
+the widgets in the "active" list, or is NULL if no widget is
+focused. How CTK widgets are drawn is explained below.
+
+A pseudo-code implementation of a ctk_draw_window() function might
+look like this:
+
+   ctk_draw_window(window, focus, clipy1, clipy2, draw_borders) {
+      if(draw_borders) {
+         draw_window_borders(window, focus, clipy1, clipy2);
+      }
+      foreach(widget, window->inactive) {
+         draw_widget(widget, focus, clipy1, clipy2);
+      }
+      foreach(widget, window->active) {
+         if(widget == window->focused) {
+	    draw_widget(widget, focus | CTK_FOCUS_WIDGET,
+	                    clipy1, clipy2);
+	 } else {
+	    draw_widget(widget, focus, clipy1, clipy2);
+	 }
+      }
+   }
+
+Where draw_window_borders() draws the window borders (also between
+clipy1 and clipy2). The draw_widget() function used may the same
+function as ctk_draw_widget() explained later. Notice how the clipy1
+and clipy2 parameters are passed to all other functions; every
+function needs to know the boundaries within which they are allowed to
+draw.
+
+
+* Drawing dialogs *
+-------------------
+
+In CTK, a dialog is similar to a window, with the only exception being
+that they are drawn in a different style. Also, since dialogs always
+are drawn on top of everything else, they do not need to be drawn
+within any special boundaries.
+
+The ctk-draw function that draws a dialog on screen is as follows:
+
+   void ctk_draw_dialog(struct ctk_window *dialog);
+
+It can usually be implemented together with the ctk_draw_window()
+function, which is explained above.
+
+
+* Drawing widgets *
+-------------------
+
+The function that draws the CTK widgets is likely to be the most
+complex function in the ctk-draw module. Still, it is straightforward
+to implement as it can be written in an incremental fashion, starting
+with a single widget type and adding more widget types, one at a time.
+
+The function for drawing widgets is:
+
+   void ctk_draw_widget(struct ctk_widget *widget,
+                        unsigned char focus,
+                        unsigned char clipy1,
+                        unsigned char clipy2);
+
+The "clipy1" and "clipy2" parameters specify the upper and lower
+bounds for the widget. The "focus" parameter specifies how the widget
+is focused and usually is used to decide in what colors the widget is
+to be drawn. The focus is a logical "or" combination of
+CTK_FOCUS_WIDGET and either CTK_FOCUS_WINDOW, CTK_FOCUS_DIALOG or
+CTK_FOCUS_NONE. A non-focused widget in a background window will have
+focus == CTK_FOCUS_NONE, a focused widget in a foreground window will
+have focus == CTK_FOCUS_WIDGET | CTK_FOCUS_WINDOW, and so on.
+
+The ctk-draw module may exploit how the CTK focus constants are
+defined in order to use a look-up table for the colors. The CTK focus
+constants are defined in the file ctk/ctk.h as follows:
+
+   #define CTK_FOCUS_NONE     0
+   #define CTK_FOCUS_WIDGET   1
+   #define CTK_FOCUS_WINDOW   2
+   #define CTK_FOCUS_DIALOG   4
+
+This gives the following table:
+
+   0: CTK_FOCUS_NONE      (Background window, non-focused widget)
+   1: CTK_FOCUS_WIDGET    (Background window, focused widget)
+   2: CTK_FOCUS_WINDOW    (Foreground window, non-focused widget)
+   3: CTK_FOCUS_WINDOW | CTK_FOCUS_WIDGET
+                          (Foreground window, focused widget)
+   4: CTK_FOCUS_DIALOG    (Dialog, non-focused widget)
+   5: CTK_FOCUS_DIALOG | CTK_FOCUS_WIDGET
+                          (Dialog, focused widget)
+
+Finally, the "widget" parameter gives the actual widget that is to be
+drawn. The struct ctk_widget is defined in ctk/ctk.h and looks like:
+
+   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;
+       struct ctk_widget_bitmap bitmap;
+     } widget;
+   };
+
+The "next" pointer points to the next widget in the linked list of
+widgets and should be used by the ctk_draw_window() function when
+stepping through the widgets. It should not be used by the
+ctk_draw_widget() function, however. The "window" pointer points to
+the window in which the widget is contained, and should be used to
+obtain the coordinates for the window.
+
+The "x" and "y" fields are the x and y coordinates of the widget,
+relative to the x and y coordinates of the window in which the widget
+is contained (the "window" pointer). The "type" field specifies what
+kind of widget this is, and the "w" field has the width of the widget.
+
+Finally, the "widget" union holds the actual widget structure. These
+are described below.
+
+
+* The separator widget *
+------------------------
+
+The separator widget is the simplest of all widgets, and do not need
+any more information than what already is present in the struct
+ctk_widget structure: it has x and y coordinates and a width.
+
+
+* The label widget *
+--------------------
+
+The label widget is defined by the struct ctk_widget_label structure
+(accessible from the struct ctk_widget *widget as
+widget->widget.label), which is found in ctk/ctk.h:
+
+   struct ctk_widget_label {
+     char *text;
+     unsigned char h;
+   };
+
+The "text" points to an array of text, and the "h" specifies the
+height of the label. Each line of text in the "text" array is found at
+"w" distance from each other (the "w" is found in the struct
+ctk_widget).
+
+
+* The button widget *
+---------------------
+
+The struct ctk_widget_button looks like:
+
+   struct ctk_widget_button {
+     char *text;
+   };
+
+Where the "text" is the text that is to be displayed on the
+button. The CTK assumes that the button widget will have one character
+of space to the left and right of it (this is usually where the button
+borders are drawn).
+
+
+* The hyperlink widget *
+------------------------
+
+The hyperlink widget is defined by the struct ctk_widget_hyperlink
+structure:
+
+   struct ctk_widget_hyperlink {
+     char *text;
+     char *url;
+   };
+
+The "text" pointer points to the text of the hyperlink, and the "url"
+is the URL to which the hyperlink points. The ctk-draw usually will
+not need to bother with the "url" field. The hyperlink widget usually
+is drawn in a different color than the label widget, preferably
+underlined.
+
+
+* The text entry widget *
+-------------------------
+
+The text entry widget is a little more complicated to draw than the
+other widgets because it has a number of state variables which
+influence the way it should be drawn. The struct ctk_widget_textentry
+looks like this:
+
+   struct ctk_widget_textentry {
+     char *text;
+     unsigned char h;
+     unsigned char len;
+     unsigned char xpos, ypos;
+     unsigned char state;
+   };
+
+Where "text" is the text which is to be edited, "h" is the height of
+the text edit widget, "len" is the length of the line(s) that is being
+edited (which may be different from the width "w" of the
+widget). "xpos" and "ypos" is the position of the cursor in the text
+edit widget and "state" is the state in which the widget is. The state
+can be
+
+   CTK_TEXTENTRY_NORMAL
+
+or
+
+   CTK_TEXTENTRY_EDIT
+
+In the CTK_TEXTENTRY_EDIT state, the text is currenly being edited,
+while in the CTK_TEXTENTRY_NORMAL, the text is not being edited. Text
+entry widgets where the text is being edited should be drawn
+differently than when in the normal state.
+
+
+* The bitmap widget *
+---------------------
+
+The bitmap widget is different from the other CTK widgets because it
+is architecture dependant; there is no standard bitmap format
+specified for Contiki, but this is up to the architecture. (This means
+that application programs that use the bitmap widget must be able to
+draw in the architecture specific format as well.)
+
+The struct ctk_widget_bitmap looks like:
+
+   struct ctk_widget_bitmap {
+     unsigned char *bitmap;
+     unsigned char h;
+   };
+
+Where "h" is the height of the bitmap widget, and "bitmap" is a
+generic pointer that points to an architecture specific
+repressentation of the bitmap.
+
+* The icon widget *
+-------------------
+
+The icon widget is similar to the bitmap widget in that it uses an
+architecture specific bitmap format for the repressentation of the
+graphical icon. It also includes a text version of the icon. XXX: the
+icon widget format is likely to change in the near future!
+
+The struct ctk_widget_icon is defined as:
+
+   struct ctk_widget_icon {
+     char *title;
+     ek_id_t owner;
+     unsigned char *bitmap;
+     char *textmap;
+   };
+
+The "title" field is the name of the icon, and should be drawn below
+the icon picture. The "owner" is the process that created the icon,
+and should normally be ignored by the ctk-draw. The "bitmap" is a
+pointer to an architecture specific repressentation of the icon; the
+same on-screen drawing function can be used for this bitmap as for the
+bitmap widget. Finally, the "textmap" is a text based icon.
+
+Currently, icons are 24x24 pixels large (the text based versions are
+3x3 characters).
+
diff --git a/contiki/doc/pt-doc.txt b/contiki/doc/pt-doc.txt
new file mode 100644
index 0000000..75c80fa
--- /dev/null
+++ b/contiki/doc/pt-doc.txt
@@ -0,0 +1,171 @@
+/**
+\defgroup pt Protothreads 
+@{ 
+
+
+Protothreads are a type of lightweight stackless threads designed for
+severly memory constrained systems such as deeply embedded systems or
+sensor network nodes. Protothreads provides linear code execution for
+event-driven systems implemented in C. Protothreads can be used with
+or without an RTOS.
+
+Protothreads are a extremely lightweight, stackless type of threads
+that provides a blocking context on top of an event-driven system,
+without the overhead of per-thread stacks. The purpose of protothreads
+is to implement sequential flow of control without complex state
+machines or full multi-threading. Protothreads provides conditional
+blocking inside C functions.
+
+The advantage of protothreads over a purely event-driven approach is
+that protothreads provides a sequential code structure that allows for
+blocking functions. In purely event-driven systems, blocking must be
+implemented by manually breaking the function into two pieces - one
+for the piece of code before the blocking call and one for the code
+after the blocking call. This makes it hard to use control structures
+such as if() conditionals and while() loops.
+
+The advantage of protothreads over ordinary threads is that a
+protothread do not require a separate stack. In memory constrained
+systems, the overhead of allocating multiple stacks can consume large
+amounts of the available memory. In contrast, each protothread only
+requires between two and twelve bytes of state, depending on the
+architecture.
+
+\note Because protothreads do not save the stack context across a
+blocking call, <b>local variables are not preserved when the
+protothread blocks</b>. This means that local variables should be used
+with utmost care - <b>if in doubt, do not use local variables inside a
+protothread!</b>
+
+
+Main features:
+
+    - No machine specific code - the protothreads library is pure C
+
+    - Does not use error-prone functions such as longjmp()
+        
+    - Very small RAM overhead - only two bytes per protothread
+    
+    - Can be used with or without an OS
+    
+    - Provides blocking wait without full multi-threading or
+      stack-switching
+
+Examples applications:
+
+    - Memory constrained systems
+    
+    - Event-driven protocol stacks
+    
+    - Deeply embedded systems
+    
+    - Sensor network nodes
+
+The protothreads API consists of four basic operations:
+initialization: PT_INIT(), execution: PT_BEGIN(), conditional
+blocking: PT_WAIT_UNTIL() and exit: PT_END(). On top of these, two
+convenience functions are built: reversed condition blocking:
+PT_WAIT_WHILE() and protothread blocking: PT_WAIT_THREAD().
+
+\sa \ref pt "Protothreads API documentation"
+    
+The protothreads library is released under a BSD-style license that
+allows for both non-commercial and commercial usage. The only
+requirement is that credit is given.
+
+\section authors Authors
+
+The protothreads library was written by Adam Dunkels <adam@sics.se>
+with support from Oliver Schmidt <ol.sc@web.de>.
+
+\section pt-desc Protothreads
+
+Protothreads are a extremely lightweight, stackless threads that
+provides a blocking context on top of an event-driven system, without
+the overhead of per-thread stacks. The purpose of protothreads is to
+implement sequential flow of control without using complex state
+machines or full multi-threading. Protothreads provides conditional
+blocking inside a C function.
+
+In memory constrained systems, such as deeply embedded systems,
+traditional multi-threading may have a too large memory overhead. In
+traditional multi-threading, each thread requires its own stack, that
+typically is over-provisioned. The stacks may use large parts of the
+available memory.
+
+The main advantage of protothreads over ordinary threads is that
+protothreads are very lightweight: a protothread does not require its
+own stack. Rather, all protothreads run on the same stack and context
+switching is done by stack rewinding. This is advantageous in memory
+constrained systems, where a stack for a thread might use a large part
+of the available memory. A protothread only requires only two bytes of
+memory per protothread. Moreover, protothreads are implemented in pure
+C and do not require any machine-specific assembler code.
+
+A protothread runs within a single C function and cannot span over
+other functions. A protothread may call normal C functions, but cannot
+block inside a called function. Blocking inside nested function calls
+is instead made by spawning a separate protothread for each
+potentially blocking function. The advantage of this approach is that
+blocking is explicit: the programmer knows exactly which functions
+that block that which functions the never blocks.
+
+Protothreads are similar to asymmetric co-routines. The main
+difference is that co-routines uses a separate stack for each
+co-routine, whereas protothreads are stackless. The most similar
+mechanism to protothreads are Python generators. These are also
+stackless constructs, but have a different purpose. Protothreads
+provides blocking contexts inside a C function, whereas Python
+generators provide multiple exit points from a generator function.
+
+\section pt-autovars Local variables
+
+\note 
+Because protothreads do not save the stack context across a blocking
+call, local variables are not preserved when the protothread
+blocks. This means that local variables should be used with utmost
+care - if in doubt, do not use local variables inside a protothread!
+
+\section pt-scheduling Scheduling
+
+A protothread is driven by repeated calls to the function in which the
+protothread is running. Each time the function is called, the
+protothread will run until it blocks or exits. Thus the scheduling of
+protothreads is done by the application that uses protothreads.
+
+\section pt-impl Implementation
+
+Protothreads are implemented using \ref lc "local continuations". A
+local continuation represents the current state of execution at a
+particular place in the program, but does not provide any call history
+or local variables. A local continuation can be set in a specific
+function to capture the state of the function. After a local
+continuation has been set can be resumed in order to restore the state
+of the function at the point where the local continuation was set.
+
+
+Local continuations can be implemented in a variety of ways:
+
+   -# by using machine specific assembler code,
+   -# by using standard C constructs, or
+   -# by using compiler extensions. 
+
+The first way works by saving and restoring the processor state,
+except for stack pointers, and requires between 16 and 32 bytes of
+memory per protothread. The exact amount of memory required depends on
+the architecture.
+
+The standard C implementation requires only two bytes of state per
+protothread and utilizes the C switch() statement in a non-obvious way
+that is similar to Duff's device. This implementation does, however,
+impose a slight restriction to the code that uses protothreads in that
+the code cannot use switch() statements itself.
+
+Certain compilers has C extensions that can be used to implement
+protothreads. GCC supports label pointers that can be used for this
+purpose. With this implementation, protothreads require 4 bytes of RAM
+per protothread.
+
+
+*/
+
diff --git a/contiki/doc/release.txt b/contiki/doc/release.txt
new file mode 100644
index 0000000..066c914
--- /dev/null
+++ b/contiki/doc/release.txt
@@ -0,0 +1,74 @@
+This document is a checklist for what steps to take for a Contiki
+release.
+
+Version: $Id: release.txt,v 1.2 2003/04/09 13:45:08 adamdunkels Exp $
+Author: Adam Dunkels
+
+* Update version number for web browser user-agent string:
+- Update version number in apps/http-strings
+- Run ./makestrings in apps/
+
+* Make sure everything is commited by checking out a separate version,
+  compile and run. 
+
+* Tag base code and ports with CONTIKI-MAJOR-MINOR tag.
+
+* Export a version of the base code and ports with the
+  CONTIKI-MAJOR-MINOR tag.
+
+* Copy include files to contiki-devel-environment:
+ - ctk/ctk-draw.h
+ - ctk/ctk-mouse.h
+ - ctk/ctk.h
+ - ek/dispatcher.h
+ - ek/ek.h
+ - ek/loader.h
+ - lib/petsciiconv.h
+ - uip/resolv.h
+ - uip/uip.h
+ - uip/uip_main.h
+ - uip/uipopt.h
+ From port:
+ - ctk/ctk-conf.h
+ - ctk/ek-conf.h
+ - loader/loader-arch.h
+
+* Compile the rs232-eyecandy module and programs in contiki-c64
+ - gmake clean rs232-eyecandy programs
+
+* Make D64 image in contiki-c64
+ - gmake d64
+
+* Rename D64 image to contiki-minor.major.d64
+
+* Copy .prg programs from port to contiki-devel-environment
+
+* Copy contiki, contiki-labels.o and loader-arch-module.o into
+  contiki-devel-environment
+
+* Rename contiki to contiki-minor.major and contiki-labels.o to
+  contiki-labels-minor.major.o
+
+* Update Makefile in contiki-devel-environment to use
+  contiki-labels-minor.major.o 
+
+* Compile and run test program in contiki-devel-environment
+
+* Commit in contiki-devel-environment
+
+* Tag contiki-devel-environment with CONTIKI-MAJOR-MINOR tag.
+
+* Export clean CONTIKI-MAJOR-MINOR sources for base, ports and
+  contiki-devel-enviroment 
+
+* Copy contiki, contiki-labels.o and loader-arch-module.o into
+  clean contiki-devel-environment
+
+* Rename directories to <dirname>-major.minor
+
+* Create tarball and zip of the clean base code and ports.
+
+* Create tarball and zip of the contiki-devel-environment with
+  contiki, contiki-labels.o and loader-arch-module.o
+
+* Create zip and gz of the D64 image.
diff --git a/contiki/doc/uip-doc.txt b/contiki/doc/uip-doc.txt
new file mode 100644
index 0000000..c4203d6
--- /dev/null
+++ b/contiki/doc/uip-doc.txt
@@ -0,0 +1,393 @@
+/**
+\defgroup uip The uIP TCP/IP stack
+@{
+
+The uIP TCP/IP stack provides Internet communication abilities to
+Contiki.
+
+\section uip-introduction uIP introduction
+
+With the success of the Internet, the TCP/IP protocol suite has become
+a global standard for communication. TCP/IP is the underlying protocol
+used for web page transfers, e-mail transmissions, file transfers, and
+peer-to-peer networking over the Internet. For embedded systems, being
+able to run native TCP/IP makes it possible to connect the system
+directly to an intranet or even the global Internet. Embedded devices
+with full TCP/IP support will be first-class network citizens, thus
+being able to fully communicate with other hosts in the network.
+
+Traditional TCP/IP implementations have required far too much
+resources both in terms of code size and memory usage to be useful in
+small 8 or 16-bit systems. Code size of a few hundred kilobytes and
+RAM requirements of several hundreds of kilobytes have made it
+impossible to fit the full TCP/IP stack into systems with a few tens
+of kilobytes of RAM and room for less than 100 kilobytes of
+code.
+
+The uIP implementation is designed to have only the absolute minimal
+set of features needed for a full TCP/IP stack. It can only handle a
+single network interface and does not implement UDP, but focuses on
+the IP, ICMP and TCP protocols. uIP is written in the C programming
+language.
+
+Many other TCP/IP implementations for small systems assume that the
+embedded device always will communicate with a full-scale TCP/IP
+implementation running on a workstation-class machine. Under this
+assumption, it is possible to remove certain TCP/IP mechanisms that
+are very rarely used in such situations. Many of those mechanisms are
+essential, however, if the embedded device is to communicate with
+another equally limited device, e.g., when running distributed
+peer-to-peer services and protocols. uIP is designed to be RFC
+compliant in order to let the embedded devices to act as first-class
+network citizens. The uIP TCP/IP implementation that is not tailored
+for any specific application.
+
+
+\section uip-tcpip TCP/IP communication
+
+The full TCP/IP suite consists of numerous protocols, ranging from low
+level protocols such as ARP which translates IP addresses to MAC
+addresses, to application level protocols such as SMTP that is used to
+transfer e-mail. The uIP is mostly concerned with the TCP and IP
+protocols and upper layer protocols will be refered to as ``the
+application''. Lower layer protocols are often implemented in hardware
+or firmware and will be referred to as ``the network device'' that are
+controlled by the network device driver.
+
+TCP provides a reliable byte stream to the upper layer protocols. It
+breaks the byte stream into appropriately sized segments and each
+segment is sent in its own IP packet. The IP packets are sent out on
+the network by the network device driver. If the destination is not on
+the physically connected network, the IP packet is forwarded onto
+another network by a router that is situated between the two
+networks. If the maximum packet size of the other network is smaller
+than the size of the IP packet, the packet is fragmented into smaller
+packets by the router. If possible, the size of the TCP segments are
+chosen so that fragmentation is minimized. The final recipient of the
+packet will have to reassemble any fragmented IP packets before they
+can be passed to higher layers.
+
+The formal requirements for the protocols in the TCP/IP stack is
+specified in a number of RFC documents published by the Internet
+Engineering Task Force, IETF. Each of the protocols in the stack is
+defined in one more RFC documents and RFC1122 collects
+all requirements and updates the previous RFCs. 
+
+The RFC1122 requirements can be divided into two categories; those
+that deal with the host to host communication and those that deal with
+communication between the application and the networking stack. An
+example of the first kind is "A TCP MUST be able to receive a TCP
+option in any segment" and an example of the second kind is "There
+MUST be a mechanism for reporting soft TCP error conditions to the
+application." A TCP/IP implementation that violates requirements of
+the first kind may not be able to communicate with other TCP/IP
+implementations and may even lead to network failures. Violation of
+the second kind of requirements will only affect the communication
+within the system and will not affect host-to-host communication.
+
+In our implementations, we have implemented all RFC requirements that
+affect host-to-host communication. However, in order to reduce code
+size, we have removed certain mechanisms in the interface between the
+application and the stack, such as the soft error reporting mechanism
+and dynamically configurable type-of-service bits for TCP
+connections. Since there are only very few applications that make use
+of those features they can be removed without loss of generality.
+
+\section uip-memory Memory management
+
+In the architectures for which uIP is intended, RAM is the most
+scarce resource. With only a few kilobytes of RAM available for the
+TCP/IP stack to use, mechanisms used in traditional TCP/IP cannot be
+directly applied.
+
+
+The uIP stack does not use explicit dynamic memory
+allocation. Instead, it uses a single global buffer for holding
+packets and has a fixed table for holding connection state. The global
+packet buffer is large enough to contain one packet of maximum
+size. When a packet arrives from the network, the device driver places
+it in the global buffer and calls the TCP/IP stack. If the packet
+contains data, the TCP/IP stack will notify the corresponding
+application. Because the data in the buffer will be overwritten by the
+next incoming packet, the application will either have to act
+immediately on the data or copy the data into a secondary buffer for
+later processing. The packet buffer will not be overwritten by new
+packets before the application has processed the data. Packets that
+arrive when the application is processing the data must be queued,
+either by the network device or by the device driver. Most single-chip
+Ethernet controllers have on-chip buffers that are large enough to
+contain at least 4 maximum sized Ethernet frames. Devices that are
+handled by the processor, such as RS-232 ports, can copy incoming
+bytes to a separate buffer during application processing. If the
+buffers are full, the incoming packet is dropped. This will cause
+performance degradation, but only when multiple connections are
+running in parallel. This is because uIP advertises a very small
+receiver window, which means that only a single TCP segment will be in
+the network per connection.
+
+In uIP, the same global packet buffer that is used for incoming
+packets is also used for the TCP/IP headers of outgoing data. If the
+application sends dynamic data, it may use the parts of the global
+packet buffer that are not used for headers as a temporary storage
+buffer. To send the data, the application passes a pointer to the data
+as well as the length of the data to the stack. The TCP/IP headers are
+written into the global buffer and once the headers have been
+produced, the device driver sends the headers and the application data
+out on the network. The data is not queued for
+retransmissions. Instead, the application will have to reproduce the
+data if a retransmission is necessary.
+
+The total amount of memory usage for uIP depends heavily on the
+applications of the particular device in which the implementations are
+to be run. The memory configuration determines both the amount of
+traffic the system should be able to handle and the maximum amount of
+simultaneous connections. A device that will be sending large e-mails
+while at the same time running a web server with highly dynamic web
+pages and multiple simultaneous clients, will require more RAM than a
+simple Telnet server. It is possible to run the uIP implementation
+with as little as 200 bytes of RAM, but such a configuration will
+provide extremely low throughput and will only allow a small number of
+simultaneous connections.
+
+\section uip-api Application program interface (API)
+
+The Application Program Interface (API) defines the way the
+application program interacts with the TCP/IP stack. The most commonly
+used API for TCP/IP is the BSD socket API which is used in most Unix
+systems and has heavily influenced the Microsoft Windows WinSock
+API. Because the socket API uses stop-and-wait semantics, it requires
+support from an underlying multitasking operating system. Since the
+overhead of task management, context switching and allocation of stack
+space for the tasks might be too high in the intended uIP target
+architectures, the BSD socket interface is not suitable for our
+purposes.
+
+Instead, uIP uses an event driven interface where the application is
+invoked in response to certain events. An application running on top
+of uIP is implemented as a C function that is called by uIP in
+response to certain events. uIP calls the application when data is
+received, when data has been successfully delivered to the other end
+of the connection, when a new connection has been set up, or when data
+has to be retransmitted. The application is also periodically polled
+for new data. The application program provides only one callback
+function; it is up to the application to deal with mapping different
+network services to different ports and connections. Because the
+application is able to act on incoming data and connection requests as
+soon as the TCP/IP stack receives the packet, low response times can
+be achieved even in low-end systems.
+
+uIP is different from other TCP/IP stacks in that it requires help
+from the application when doing retransmissions. Other TCP/IP stacks
+buffer the transmitted data in memory until the data is known to be
+successfully delivered to the remote end of the connection. If the
+data needs to be retransmitted, the stack takes care of the
+retransmission without notifying the application. With this approach,
+the data has to be buffered in memory while waiting for an
+acknowledgment even if the application might be able to quickly
+regenerate the data if a retransmission has to be made.
+
+In order to reduce memory usage, uIP utilizes the fact that the
+application may be able to regenerate sent data and lets the
+application take part in retransmissions. uIP does not keep track of
+packet contents after they have been sent by the device driver, and
+uIP requires that the application takes an active part in performing
+the retransmission. When uIP decides that a segment should be
+retransmitted, it calls the application with a flag set indicating
+that a retransmission is required. The application checks the
+retransmission flag and produces the same data that was previously
+sent. From the application's standpoint, performing a retransmission
+is not different from how the data originally was sent. Therefore the
+application can be written in such a way that the same code is used
+both for sending data and retransmitting data. Also, it is important
+to note that even though the actual retransmission operation is
+carried out by the application, it is the responsibility of the stack
+to know when the retransmission should be made. Thus the complexity of
+the application does not necessarily increase because it takes an
+active part in doing retransmissions.
+
+\subsection uip-appevents Application events
+
+The application must be implemented as a C function, UIP_APPCALL(),
+that uIP calls whenever an event occurs. Each event has a corresponing
+test function that is used to distinguish between different
+events. The functions are implemented as C macros that will evaluate
+to either zero or non-zero. Note that certain events can happen in
+conjunction with each other (i.e., new data can arrive at the same
+time as data is acknowledged).
+
+\subsection uip-connstate The connection pointer
+
+When the application is called by uIP, the global variable uip_conn is
+set to point to the uip_conn structure for the current
+connection. This can be used to distinguish between different
+services. A typical use would be to inspect the uip_conn->lport (the
+local TCP port number) to decide which service the connection should
+provide. For instance, an application might decide to act as an HTTP
+server if the value of uip_conn->lport is equal to 80 and act as a
+TELNET server if the value is 23.
+
+\subsection uip-recvdata Receiving data
+
+If the uIP test function uip_newdata() is non-zero, the remote host of
+the connection has sent new data. The uip_appdata pointer point to the
+actual data. The size of the data is obtained through the uIP function
+uip_datalen(). The data is not buffered by uIP, but will be
+overwritten after the application function returns, and the
+application will therefor have to either act directly on the incoming
+data, or by itself copy the incoming data into a buffer for later
+processing.
+
+\subsection uip-senddata Sending data
+
+When sending data, the application must check the number of available
+bytes in the send window and adjust the length of the data to be sent
+accordingly. The size of the send window is dictated by the memory
+configuration as well as the buffer space announced by the remote
+host. If no buffer space is available, the application has to defer
+the send and wait until later.
+
+The application sends data by using the uIP function uip_send(). The
+uip_send() function takes two arguments; a pointer to the data to be
+sent and the length of the data. If the application needs RAM space
+for producing the actual data that should be sent, the packet buffer
+(pointed to by the uip_appdata pointer) can be used for this purpose.
+
+The application can send only one chunk of data at a time on a
+connection and it is not possible to call uip_send() more than once
+per application invocation; only the data from the last call will be
+sent.
+
+\subsection uip-rexmitdata Retransmitting data
+
+Retransmissions are driven by the periodic TCP timer. Every time the
+periodic timer is invoked, the retransmission timer for each
+connection is decremented. If the timer reaches zero, a retransmission
+should be made. As uIP does not keep track of packet contents after they have
+been sent by the device driver, uIP requires that the
+application takes an active part in performing the
+retransmission. When uIP decides that a segment should be
+retransmitted, the application function is called with the
+uip_rexmit() flag set, indicating that a retransmission is
+required.
+
+The application must check the uip_rexmit() flag and produce the same
+data that was previously sent. From the application's standpoint,
+performing a retransmission is not different from how the data
+originally was sent. Therefor, the application can be written in such
+a way that the same code is used both for sending data and
+retransmitting data. Also, it is important to note that even though
+the actual retransmission operation is carried out by the application,
+it is the responsibility of the stack to know when the retransmission
+should be made. Thus the complexity of the application does not
+necessarily increase because it takes an active part in doing
+retransmissions.
+
+\subsection uip-closing Closing connections
+
+The application closes the current connection by calling the
+uip_close() during an application call. This will cause the connection
+to be cleanly closed. In order to indicate a fatal error, the
+application might want to abort the connection and does so by calling
+the uip_abort() function.
+
+If the connection has been closed by the remote end, the test function
+uip_closed() is true. The application may then do any necessary
+cleanups.
+
+\subsection uip-errors Reporting errors
+
+There are two fatal errors that can happen to a connection, either
+that the connection was aborted by the remote host, or that the
+connection retransmitted the last data too many times and has been
+aborted. uIP reports this by calling the application function. The
+application can use the two test functions uip_aborted() and
+uip_timedout() to test for those error conditions.
+
+\subsection uip-polling Polling
+
+When a connection is idle, uIP polls the application every time the
+periodic timer fires. The application uses the test function
+uip_poll() to check if it is being polled by uIP.
+
+The polling event has two purposes. The first is to let the
+application periodically know that a connection is idle, which allows
+the application to close connections that have been idle for too
+long. The other purpose is to let the application send new data that
+has been produced. The application can only send data when invoked by
+uIP, and therefore the poll event is the only way to send data on an
+otherwise idle connection.
+
+\subsection uip-listen Listening ports
+
+uIP maintains a list of listening TCP ports. A new port is opened for
+listening with the uip_listen() function. When a connection request
+arrives on a listening port, uIP creates a new connection and calls
+the application function. The test function uip_connected() is true if
+the application was invoked because a new connection was created.
+
+The application can check the lport field in the uip_conn structure to
+check to which port the new connection was connected.
+
+\subsection uip-connect Opening connections
+
+New connections can be opened from within
+uIP by the function uip_connect(). This function
+allocates a new connection and sets a flag in the connection state
+which will open a TCP connection to the specified IP address and port
+the next time the connection is polled by uIP. The uip_connect()
+function returns
+a pointer to the uip_conn structure for the new
+connection. If there are no free connection slots, the function
+returns NULL. 
+
+The function uip_ipaddr() may be used to pack an IP address into the
+two element 16-bit array used by uIP to represent IP addresses.
+
+Two examples of usage are shown below. The first example shows how to
+open a connection to TCP port 8080 of the remote end of the current
+connection. If there are not enough TCP connection slots to allow a
+new connection to be opened, the uip_connect() function returns NULL
+and the current connection is aborted by uip_abort(). 
+
+\code
+void connect_example1_app(void) {
+   if(uip_connect(uip_conn->ripaddr, 8080) == NULL) {
+      uip_abort();
+   }
+}   
+\endcode
+
+The second example shows how to open a new connection to a specific IP
+address. No error checks are made in this example.
+
+\code
+void connect_example2(void) {
+   u16_t ipaddr[2];
+
+   uip_ipaddr(ipaddr, 192,168,0,1);
+   uip_connect(ipaddr, 8080);
+}
+\endcode
+
+\section uip-drivers uIP device drivers
+
+From the network device driver's standpoint, uIP consists of two C
+functions: uip_input() and uip_periodic(). The uip_input() function
+should be called by the device driver when an IP packet has been
+received and put into the uip_buf packet buffer. The uip_input()
+function will process the packet, and when it returns an outbound
+packet may have been placed in the same uip_buf packet buffer
+(indicated by the uip_len variable being non-zero). The device driver
+should then send out this packet onto the network.
+
+The uip_periodic() function should be invoked periodically once per
+connection by the device driver, typically one per second. This
+function is used by uIP to drive protocol timers and retransmissions,
+and when it returns it may have placed an outbound packet in the
+uip_buf buffer.
+
+
+
+*/
+
+/** @} */
\ No newline at end of file
diff --git a/contiki/ek/FILES b/contiki/ek/FILES
new file mode 100644
index 0000000..ad859d6
--- /dev/null
+++ b/contiki/ek/FILES
@@ -0,0 +1,46 @@
+The contiki/ek/ directory contains the source code for the Contiki
+kernel and the concurrency libraries (multithreading, protothreads).
+
+arc.[ch]
+
+  Implementation of the argument buffer.
+
+contiki-version.h
+
+  A string holding the current version of Contiki.
+
+contiki.h
+
+  Header file which includes the core Contiki includes.
+
+dsc.h
+
+  Header file for the DSC file description format used by Contiki.
+
+ek-service.[ch]
+
+  The Contiki service layer.
+
+ek.[ch]
+
+  The Contiki event-driven kernel.
+
+loader.h
+
+  Header file for the program loader.
+
+log.h
+
+  Header file for the system logging facility.
+
+mt.[ch]
+
+  Multithreading library.
+
+pt.h
+
+  Protothreads implementation.
+
+pt-sem.h
+
+  Semaphores for protothreads.              
diff --git a/contiki/ek/arg.c b/contiki/ek/arg.c
new file mode 100644
index 0000000..6d533b2
--- /dev/null
+++ b/contiki/ek/arg.c
@@ -0,0 +1,131 @@
+/**
+ * \file
+ * Argument buffer for passing arguments when starting processes
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/**
+ * \addtogroup kernel
+ * @{
+ */
+
+/**
+ * \page arg Argument buffer
+ *
+ * The argument buffer can be used when passing an argument from an
+ * exiting process to a process that has not been created yet. Since
+ * the exiting process will have exited when the new process is
+ * started, the argument cannot be passed in any of the processes'
+ * addres spaces. In such situations, the argument buffer can be used.
+ *
+ * The argument buffer is statically allocated in memory and is
+ * globally accessible to all processes.
+ *
+ * An argument buffer is allocated with the arg_alloc() function and
+ * deallocated with the arg_free() function. The arg_free() function
+ * is designed so that it can take any pointer, not just an argument
+ * buffer pointer. If the pointer to arg_free() is not an argument
+ * buffer, the function does nothing.
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: arg.c,v 1.3 2003/10/01 07:53:57 adamdunkels Exp $
+ *
+ */
+
+#include "arg.h"
+
+/**
+ * \internal Structure used for holding an argument buffer.
+ */
+struct argbuf {
+  char buf[128];
+  char used;
+};
+
+static struct argbuf bufs[1];
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * \internal Initalizer, called by the dispatcher module.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+arg_init(void)
+{
+  bufs[0].used = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Allocates an argument buffer.
+ *
+ * \param size The requested size of the buffer, in bytes.
+ *
+ * \return Pointer to allocated buffer, or NULL if no buffer could be
+ * allocated.
+ *
+ * \note It currently is not possible to allocate argument buffers of
+ * any other size than 128 bytes.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+char *
+arg_alloc(char size)
+{
+  if(bufs[0].used == 0) {
+    bufs[0].used = 1;
+    return bufs[0].buf;
+  } 
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Deallocates an argument buffer.
+ *
+ * This function deallocates the argument buffer pointed to by the
+ * parameter, but only if the buffer actually is an argument buffer
+ * and is allocated. It is perfectly safe to call this function with
+ * any pointer.
+ *
+ * \param arg A pointer.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+arg_free(char *arg)
+{
+  if(arg == bufs[0].buf) {
+    bufs[0].used = 0;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/** @} */
diff --git a/contiki/ek/arg.h b/contiki/ek/arg.h
new file mode 100644
index 0000000..aed23f8
--- /dev/null
+++ b/contiki/ek/arg.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: arg.h,v 1.2 2004/06/06 06:06:34 adamdunkels Exp $
+ *
+ */
+#ifndef __ARG_H__
+#define __ARG_H__
+
+void arg_init(void);
+
+char *arg_alloc(char size);
+void arg_free(char *arg);
+
+#endif /* __ARG_H__ */
diff --git a/contiki/ek/contiki-version.h b/contiki/ek/contiki-version.h
new file mode 100644
index 0000000..f739f97
--- /dev/null
+++ b/contiki/ek/contiki-version.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: contiki-version.h,v 1.6 2006/05/30 21:04:47 oliverschmidt Exp $
+ */
+#ifndef __CONTIKI_VERSION__
+#define __CONTIKI_VERSION__
+
+#ifndef CONTIKI_VERSION_STRING
+#define CONTIKI_VERSION_STRING "Contiki 1.3"
+#endif /* CONTIKI_VERSION_STRING */
+
+#endif /* __CONTIKI_VERSION__ */
diff --git a/contiki/ek/contiki.h b/contiki/ek/contiki.h
new file mode 100644
index 0000000..b6ea092
--- /dev/null
+++ b/contiki/ek/contiki.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: contiki.h,v 1.5 2005/02/22 22:43:36 adamdunkels Exp $
+ */
+#ifndef __CONTIKI_H__
+#define __CONTIKI_H__
+
+#include "contiki-version.h"
+
+#include "ek.h"
+#include "ek-service.h"
+#include "uip.h"
+#include "uiplib.h"
+#include "resolv.h"
+#include "tcpip.h"
+#include "memb.h"
+#include "timer.h"
+
+
+#endif /* __CONTIKI_H__ */
diff --git a/contiki/ek/dsc.h b/contiki/ek/dsc.h
new file mode 100644
index 0000000..15f408c
--- /dev/null
+++ b/contiki/ek/dsc.h
@@ -0,0 +1,135 @@
+/**
+ * \file
+ * Declaration of the DSC program description structure.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/**
+ * \addtogroup loader
+ * @{
+ */
+
+/**
+ * \page dsc The program description structure
+ *
+ * The Contiki DSC structure is used for describing programs. It
+ * includes a string describing the program, the name of the program
+ * file on disk (or a pointer to the programs initialization function
+ * for systems without disk support), a bitmap icon and a text version
+ * of the same icon.
+ *
+ * The DSC is saved into a file which can be loaded by programs such
+ * as the "Directory" application which reads all DSC files on disk
+ * and presents the icons and descriptions in a window.
+ *
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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: dsc.h,v 1.7 2005/03/18 00:40:30 oliverschmidt Exp $
+ *
+ */
+#ifndef __DSC_H__
+#define __DSC_H__
+
+#include "ctk.h"
+
+/**
+ * The DSC program description structure.
+ *
+ * The DSC structure is used for describing a Contiki program. It
+ * includes a short textual description of the program, either the
+ * name of the program on disk, or a pointer to the init() function,
+ * and an icon for the program.
+ */
+struct dsc {
+  char *description; /**< A text string containing a one-line
+			description of the program */
+  
+#if WITH_LOADER_ARCH
+  char *prgname;     /**< The name of the program on disk. */
+#else /* WITH_LOADER_ARCH */
+  void (*init)(char *arg); /**< A pointer to the initialization
+			      function of the program .*/
+#endif /* WITH_LOADER_ARCH */
+  
+  struct ctk_icon *icon;  /**< A pointer to the ctk_icon structure for
+			     the DSC. */
+ 
+#if WITH_LOADER_ARCH
+  void *loadaddr;         /**< The loading address of the DSC. Used by
+			     the LOADER_UNLOAD() function when
+			     deallocating the memory allocated for the
+			     DSC when loading it. */
+#endif /* WITH_LOADER_ARCH */
+};
+
+#if CTK_CONF_ICONS
+#define DSC_ICON(icon) icon
+#else
+#define DSC_ICON(icon) NULL
+#endif
+
+/**
+ * Intantiating macro for the DSC structure.
+ *
+ * \param dscname The name of the C variable which is to contain the
+ * DSC.
+ *
+ * \param description A one-line text describing the program.
+ *
+ * \param prgname The name of the program on disk.
+ *
+ * \param initfunc A pointer to the initialization function of the
+ * program.
+ *
+ * \param icon A pointer to the CTK icon.
+ */
+#if WITH_LOADER_ARCH
+#define DSC(dscname, description, prgname, initfunc, icon) \
+        const struct dsc dscname = {description, prgname, DSC_ICON(icon)}
+#else /* WITH_LOADER_ARCH */
+#define DSC(dscname, description, prgname, initfunc, icon) \
+    void initfunc(char *arg); \
+    const struct dsc dscname = {description, initfunc, DSC_ICON(icon)}
+#endif /* WITH_LOADER_ARCH */
+
+#define DSC_HEADER(name) extern struct dsc name;
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+/** @} */
+
+#endif /* _DSC_H__ */
diff --git a/contiki/ek/ek-service.c b/contiki/ek/ek-service.c
new file mode 100644
index 0000000..e77b754
--- /dev/null
+++ b/contiki/ek/ek-service.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ek-service.c,v 1.6 2005/02/07 07:50:35 adamdunkels Exp $
+ */
+
+#include "ek-service.h"
+
+#include "log.h"
+
+/*---------------------------------------------------------------------------*/
+ek_id_t
+ek_service_start(const char *name, struct ek_proc *p)
+{
+  ek_id_t service;
+  
+  service = ek_find(name);
+
+  if(service == EK_ID_NONE) {
+    log_message("ek-service: starting ", name);
+    return ek_start(p);
+  } else {
+    log_message("ek-service: replacing ", name);
+    ek_post_synch(service, EK_EVENT_REQUEST_REPLACE, p);
+    return service;
+  } 
+
+}
+/*---------------------------------------------------------------------------*/
+ek_err_t
+ek_service_find(struct ek_service *s)
+{
+  ek_id_t id;
+  id = ek_find(s->name);
+  s->id = id;
+  if(s->id == EK_ID_NONE) {
+    return EK_ERR_NOTFOUND;
+  }
+  return EK_ERR_OK;
+}
+/*---------------------------------------------------------------------------*/
+void *
+ek_service_state(struct ek_service *s)
+{
+  if(s->id == EK_ID_NONE) {
+    if(ek_service_find(s) == EK_ERR_NOTFOUND) {
+      return NULL;
+    }
+  }
+  return ek_procstate(s->id);  
+}
+/*---------------------------------------------------------------------------*/
+void
+ek_service_reset(struct ek_service *s)
+{
+  log_message("ek-service: reseting ", s->name);
+  s->id = EK_ID_NONE;
+}
+/*---------------------------------------------------------------------------*/
+#if 0
+unsigned char
+ek_service_ref(struct ek_service *s)
+{
+}
+/*---------------------------------------------------------------------------*/
+unsigned char
+ek_service_unref(struct ek_service *s)
+{
+}
+#endif 
+/*---------------------------------------------------------------------------*/
+
diff --git a/contiki/ek/ek-service.h b/contiki/ek/ek-service.h
new file mode 100644
index 0000000..ebede37
--- /dev/null
+++ b/contiki/ek/ek-service.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ek-service.h,v 1.4 2005/02/07 07:50:35 adamdunkels Exp $
+ */
+
+/**
+ * \addtogroup ek
+ * @{
+ */
+
+/**
+ * \defgroup ekservice The service layer
+ * @{
+ */
+
+/**
+ * \file
+ * Service layer header file.
+ * \author Adam Dunkels <adam@sics.se>
+ */
+
+#ifndef __EK_SERVICE_H__
+#define __EK_SERVICE_H__
+
+#include "ek.h"
+
+struct ek_service {
+  const char *name;
+  ek_id_t id;
+};
+
+/**
+ * Declare a service state.
+ *
+ * This macro declares a service state. The service state is used to
+ * access a particular service. The declared service state serves as
+ * the input to all other service functions.
+ *
+ * \param service The name of the service state.
+ * \param name The name of the service - this is defined in the header file of the service.
+ *
+ * \hideinitializer
+ */
+#define EK_SERVICE(service, name) \
+ static struct ek_service service = {name, EK_ID_NONE}
+
+/**
+ * Start a service.
+ *
+ * This function is called from within a service in order to start the
+ * service process and to register the service with Contiki. If
+ * another instance of the same service is running, it is requested to
+ * shut itself down before the current service is started.
+ *
+ * This function is the equivalent of ek_start() but for services.
+ *
+ * \note Do not call the function ek_start() from a service, use
+ * ek_service_start() instead.
+ *
+ * \param name The name of the service. The first part of the name
+ * must be indentical for all services of the same kind.
+ *
+ * \param p The process structure for the service.
+ *
+ * \return The process ID of the service.
+ */ 
+ek_id_t ek_service_start(const char *name, struct ek_proc *p);
+
+/**
+ * Find a running service.
+ *
+ * This function finds a running service. The function is called from
+ * programs that utilize the service, not from within a service process.
+ *
+ * Example:
+ \code
+ #include "packet-service.h"
+ 
+ EK_SERVICE(packetservice, PACKET_SERVICE_NAME);
+
+ void stop_packetservice(void) {
+   if(ek_service_find(&packetservice) == EK_ERR_OK) {
+     ek_service_post(&packetservice, EK_EVENT_REQUEST_EXIT, NULL);
+     ek_service_reset(&packetservice);
+   }
+ }
+ \endcode
+ *
+ * \param s The service state. This state is filled in with
+ * information by the ek_service_find() function.
+ *
+ * \retval EK_ERR_OK The requested service was found.
+ * \retval EK_ERR_NOTFOUND The requested service was not found.
+ */
+ek_err_t ek_service_find(struct ek_service *s);
+
+/**
+ * Retrieve the service interface for a running service.
+ *
+ * This function retrieves the service interface (the API for the
+ * service) for a running service. The service state must first have
+ * been looked up using the ek_service_find() function.
+ *
+ * This function is used in the service stub.
+ *
+ * Example
+ \code
+ #include "packet-service.h"
+  
+ EK_SERVICE(packetservice, PACKET_SERVICE_NAME);
+
+ static struct packet_service_interface *
+ find_interface(void)
+ {
+   struct packet_service_interface *interface;
+   interface = (struct packet_service_interface *)ek_service_state(&service);
+   if(interface != NULL &&
+      interface->version == PACKET_SERVICE_VERSION) {
+     return interface;
+   } else {
+     return NULL;
+   }
+ }
+ \endcode
+ *
+ * \param s The service state that previously has been looked up with
+ * ek_service_find().
+ *
+ * \return A pointer to the service interface if the requested service
+ * is running, or NULL if no such service was found.
+ */
+void *ek_service_state(struct ek_service *s);
+
+/**
+ * Reset a service.
+ *
+ * When a service is looked up by Contiki, the process ID of the
+ * service is cached. This function resets the cache so that a running
+ * service can be removed from the system.
+ *
+ * Example:
+ \code
+ #include "packet-service.h"
+ 
+ EK_SERVICE(packetservice, PACKET_SERVICE_NAME);
+
+ void stop_packetservice(void) {
+   if(ek_service_find(&packetservice) == EK_ERR_OK) {
+     ek_service_post(&packetservice, EK_EVENT_REQUEST_EXIT, NULL);
+     ek_service_reset(&packetservice);
+   }
+ }
+ \endcode
+ *
+ * \param s The service state.
+ */
+void ek_service_reset(struct ek_service *s);
+
+/**
+ * Post an event to a running service.
+ *
+ * This macro posts an event to a running service. The service must
+ * first be looked up using ek_service_find().
+ *
+ * \sa ek_post().
+ *
+ * \param s The service state
+ * \param ev The event to be posted.
+ * \param data An opaque pointer to be posted with the event.
+ * 
+ * \hideinitializer
+ */
+#define ek_service_post(s, ev, data) ek_post((s)->id, (ev), (data))
+
+/*ek_err_t ek_service_call(struct ek_service *s,
+  ek_event_t ev, ek_data_t data);*/
+
+/** @} */
+/** @} */
+
+#endif /* __EK_SERVICE_H__ */
+
diff --git a/contiki/ek/ek.c b/contiki/ek/ek.c
new file mode 100644
index 0000000..c570dc6
--- /dev/null
+++ b/contiki/ek/ek.c
@@ -0,0 +1,601 @@
+/**
+ * \defgroup ek The Contiki event kernel
+ * @{
+ *
+ * At the heart of the Contiki desktop environment is the event driven
+ * Contiki kernel. Using non-preemptive multitasking, the Contiki
+ * event kernel makes it possible to run several programs in
+ * parallel. It also provides message passing mechanisms to the
+ * running programs.
+ *
+ * The Contiki kernel is a simple event driven dispatcher which
+ * handles processes and events. All code execution is
+ * initiated by the kernel, and applications are implemented as C
+ * functions that must return within a short time after being
+ * called.
+ *
+ * The kernel does not provide multi-threading. Rather, this is
+ * implemented as an application library. For threads, see the
+ * \ref mt "Multithreading library" and \ref pt "Protothreads".
+ *
+ * The kernel is the initiator of all program execution in
+ * Contiki. After the system has been initialized by the boot up code,
+ * the ek_run() function is called. This function never
+ * returns, but will sit in a loop in which it does two things.
+ * 
+ * - Pulls the first event of the event queue and dispatches this to
+ *   all listening processes (ek_process_event()).
+ *
+ * - Executes the "poll" handlers of all processes that have
+ *   registered (ek_process_poll()).
+ *
+ * Only one event is processes at a time, and the poll handlers of
+ * all processes are called between two events are handled.
+ *
+ * 
+ * A process is defined by an initialization function, a event
+ * handler, a uIP event handler, and an poll handler. The event
+ * handler is called when a event has been posted, for which the
+ * process is currently listening. The uIP event handler is called
+ * when the uIP TCP/IP stack has an event to deliver to the
+ * process. Such events can be that new data has arrived on a
+ * connection, that previously sent data has been acknowledged or that
+ * a connection has been closed. The poll handler is periodically
+ * called by the system.
+ *
+ * A process is started by calling the ek_start()
+ * function. This function must be called by the initialization
+ * function before any other kernel function is called. When the
+ * function returns, the new process is running. 
+ *
+ * The initialization function is declared with the special
+ * LOADER_INIT() macro. The initializaition function takes a single
+ * argument; a char * pointer.
+ *
+ * The function ek_exit() is used to tell the kernel that
+ * a process has exited. This function must be called by the process
+ * itself, and must be called the process unloads itself.
+ *
+ * \note It is not possible to call ek_exit() on behalf of
+ * another process - instead, post the event ek_event_quit
+ * with the process as a receiver. The other process should then
+ * listen for this event, and call ek_exit() when the event
+ * is received. 
+ *
+ *
+ * The kernel can pass events between different
+ * processes. Events are simple messages that consist of a event
+ * number and a generic data pointer called the event data. The
+ * event data can be used to pass messages between processes. In
+ * order for a event to be delivered to a process, the process must
+ * be listening for the event number.
+ *
+ * If a process has registered an poll handler, the kernel will
+ * call it as often as possible. The poll handler can be used to
+ * implement timer based functionality (by checking the ek_clock()
+ * function), or other background processing. The poll handler must
+ * return to the caller within a short time, or otherwise the system
+ * will become sluggish.
+ *
+ *
+ */
+
+
+/**
+ * \file
+ * Event kernel.
+ * \author Adam Dunkels <adam@dunkels.com> 
+ *
+ * The kernel in Contiki handles processes and events. All process
+ * execution is initiated by the kernel.
+ */
+/*
+ * Copyright (c) 2002-2003, 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. 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.9 2007/06/02 07:32:05 ryohji Exp $
+ *
+ */
+
+#include "ek.h"
+
+#include <string.h> /* for strncmp() */
+
+/**
+ * \internal Pointer to the currently running process structure.
+ *
+ */
+struct ek_proc *ek_procs = NULL;
+struct ek_proc *ek_proclist[EK_CONF_MAXPROCS];
+struct ek_proc *ek_current = NULL;
+ 
+ek_event_t ek_event_quit;
+ek_event_t ek_event_msg;
+
+static ek_event_t lastevent;
+
+#if CC_FUNCTION_POINTER_ARGS
+
+#else /* CC_FUNCTION_POINTER_ARGS */
+ek_event_t ek_eventhandler_s;
+ek_data_t ek_eventhandler_data;
+#endif /* CC_FUNCTION_POINTER_ARGS */      
+
+
+/**
+ * \internal Structure used for keeping the queue of active events.
+ */
+struct event_data {
+  ek_event_t s;
+  ek_data_t data;
+  ek_id_t id;
+};
+
+static ek_num_events_t nevents, fevent;
+static struct event_data events[EK_CONF_NUMEVENTS];
+
+volatile unsigned char ek_poll_request;
+
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Allocates a event number.
+ *
+ * \return The allocated event number or EK_EVENT_NONE if no event
+ * number could be allocated.
+ */
+/*-----------------------------------------------------------------------------------*/
+ek_event_t
+ek_alloc_event(void)
+{
+  return lastevent++;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+procs_add(struct ek_proc *p)
+{
+  static struct ek_proc *q, *r;
+  
+  /* The process should be placed on the process list according to the
+     process' priority. The higher the priority, the earlier on the
+     list. */
+  r = NULL;
+  for(q = ek_procs; q != NULL; q = q->next) {
+    if(p->prio >= q->prio) {
+      p->next = q;
+      if(r == NULL) {
+	ek_procs = p;
+      } else {
+	r->next = p;       
+      }
+      return;
+    }
+    r = q;
+  }
+
+  if(q == NULL) {
+    if(r == NULL) {
+      p->next = ek_procs;
+      ek_procs = p;
+    } else {
+      r->next = p;
+      p->next = NULL;
+    } 
+  }
+  
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Starts a new process.
+ *
+ * Is called by a program in order to start a new process for the
+ * program. This function should be called quite early in the
+ * initialization procedure of a new process. In partcular, it must be
+ * called before any other dispatcher functions, or functions of other
+ * modules that make use of dispatcher functions. Most CTK functions
+ * call dispatcher functions, and should therefore not be called
+ * before ek_start() is called.
+ *
+ * Example:
+ \code
+static void app_poll(void);
+static EK_EVENTHANDLER(app_eventhandler, s, data);
+static struct ek_proc p =
+  {EK_PROC("Generic applications", app_poll, app_eventhandler, NULL)};
+static ek_id_t id = EK_ID_NONE;
+ 
+LOADER_INIT_FUNC(app_init, arg)
+{
+  arg_free(arg);
+  
+  if(id == EK_ID_NONE) {
+    id = ek_start(&p);
+
+    rest_of_initialization();
+  }
+}
+ \endcode
+ *
+ * \param p A pointer to a ek_proc struct that must be found
+ * in the process own memory space.
+ *
+ * \return The process identifier for the new process or EK_ID_NONE
+ * if the process could not be started.
+ */
+/*-----------------------------------------------------------------------------------*/
+ek_id_t
+ek_start(CC_REGISTER_ARG struct ek_proc *p)
+{
+  ek_id_t id;
+
+  for(id = 0; id < EK_CONF_MAXPROCS; ++id) {
+    if(ek_proclist[id] == NULL) {
+      break;
+    }
+  }
+  if(id == EK_CONF_MAXPROCS) {
+    return EK_ID_NONE;
+  }
+
+  ek_proclist[id] = p;
+  
+  /* Put on the procs list.*/
+  procs_add(p);
+  
+  p->id = id;
+
+  /* Post an asynchronous event to the process. */
+  ek_post(id, EK_EVENT_INIT, p);
+
+  return id;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Exit the currently running process
+ *
+ * This function causes the currently running process to exit. The
+ * function must be called by the process before it unloads itself, or
+ * the system will crash.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ek_exit(void)
+{
+  register struct ek_proc *q, *p;
+  
+  p = ek_current;
+
+  /* Post a synchronous event to all processes to inform them that
+     this process is about to exit. This will allow services to
+     dealloc state associated with this process. */
+  for(q = ek_procs; q != NULL; q = q->next) {
+    if(p != q) {
+      ek_current = q;
+      if(q->eventhandler != NULL) {
+	q->eventhandler(EK_EVENT_EXITED, (ek_data_t)p->id);
+      }
+    }    
+  }
+  
+  /* Remove process from the process lists. */
+  ek_proclist[p->id] = NULL;
+  
+  if(p == ek_procs) {
+    ek_procs = ek_procs->next;    
+  } else {
+    for(q = ek_procs; q != NULL; q = q->next) {
+      if(q->next == p) {
+	q->next = p->next;
+	break;
+      }
+    }
+  }
+  
+  ek_current = NULL;
+}
+/**
+ * \addtogroup kernel
+ * @{
+ */
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Finds the process structure for a specific process ID.
+ *
+ * \param id The process ID for the process.
+ *
+ * \return The process structure for the process, or NULL if there
+ * process ID was not found.
+ */
+/*-----------------------------------------------------------------------------------*/
+struct ek_proc *
+ek_process(ek_id_t id)
+{
+  struct ek_proc *p;
+  for(p = ek_procs; p != NULL; p = p->next) {
+    if(p->id == id) {
+      return p;
+    }
+  }
+  return NULL;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Initializes the dispatcher module.
+ *
+ * Must be called during the initialization of Contiki.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ek_init(void)
+{
+  int i;
+  
+  lastevent = EK_EVENT_MAX;
+
+  nevents = fevent = 0;
+
+  ek_current = ek_procs = NULL;
+
+  arg_init();
+
+  for(i = 0; i < EK_CONF_MAXPROCS; ++i) {
+    ek_proclist[i] = NULL;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Process the next event in the event queue and deliver it to
+ * listening processes.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ek_process_event(void)
+{ 
+  static ek_event_t s;
+  static ek_data_t data;
+  static ek_id_t id;
+  static struct ek_proc *p;
+  
+  /* If there are any events in the queue, take the first one and
+     walk through the list of processes to see if the event should be
+     delivered to any of them. If so, we call the event handler
+     function for the process. We only process one event at a time
+     and call the poll handlers inbetween. */
+
+  if(nevents > 0) {
+    
+    /* There are events that we should deliver. */
+    s = events[fevent].s;
+    
+    data = events[fevent].data;
+    id = events[fevent].id;
+
+    /* Since we have seen the new event, we move pointer upwards
+       and decrese number. */
+    fevent = (fevent + 1) % EK_CONF_NUMEVENTS;
+    --nevents;
+
+    /* If this is a broadcast event, we deliver it to all events, in
+       order of their priority. */
+    if(id == EK_BROADCAST) {
+      for(p = ek_procs; p != NULL; p = p->next) {
+
+	if(ek_poll_request) {
+	  ek_poll_request = 0;
+	  ek_process_poll();
+	}
+	
+	ek_current = p;
+	if(p->eventhandler != NULL) {
+	  p->eventhandler(s, data);
+	}
+      }
+    } else {
+      /* This is not a broadcast event, so we deliver it to the
+	 specified process. */
+      if(ek_poll_request) {
+	ek_poll_request = 0;
+	ek_process_poll();
+      }
+      
+      p = ek_proclist[id];
+      if(p != NULL &&
+	 p->eventhandler != NULL) {
+	ek_current = p;
+	p->eventhandler(s, data);
+
+	/* If the event was an INIT event, we should also put the
+	   process on the process list. */
+	/*	procs_add(p);*/
+      }
+    }    
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Call each process' poll handler.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ek_process_poll(void)
+{
+  struct ek_proc *p;
+  
+  /* Call poll handlers. */
+  for(p = ek_procs; p != NULL; p = p->next) {
+    
+    if(ek_poll_request) {
+      ek_poll_request = 0;
+      p = ek_procs;
+    }
+
+    if(p->pollhandler != NULL) {
+      ek_current = p;
+      p->pollhandler();
+    }
+  }
+  
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Run the system once - call poll handlers and process one event.
+ *
+ * This function should be called repeatedly from the main() program
+ * to actuall run the Contiki system. It calls the necessary poll
+ * handlers, and processes one event. The function returns the number
+ * of events that are waiting in the event queue so that the caller
+ * may choose to put the CPU to sleep when there are no pending
+ * events.
+ *
+ * \return The number of events that are currently waiting in the
+ * event queue.
+ */
+/*-----------------------------------------------------------------------------------*/
+int
+ek_run(void)
+{
+  /* Process "poll" events. */
+  do {
+    ek_poll_request = 0;
+    ek_process_poll();
+  } while(ek_poll_request != 0);
+  
+  /* Process one event */
+  ek_process_event();
+
+  return nevents;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Post an asynchronous event.
+ *
+ * This function posts an asynchronous event to one or more
+ * processes. The handing of the event is deferred until the target
+ * process is scheduled by the kernel. An event can be broadcast to
+ * all processes, in which case all processes in the system will be
+ * scheduled to handle the event.
+ * 
+ * \param s The event to be posted.
+ *
+ * \param data The auxillary data to be sent with the event
+ *
+ * \param id The process ID to which the event should be posted, or
+ * EK_BROADCAST if the event should be posted to all
+ * processes.
+ *
+ * \retval EK_ERR_OK The event could be posted.
+ *
+ * \retval EK_ERR_FULL The event queue was full and the event could
+ * not be posted.
+ */
+/*-----------------------------------------------------------------------------------*/
+ek_err_t
+ek_post(ek_id_t id, ek_event_t s, ek_data_t data)
+{
+  static unsigned char snum;
+  
+  if(nevents == EK_CONF_NUMEVENTS) {
+    return EK_ERR_FULL;
+  }
+  
+  snum = (fevent + nevents) % EK_CONF_NUMEVENTS;
+  events[snum].s = s;
+  events[snum].data = data;
+  events[snum].id = id;
+  ++nevents;
+  
+  return EK_ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ek_post_synch(ek_id_t id, ek_event_t ev, ek_data_t data)
+{
+  struct ek_proc *p = ek_current;
+  
+  ek_current = ek_proclist[id]; 
+  ek_current->eventhandler(ev, data); 
+  ek_current = p;
+}
+/*-----------------------------------------------------------------------------------*/
+ek_id_t
+ek_find(const char *prefix)
+{
+  struct ek_proc *p;
+  unsigned short len;
+
+  /* Search through all processes and search for the specified process
+     name. */
+  len = strlen(prefix);
+  for(p = ek_procs; p != NULL; p = p->next) {
+    if(strncmp(prefix, p->name, len) == 0) {
+      return p->id;
+    }
+  }
+
+  return EK_ID_NONE;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+ek_replace(struct ek_proc *newp, void *arg)
+{
+  register struct ek_proc *p = ek_current;
+
+  /* Remove the currently executing process. */
+  ek_exit();
+
+  ek_proclist[p->id] = newp;
+  
+  /* Put on the procs list.*/
+  procs_add(newp);
+  
+  newp->id = p->id;
+
+  /* Post an asynchronous event to the process. */
+  ek_post(p->id, EK_EVENT_REPLACE, arg);
+}
+/*-----------------------------------------------------------------------------------*/
+void *
+ek_procstate(ek_id_t id)
+{
+  struct ek_proc *p;
+
+  p = ek_proclist[id];
+  if(p == NULL) {
+    return NULL;
+  }
+  return p->procstate;
+}
+/*-----------------------------------------------------------------------------------*/
+/** @} */
diff --git a/contiki/ek/ek.h b/contiki/ek/ek.h
new file mode 100644
index 0000000..1aaf5e3
--- /dev/null
+++ b/contiki/ek/ek.h
@@ -0,0 +1,426 @@
+/**
+ * \addtogroup ek
+ * @{
+ */
+
+/**
+ * \file
+ * Contiki Kernel header file.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ek.h,v 1.9 2006/05/17 15:27:43 oliverschmidt Exp $
+ */
+#ifndef __EK_H__
+#define __EK_H__
+
+#include "ek-conf.h"
+
+#include "cc.h"
+#include "arg.h"
+#include "loader.h"
+
+void ek_init(void);
+
+typedef unsigned char ek_err_t;
+
+
+/* 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: */
+
+/**
+ * Broadcast process ID.  
+ *
+ * Events emitted to the EK_BROADCAST process ID are
+ * delivered to all processes.
+ */
+#define EK_ID_NONE               EK_CONF_MAXPROCS
+#define EK_ID_ALL                EK_ID_NONE
+
+#define EK_BROADCAST             EK_ID_ALL
+
+/**
+ * \defgroup events System events
+ * @{
+ *
+ * The Contiki kernel defines a number of default events that can be
+ * delivered to processes. 
+ */
+
+#define EK_EVENT_NONE            0x80
+
+/**
+ * Initialization event.
+ *
+ * This event is posted by the kernel to a process in order to let the
+ * process to initialization.
+ *
+ */
+#define EK_EVENT_INIT            0x81
+
+/**
+ * Service replacement event.
+ *
+ * This event is posted by the kernel in order to inform a process
+ * that a service that the current process have requested to be
+ * replaced, is now replaced.
+ */
+#define EK_EVENT_REPLACE         0x82
+
+/**
+ * Continuation event.
+ *
+ * This event can be used to implement continuations.
+ */
+#define EK_EVENT_CONTINUE        0x83
+
+/**
+ * Generic message event.
+ *
+ * This event can be used to pass messages between processes.
+ */
+#define EK_EVENT_MSG             0x84
+
+/**
+ * A process has exited.
+ *
+ * This event is posted to all processes to inform that another
+ * process has exited.
+ */
+#define EK_EVENT_EXITED          0x85
+
+/**
+ * Request a process to exit itself.
+ *
+ * This event is posted to a process in order to tell it to remove
+ * itself from the system. Since each program may have allocated
+ * system resources that must be released before the process quits,
+ * each program must implement the event handler by itself. A process
+ * that receives this event must call LOADER_UNLOAD() to unload itself
+ * after doing all necessary clean ups (such as closing open windows,
+ * deallocate allocated memory, etc.).
+ */
+#define EK_EVENT_REQUEST_EXIT    0x86
+
+/**
+ * Request a service to be replaced.
+ *
+ * This event is posted by the kernel to a service that another
+ * process have requested to be replaced.
+ */
+#define EK_EVENT_REQUEST_REPLACE 0x87
+
+
+#define EK_EVENT_MAX             0x88
+
+/** @}*/
+
+/**
+ * Instantiating macro for the ek_proc struct.
+ *
+ * This macro is used when initializing a ek_proc structure
+ * for a process. It hides the internals of the ek_proc struct
+ * and provides an easy way to define process signature.
+ *
+ * \note Defining a ek_proc struct does not start the process and does
+ * not register the process with the kernel. Rather, the process'
+ * initialization function must explicitly call the ek_start()
+ * function with a pointer to the ek_proc struct containing the
+ * process definition.
+ *
+ * \param name The name of the \c struct \c ek_proc of the process.
+ *
+ * \param strname A textual repressentation of the process' name.
+ *
+ * \param prio The priority of the process.
+ *
+ * \param pollh A pointer to the poll function or NULL if no poll
+ * handler should be registered.
+ *
+ * \param eventh A pointer to the process' event handler. All
+ * processes are required to have a event handler.
+ *
+ * \param stateptr An opaque pointer that can be associated with the
+ * process.
+ *
+ * \hideinitializer
+ */
+#ifndef EK_PROCESS
+#define EK_PROCESS(name, strname, prio, eventh, pollh, stateptr)	\
+  static struct ek_proc name = {NULL, EK_ID_NONE, strname, prio, eventh, pollh, stateptr}
+#endif /* EK_PROCESS */
+
+struct ek_proc {
+  struct ek_proc *next;
+  ek_id_t id;
+  const char *name;
+  unsigned char prio;
+  void (* eventhandler)(ek_event_t ev, ek_data_t data);
+  void (* pollhandler)(void);
+  void *procstate;
+};
+
+/**
+ * Lowest priority.
+ *
+ * This value can be used in the \c prio field in the EK_PROCESS() macro.
+ */
+#define EK_PRIO_LOWEST  0x00
+/**
+ * Low priority.
+ *
+ * This value can be used in the \c prio field in the EK_PROCESS() macro.
+ */
+#define EK_PRIO_LOW     0x3f
+/**
+ * Normal priority.
+ *
+ * This value can be used in the \c prio field in the EK_PROCESS() macro.
+ */
+#define EK_PRIO_NORMAL  0x7f
+/**
+ * High priority.
+ *
+ * This value can be used in the \c prio field in the EK_PROCESS() macro.
+ */
+#define EK_PRIO_HIGH    0xbf
+/**
+ * Highest priority.
+ *
+ * This value can be used in the \c prio field in the EK_PROCESS() macro.
+ */
+#define EK_PRIO_HIGHEST 0xff
+
+/**
+ * Get the process state of a process.
+ *
+ * This function is used by the kernel service module, and is in most
+ * cased not used directly by user programs.
+ *
+ * \param id The process ID of the process,
+ */
+void *ek_procstate(ek_id_t id);
+
+/**
+ * Obtain a pointer to the list of processes.
+ */
+#define EK_PROCS()   ek_procs
+
+/**
+ * Obtain a pointer to the currently running process.
+ */
+#define EK_CURRENT() ek_current
+
+ek_event_t ek_alloc_event(void);
+
+ek_id_t ek_start(struct ek_proc *p);
+void ek_exit(void);
+
+ek_err_t ek_post(ek_id_t id, ek_event_t s, ek_data_t data);
+
+struct ek_proc *ek_process(ek_id_t id);
+
+/* We must do some C macro trickery to make things work with sdcc,
+   which doesn't support passing arguments to functions called as
+   function pointers. */
+#if CC_FUNCTION_POINTER_ARGS
+
+/**
+ * Declaration macro for a event handler function.
+ *
+ * This macro is used when declaring a process' event handler
+ * function. The reason why a macro is used for this instead of a
+ * regular C declaration is that certain C compilers cannot handle
+ * function pointers with arguments and therefore the
+ * EK_EVENTHANDLER() macro definition varies with different C
+ * compilers.
+ *
+ * The following example shows how to use the EK_EVENTHANDLER()
+ * declaration macro as well as the EK_EVENTHANDLER_ARGS() macro
+ * and how to handle the ek_event_quit event.
+ *
+ \code
+ static EK_EVENTHANDLER(example_eventhandler, s, data);
+
+ static
+ EK_EVENTHANDLER(example_eventhandler, s, data)
+ {
+   EK_EVENTHANDLER_ARGS(s, data);
+
+   if(s == ek_event_quit) {
+      ek_exit(&p);
+      LOADER_UNLOAD();
+   }
+ }
+ \endcode
+ *
+ * \param name The name of the event handler function.
+ *
+ * \param ev The name of the event number parameter.
+ *
+ * \param data The name of the event data parameter.
+ *
+ *
+ * \hideinitializer 
+ */
+#ifndef EK_EVENTHANDLER
+#define EK_EVENTHANDLER(name, ev, data) \
+        static void name(ek_event_t ev, ek_data_t data)
+#endif /* EK_EVENTHANDLER */
+
+#ifndef EK_POLLHANDLER
+#define EK_POLLHANDLER(name) \
+        static void name(void)
+#endif /* EK_POLLHANDLER */
+
+#ifndef EK_PROCESS_INIT
+#define EK_PROCESS_INIT(name, arg) \
+        void name(void *arg)
+#endif /* EK_PROCESS_INIT */
+
+#define EK_PROC_STATE(p) ((p)->procstate)
+#define EK_PROC_ID(p)    ((p)->id)
+
+/**
+ * Declaration macro for event handler arguments.
+ *
+ * This macro must be used for declaring the event handler function's
+ * arguments. The reason why this is needed is that some C compilers
+ * do not support function pointers with arguments and therefor a
+ * workaround has been made using C macros.
+ *
+ * \note This macro call must come after the declarations of the local
+ * variables but before the first program statement in the event
+ * handler function.
+ *
+ * The following example shows a event handler function with local
+ * variables.
+ *
+ \code
+ static
+ EK_EVENTHANDLER(example_eventhandler, s, data)
+ {
+   char c;
+   EK_EVENTHANDLER_ARGS(s, data);
+
+   if(s == ctk_event_keypress) {
+      c = (char)data;
+      process_key(c);
+   } else if(s == ek_event_quit) {
+      ek_exit(&p);
+      LOADER_UNLOAD();
+   }
+ }
+ \endcode
+ *
+ * \param ev The name of the event number argument. Must match the one
+ * in the EK_EVENTHANDLER() declaration.
+ *
+ * \param data The name of the event data argument. Must match the
+ * one in the EK_EVENTHANDLER() declaration.
+ *
+ */
+#define EK_EVENTHANDLER_ARGS(ev, data)
+
+/*
+#define EK_UIPCALL(name, state) \
+        void name(void *state)
+
+#define EK_UIPCALL_ARG(state)
+*/
+
+#else /* CC_FUNCTION_POINTER_ARGS */
+#define EK_EVENTHANDLER(s, data) \
+        void name(void)
+
+#define EK_EVENTHANDLER_ARGS(s, data) ek_event_t s = ek_eventhandler_s; \
+                                      ek_data_t data = ek_eventhandler_data
+
+extern ek_event_t ek_eventhandler_s;
+extern ek_data_t ek_eventhandler_data;
+
+#endif /* CC_FUNCTION_POINTER_ARGS */
+
+extern struct ek_proc *ek_current;
+extern struct ek_proc *ek_procs;
+extern struct ek_proc *ek_proclist[EK_CONF_MAXPROCS];
+
+void ek_process_event(void);
+void ek_process_poll(void);
+
+int ek_run(void);
+
+ek_id_t ek_find(const char *servicename);
+
+void ek_replace(struct ek_proc *newp, void *arg);
+
+/** @} */
+
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Post a synchronous event.
+ *
+ * This function emits a event and calls the listening processes'
+ * event handlers immediately, before returning to the caller. This
+ * function requires more call stack space than the ek_emit()
+ * function and should be used with care, and only in situtations
+ * where the exact implications are known.
+ *
+ * In most situations, the ek_emit() function should be used
+ * instead.
+ *
+ * \param ev The event to be emitted.
+ *
+ * \param data The auxillary data to be sent with the event
+ *
+ * \param id The process ID to which the event should be emitted, or
+ * EK_BROADCAST if the event should be emitted to all
+ * processes listening for the event.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void ek_post_synch(ek_id_t id, ek_event_t ev, ek_data_t data);
+
+extern volatile unsigned char ek_poll_request;
+#define EK_REQUEST_POLL() ek_poll_request = 1
+
+#endif /* __EK_H__ */
diff --git a/contiki/ek/lc-addrlabels.h b/contiki/ek/lc-addrlabels.h
new file mode 100644
index 0000000..b50c087
--- /dev/null
+++ b/contiki/ek/lc-addrlabels.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc-addrlabels.h,v 1.2 2005/04/01 08:12:36 adamdunkels Exp $
+ */
+
+/**
+ * \addtogroup lc
+ * @{
+ */
+
+/**
+ * \file
+ * Implementation of local continuations based on the "Labels as
+ * values" feature of gcc
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ * This implementation of local continuations is based on a special
+ * feature of the GCC C compiler called "labels as values". This
+ * feature allows assigning pointers with the address of the code
+ * corresponding to a particular C label.
+ *
+ * For more information, see the GCC documentation:
+ * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
+ *
+ */
+
+#ifndef __LC_ADDRLABELS_H__
+#define __LC_ADDRLABELS_H__
+
+/** \hideinitializer */
+typedef void * lc_t;
+
+#define LC_INIT(s) s = NULL
+
+#define LC_RESUME(s)				\
+  do {						\
+    if(s != NULL) {				\
+      goto *s;					\
+    }						\
+  } while(0)
+
+#define LC_CONCAT2(s1, s2) s1##s2
+#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2)
+
+#define LC_SET(s)				\
+  do {						\
+    LC_CONCAT(LC_LABEL, __LINE__):   	        \
+    (s) = &&LC_CONCAT(LC_LABEL, __LINE__);	\
+  } while(0)
+
+#define LC_END(s)
+
+#endif /* __LC_ADDRLABELS_H__ */
diff --git a/contiki/ek/lc-switch.h b/contiki/ek/lc-switch.h
new file mode 100644
index 0000000..a559b8c
--- /dev/null
+++ b/contiki/ek/lc-switch.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc-switch.h,v 1.2 2005/04/01 08:12:37 adamdunkels Exp $
+ */
+
+/**
+ * \addtogroup lc
+ * @{
+ */
+
+/**
+ * \file
+ * Implementation of local continuations based on switch() statment
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ * This implementation of local continuations uses the C switch()
+ * statement to resume execution of a function somewhere inside the
+ * function's body. The implementation is based on the fact that
+ * switch() statements are able to jump directly into the bodies of
+ * control structures such as if() or while() statmenets.
+ *
+ * This implementation borrows heavily from Simon Tatham's coroutines
+ * implementation in C:
+ * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
+ */
+
+#ifndef __LC_SWITCH_H__
+#define __LC_SWTICH_H__
+
+/* WARNING! lc implementation using switch() does not work if an
+   LC_SET() is done within another switch() statement! */
+
+/** \hideinitializer */
+typedef unsigned short lc_t;
+
+#define LC_INIT(s) s = 0;
+
+#define LC_RESUME(s) switch(s) { case 0:
+
+#define LC_SET(s) s = __LINE__; case __LINE__: 
+
+#define LC_END(s) }
+
+#endif /* __LC_SWITCH_H__ */
+
+/** @} */
diff --git a/contiki/ek/lc.h b/contiki/ek/lc.h
new file mode 100644
index 0000000..24efb62
--- /dev/null
+++ b/contiki/ek/lc.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: lc.h,v 1.1 2005/02/22 22:36:51 adamdunkels Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \defgroup lc Local continuations
+ * @{
+ *
+ * Local continuations form the basis for implementing protothreads. A
+ * local continuation can be <i>set</i> in a specific function to
+ * capture the state of the function. After a local continuation has
+ * been set can be <i>resumed</i> in order to restore the state of the
+ * function at the point where the local continuation was set.
+ *
+ *
+ */
+
+/**
+ * \file lc.h
+ * Local continuations
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifdef DOXYGEN
+/**
+ * Initialize a local continuation.
+ *
+ * This operation initializes the local continuation, thereby
+ * unsetting any previously set continuation state.
+ *
+ * \hideinitializer
+ */
+#define LC_INIT(lc)
+
+/**
+ * Set a local continuation.
+ *
+ * The set operation saves the state of the function at the point
+ * where the operation is executed. As far as the set operation is
+ * concerned, the state of the function does <b>not</b> include the
+ * call-stack or local (automatic) variables, but only the program
+ * counter and such CPU registers that needs to be saved.
+ *
+ * \hideinitializer
+ */
+#define LC_SET(lc)
+
+/**
+ * Resume a local continuation.
+ *
+ * The resume operation resumes a previously set local continuation, thus
+ * restoring the state in which the function was when the local
+ * continuation was set. If the local continuation has not been
+ * previously set, the resume operation does nothing.
+ *
+ * \hideinitializer
+ */
+#define LC_RESUME(lc)
+
+/**
+ * Mark the end of local continuation usage.
+ *
+ * The end operation signifies that local continuations should not be
+ * used any more in the function. This operation is not needed for
+ * most implementations of local continuation, but is required by a
+ * few implementations.
+ *
+ * \hideinitializer 
+ */
+#define LC_END(lc)
+
+/**
+ * \var typedef lc_t;
+ *
+ * The local continuation type.
+ *
+ * \hideinitializer
+ */
+#endif /* DOXYGEN */
+
+#ifndef __LC_H__
+#define __LC_H__
+
+
+#ifdef LC_INCLUDE
+#include LC_INCLUDE
+#else
+#include "lc-switch.h"
+#endif /* LC_INCLUDE */
+
+#endif /* __LC_H__ */
+
+/** @} */
+/** @} */
diff --git a/contiki/ek/loader.h b/contiki/ek/loader.h
new file mode 100644
index 0000000..ffc8c07
--- /dev/null
+++ b/contiki/ek/loader.h
@@ -0,0 +1,131 @@
+/**
+ * \file
+ * Default definitions and error values for the Contiki program loader.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/**
+ * \defgroup loader The Contiki program loader
+ * @{
+ *
+ * The Contiki program loader is an abstract interface for loading and
+ * starting programs.
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: loader.h,v 1.10 2005/05/07 14:24:59 oliverschmidt Exp $
+ *
+ */
+#ifndef __LOADER_H__
+#define __LOADER_H__
+
+/* Errors that the LOADER_LOAD() function may return: */
+
+#define LOADER_OK                0       /**< No error. */
+#define LOADER_ERR_READ          1       /**< Read error. */
+#define LOADER_ERR_HDR           2       /**< Header error. */
+#define LOADER_ERR_OS            3       /**< Wrong OS. */
+#define LOADER_ERR_FMT           4       /**< Data format error. */
+#define LOADER_ERR_MEM           5       /**< Not enough memory. */
+#define LOADER_ERR_OPEN          6       /**< Could not open file. */
+#define LOADER_ERR_ARCH          7       /**< Wrong architecture. */
+#define LOADER_ERR_VERSION       8       /**< Wrong OS version. */
+#define LOADER_ERR_NOLOADER      9       /**< Program loading not supported. */
+
+#ifdef WITH_LOADER_ARCH
+#include "loader-arch.h"
+#include "loader-arch-dsc.h"
+#define LOADER_INIT_FUNC(name, arg) void loader_appinit(char *arg)
+#else /* WITH_LOADER_ARCH */
+#define LOADER_INIT_FUNC(name, arg) void name(char *arg)
+#endif /* WITH_LOADER_ARCH */
+
+/**
+ * Load and execute a program.
+ *
+ * This macro is used for loading and executing a program, and
+ * requires support from the architecture dependant code. The actual
+ * program loading is made by architecture specific functions.
+ *
+ * \note A program loaded with LOADER_LOAD() must call the
+ * LOADER_UNLOAD() function to unload itself.
+ *
+ * \param name The name of the program to be loaded.
+ *
+ * \param arg A pointer argument that is passed to the program.
+ *
+ * \return A loader error, or LOADER_OK if loading was successful.
+ */
+#ifndef LOADER_LOAD
+#define LOADER_LOAD(name, arg) LOADER_ERR_NOLOADER
+#endif /* LOADER_LOAD */
+
+/**
+ * Unload a program from memory.
+ *
+ * This macro is used for unloading a program and deallocating any
+ * memory that was allocated during the loading of the program. This
+ * function must be called by the program itself.
+ *
+ */
+#ifndef LOADER_UNLOAD
+#define LOADER_UNLOAD()
+#endif /* LOADER_UNLOAD */
+
+/**
+ * Load a DSC (program description).
+ *
+ * Loads a DSC (program description) into memory and returns a pointer
+ * to the dsc.
+ *
+ * \return A pointer to the DSC or NULL if it could not be loaded.
+ */
+#ifndef LOADER_LOAD_DSC
+#define LOADER_LOAD_DSC(name) NULL
+#endif /* LOADER_LOAD_DSC */
+
+/**
+ * Unload a DSC (program description).
+ *
+ * Unload a DSC from memory and deallocate any memory that was
+ * allocated when it was loaded.
+ */
+#ifndef LOADER_UNLOAD_DSC
+#define LOADER_UNLOAD_DSC(dsc)
+#endif /* LOADER_UNLOAD */
+
+
+
+
+#endif /* __LOADER_H__ */
diff --git a/contiki/ek/log.h b/contiki/ek/log.h
new file mode 100644
index 0000000..5f6f262
--- /dev/null
+++ b/contiki/ek/log.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: log.h,v 1.3 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#ifndef __LOG_H__
+#define __LOG_H__
+
+#include "log-conf.h"
+
+#if LOG_CONF_ENABLED
+void log_message(const char *part1, const char *part2);
+#else /* LOG_CONF_ENABLED */
+#define log_message(p1, p2)
+#endif /* LOG_CONF_ENABLED */
+
+#endif /* __LOG_H__ */
diff --git a/contiki/ek/mt.c b/contiki/ek/mt.c
new file mode 100644
index 0000000..9a349d5
--- /dev/null
+++ b/contiki/ek/mt.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: mt.c,v 1.3 2005/02/22 22:46:33 adamdunkels Exp $
+ */
+
+/**
+ * \file
+ * Implementation of the archtecture agnostic parts of the preemptive
+ * multithreading library for Contiki.
+ *
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "ek.h"
+#include "mt.h"
+#include "cc.h"
+
+#define MT_STATE_READY   1
+#define MT_STATE_RUNNING 2
+#define MT_STATE_WAITING 3
+#define MT_STATE_PEEK    4
+#define MT_STATE_EXITED  5
+
+static struct mt_thread *current;
+
+/*--------------------------------------------------------------------------*/
+void
+mt_init(void)
+{
+  mtarch_init();
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_remove(void)
+{
+  mtarch_remove();
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_start(struct mt_thread *thread, void (* function)(void *), void *data)
+{
+  /* Call the architecture dependant function to set up the processor
+     stack with the correct parameters. */
+  mtarch_start(&thread->thread, function, data);
+
+  thread->state = MT_STATE_READY;
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_exec(struct mt_thread *thread)
+{
+  if(thread->state == MT_STATE_READY ||
+     thread->state == MT_STATE_PEEK) {
+    thread->state = MT_STATE_RUNNING;
+    current = thread;
+    /* Switch context to the thread. The function call will not return
+       until the the thread has yielded, or is preempted. */
+    mtarch_exec(&thread->thread);
+  }
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_exit(void)
+{
+  current->state = MT_STATE_EXITED;
+  current = NULL;
+  mtarch_yield();
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_exec_event(struct mt_thread *thread, ek_event_t ev, ek_data_t data)
+{
+  if(thread->state == MT_STATE_WAITING ||
+     thread->state == MT_STATE_PEEK) {
+    *(thread->evptr) = ev;
+    *(thread->dataptr) = data;
+    thread->state = MT_STATE_RUNNING;
+    current = thread;    
+    /* Switch context to the thread. The function call will not return
+       until the the thread has yielded, or is preempted. */
+    mtarch_exec(&thread->thread);
+  }
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_yield(void)
+{    
+  mtarch_pstop();
+  current->state = MT_STATE_READY;
+  current = NULL;
+  /* This function is called from the running thread, and we call the
+     switch function in order to switch the thread to the main Contiki
+     program instead. For us, the switch function will not return
+     until the next time we are scheduled to run. */
+  mtarch_yield();
+  
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_post(ek_id_t id, ek_event_t ev, ek_data_t data)
+{  
+  /* Turn off preemption to ensure mutual exclusion of kernel. */
+  mtarch_pstop();
+
+  ek_post(id, ev, data);
+  
+  /* Turn preemption on again. */  
+  mtarch_pstart();  
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_wait(ek_event_t *ev, ek_data_t *data)
+{
+  mtarch_pstop();
+  current->evptr = ev;
+  current->dataptr = data;
+  current->state = MT_STATE_WAITING;
+  current = NULL;
+  mtarch_yield();
+}
+/*--------------------------------------------------------------------------*/
+void
+mt_peek(ek_event_t *ev, ek_data_t *data)
+{
+  mtarch_pstop();
+  *ev = EK_EVENT_NONE;
+  current->evptr = ev;
+  current->dataptr = data;
+  current->state = MT_STATE_PEEK;
+  current = NULL;
+  mtarch_yield();  
+}
+/*--------------------------------------------------------------------------*/
+void
+mtp_start(struct mtp_thread *t,
+	  void (* function)(void *), void *data)
+{
+  mt_start(&t->t, function, data);
+  ek_start(t->p);
+}
+/*--------------------------------------------------------------------------*/
+void
+mtp_exit(void)
+{
+  mtarch_pstop();
+  mt_exit();
+  mt_remove();
+}
+/*--------------------------------------------------------------------------*/
+void
+mtp_eventhandler(ek_event_t ev, ek_data_t data)
+{
+  struct mtp_thread *thread = (struct mtp_thread *)EK_PROC_STATE(EK_CURRENT());
+
+  if(ev == EK_EVENT_REQUEST_EXIT) {
+    ek_exit();
+    LOADER_UNLOAD();
+    
+  } else if(ev == EK_EVENT_INIT) {
+    
+    ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, NULL);
+    
+  } else if(ev == EK_EVENT_CONTINUE) {
+
+    if(thread->t.state == MT_STATE_READY ||
+       thread->t.state == MT_STATE_PEEK) {
+      mt_exec(&thread->t);
+      if(thread->t.state == MT_STATE_EXITED) {
+	ek_exit();
+	LOADER_UNLOAD();
+      } else {
+	ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, NULL);
+      }
+    }
+  } else {
+    mt_exec_event(&thread->t, ev, data);
+    if(thread->t.state == MT_STATE_EXITED) {
+      ek_exit();
+      LOADER_UNLOAD();
+    } else if(thread->t.state == MT_STATE_READY ||
+	      thread->t.state == MT_STATE_PEEK) {
+      ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, NULL);
+    }
+  }
+}
+/*--------------------------------------------------------------------------*/
diff --git a/contiki/ek/mt.h b/contiki/ek/mt.h
new file mode 100644
index 0000000..bbfbc34
--- /dev/null
+++ b/contiki/ek/mt.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: mt.h,v 1.4 2005/02/22 22:46:33 adamdunkels Exp $
+ */
+
+/**
+ * \defgroup mt Multi-threading library
+ * @{
+ *
+ * The event driven Contiki kernel does not provide multi-threading
+ * by itself - instead, preemptive multi-threading is implemented
+ * as a library that optionally can be linked with applications. This
+ * library constists of two parts: a platform independent part, which is
+ * the same for all platforms on which Contiki runs, and a platform
+ * specific part, which must be implemented specifically for the
+ * platform that the multi-threading library should run.
+ */
+
+/**
+ * \defgroup mtarch Architecture support for multi-threading
+ * @{
+ *
+ * The Contiki multi-threading library requires some architecture
+ * specific support for seting up and switching stacks. This support
+ * requires three stack manipulation functions to be implemented:
+ * mtarch_start(), which sets up the stack frame for a new thread,
+ * mtarch_exec(), which switches in the stack of a thread, and
+ * mtarch_yield(), which restores the kernel stack from a thread's
+ * stack. Additionally, two functions for controlling the preemption
+ * (if any) must be implemented: mtarch_preemption_start() and
+ * mtarch_preemption_stop(). If no preemption is used, these functions
+ * can be implemented as empty functions. Finally, the function
+ * mtarch_init() is called by mt_init(), and can be used for
+ * initalization of timer interrupts, or any other mechanisms required
+ * for correct operation of the architecture specific support funcions.
+ *
+ */
+
+/**
+ * \file
+ * Header file for the preemptive multitasking library for Contiki.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __MT_H__
+#define __MT_H__
+
+#include "ek.h"
+
+
+/**
+ * An opaque structure that is used for holding the state of a thread.
+ *
+ * The structure should be defined in the "mtarch.h" file. This
+ * structure typically holds the entire stack for the thread.
+ */
+struct mtarch_thread;
+
+/**
+ * Initialize the architecture specific support functions for the
+ * multi-thread library.
+ *
+ * This function is implemented by the architecture specific functions
+ * for the multi-thread library and is called by the mt_init()
+ * function as part of the initialization of the library. The
+ * mtarch_init() function can be used for, e.g., starting preemtion
+ * timers or other architecture specific mechanisms required for the
+ * operation of the library.
+ */
+void mtarch_init(void);
+
+/**
+ * Uninstall library and clean up.
+ *
+ */
+void mtarch_remove(void);
+
+/**
+ * Setup the stack frame for a thread that is being started.
+ *
+ * This function is called by the mt_start() function in order to set
+ * up the architecture specific stack of the thread to be started.
+ *
+ * \param thread A pointer to a struct mtarch_thread for the thread to
+ * be started.
+ *
+ * \param function A pointer to the function that the thread will
+ * start executing the first time it is scheduled to run.
+ *
+ * \param data A pointer to the argument that the function should be
+ * passed.
+ */
+void mtarch_start(struct mtarch_thread *thread,
+		  void (* function)(void *data),
+		  void *data);
+
+/**
+ * Yield the processor.
+ *
+ * This function is called by the mt_yield() function, which is called
+ * from the running thread in order to give up the processor.
+ *
+ */
+void mtarch_yield(void);
+
+/**
+ * Start executing a thread.
+ *
+ * This function is called from mt_exec() and the purpose of the
+ * function is to start execution of the thread. The function should
+ * switch in the stack of the thread, and does not return until the
+ * thread has explicitly yielded (using mt_yield()) or until it is
+ * preempted.
+ *
+ */
+void mtarch_exec(struct mtarch_thread *thread);
+
+
+void mtarch_pstart(void);
+void mtarch_pstop(void);
+
+/** @} */
+
+
+#include "mtarch.h"
+#include "ek.h"
+
+struct mt_thread {
+  int state;
+  ek_event_t *evptr;
+  ek_data_t *dataptr;
+  struct mtarch_thread thread;
+};
+
+/**
+ * No error.
+ *
+ * \hideinitializer
+ */
+#define MT_OK 1
+
+/**
+ * Initializes the multithreading library.
+ *
+ */
+void mt_init(void);
+
+/**
+ * Uninstalls library and cleans up.
+ *
+ */
+void mt_remove(void);
+
+
+/**
+ * Starts a multithreading thread.
+ *
+ * \param thread Pointer to an mt_thread struct that must have been
+ * previously allocated by the caller.
+ *
+ * \param function A pointer to the entry function of the thread that is
+ * to be set up.
+ *
+ * \param data A pointer that will be passed to the entry function.
+ *
+ */
+void mt_start(struct mt_thread *thread, void (* function)(void *), void *data);
+
+/**
+ * Start executing a thread.
+ *
+ * This function is called by a Contiki process and starts running a
+ * thread. The function does not return until the thread has yielded,
+ * or is preempted.
+ *
+ * \note The thread must first be initialized with the mt_init() function.
+ *
+ * \param thread A pointer to a struct mt_thread block that must be
+ * allocated by the caller.
+ *
+ */
+void mt_exec(struct mt_thread *thread);
+
+/**
+ * Post an event to a thread.
+ *
+ * This function posts an event to a thread. The thread will be
+ * scheduled if the thread currently is waiting for the posted event
+ * number. If the thread is not waiting for the event, this function
+ * does nothing.
+ *
+ * \note The thread must first be initialized with the mt_init() function.
+ *
+ * \param thread A pointer to a struct mt_thread block that must be
+ * allocated by the caller.
+ *
+ * \param s The event that is posted to the thread.
+ *
+ * \param data An opaque pointer to a user specified structure
+ * containing additonal information, or NULL if no additional
+ * information is needed.
+ */
+void mt_exec_event(struct mt_thread *thread, ek_event_t s, ek_data_t data);
+
+/**
+ * Voluntarily give up the processor.
+ *
+ * This function is called by a running thread in order to give up
+ * control of the CPU.
+ *
+ */
+void mt_yield(void);
+
+/**
+ * Emit a signal to another process.
+ *
+ * This function is called by a running thread and will emit a signal
+ * to another Contiki process. This will cause the currently executing
+ * thread to yield.
+ *
+ * \param s The signal to be emitted.
+ * \param data A pointer to a message that is to be delivered together with the signal.
+ * \param id The process ID of the receiver of the signal, or EK_ID_ALL for a broadcast signal.
+ */
+void mt_post(ek_id_t id, ek_event_t s, ek_data_t data);
+
+/**
+ * Block and wait for an event to occur.
+ *
+ * This function can be called by a running thread in order to block
+ * and wait for an event. The function returns when an event has
+ * occured. The event number and the associated data are placed in the
+ * variables pointed to by the function arguments.
+ * 
+ */
+void mt_wait(ek_event_t *s, ek_data_t *data);
+
+/**
+ * Exit a thread.
+ *
+ * This function is called from within an executing thread in order to
+ * exit the thread. The function never returns.
+ *
+ */
+void mt_exit(void);
+
+/**
+ * \defgroup mtp Multi-threading library convenience functions
+ * @{
+ *
+ * The Contiki multi-threading library has an interface that might be
+ * hard to use. Therefore, the mtp module provides a simpler
+ * interface.
+ *
+ * Example:
+\code
+static void
+example_thread_code(void *data)
+{
+  while(1) {
+    printf("Test\n");
+    mt_yield();
+  }
+} 
+MTP(example_thread, "Example thread", p1, t1, t1_idle);
+
+int
+main(int argc, char *argv[])
+{
+  mtp_start(&example_thread, example_thread_code, NULL);
+}
+\endcode
+*
+*/
+
+#include "mt.h"
+
+/**
+ * Declare a thread.
+ *
+ * This macro is used to covneniently declare a thread, and the
+ * process in which the thread should execute. The names of the
+ * variables provided to the macro should be chosen to be unique
+ * within the file that the thread is used.
+ *
+ * Example:
+\code
+MTP(example_thread, example_proc, "Example thread");
+\endcode
+ *
+ * \param thread The variable name of the thread.
+ *
+ * \param proc The variable name of the process containing the thread.
+ *
+ * \param name A string that specifies the user-visible name of the
+ * process in which the thread will run.
+ *
+ * \hideinitializer
+ */
+#define MTP(thread, proc, name) \
+extern struct mtp_thread thread; \
+EK_PROCESS(proc, name, EK_PRIO_NORMAL, mtp_eventhandler, \
+           NULL, (void *)&thread); \
+static struct mtp_thread thread = {&proc}
+
+struct mtp_thread {
+  struct ek_proc *p;
+  struct mt_thread t;
+};
+
+/**
+ * Start a thread.
+ *
+ * This function starts the process in which the thread is to run, and
+ * also sets up the thread to run within the process. The function
+ * should be passed variable names declared with the MTP() macro.
+ *
+ * Example:
+\code
+mtp_start(&t, example_thread_code, NULL);
+\endcode
+ * \param t A pointer to a thread structure previously declared with MTP().
+ *
+ * \param function A pointer to the function that the thread should
+ * start executing.
+ *
+ * \param data A pointer that the function should be passed when first
+ * invocated.
+ */
+void mtp_start(struct mtp_thread *t,
+	       void (* function)(void *), void *data);
+
+void mtp_exit(void);
+
+
+void mtp_eventhandler(ek_event_t ev, ek_data_t data);
+
+/** @} */
+/** @} */
+#endif /* __MT_H__ */
+
diff --git a/contiki/ek/pt-sem.h b/contiki/ek/pt-sem.h
new file mode 100644
index 0000000..6d1907e
--- /dev/null
+++ b/contiki/ek/pt-sem.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: pt-sem.h,v 1.4 2005/02/28 09:02:41 adamdunkels Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \defgroup ptsem Protothread semaphores
+ * @{
+ *
+ * This module implements counting semaphores on top of
+ * protothreads. Semaphores are a synchronization primitive that
+ * provide two operations: "wait" and "signal". The "wait" operation
+ * checks the semaphore counter and blocks the thread if the counter
+ * is zero. The "signal" operation increases the semaphore counter but
+ * does not block. If another thread has blocked waiting for the
+ * semaphore that is signalled, the blocked thread will become
+ * runnable again.
+ *
+ * Semaphores can be used to implement other, more structured,
+ * synchronization primitives such as monitors and message
+ * queues/bounded buffers (see below).
+ *
+ * The following example shows how the producer-consumer problem, also
+ * known as the bounded buffer problem, can be solved using
+ * protothreads and semaphores. Notes on the program follow after the
+ * example.
+ *
+ \code
+#include "pt-sem.h"
+
+#define NUM_ITEMS 32
+#define BUFSIZE 8
+
+static struct pt_sem mutex, full, empty;
+
+PT_THREAD(producer(struct pt *pt))
+{
+  static int produced;
+  
+  PT_BEGIN(pt);
+  
+  for(produced = 0; produced < NUM_ITEMS; ++produced) {
+  
+    PT_SEM_WAIT(pt, &full);
+    
+    PT_SEM_WAIT(pt, &mutex);
+    add_to_buffer(produce_item());    
+    PT_SEM_SIGNAL(pt, &mutex);
+    
+    PT_SEM_SIGNAL(pt, &empty);
+  }
+
+  PT_END(pt);
+}
+
+PT_THREAD(consumer(struct pt *pt))
+{
+  static int consumed;
+  
+  PT_BEGIN(pt);
+
+  for(consumed = 0; consumed < NUM_ITEMS; ++consumed) {
+    
+    PT_SEM_WAIT(pt, &empty);
+    
+    PT_SEM_WAIT(pt, &mutex);    
+    consume_item(get_from_buffer());    
+    PT_SEM_SIGNAL(pt, &mutex);
+    
+    PT_SEM_SIGNAL(pt, &full);
+  }
+
+  PT_END(pt);
+}
+
+PT_THREAD(driver_thread(struct pt *pt))
+{
+  static struct pt pt_producer, pt_consumer;
+
+  PT_BEGIN(pt);
+  
+  PT_SEM_INIT(&empty, 0);
+  PT_SEM_INIT(&full, BUFSIZE);
+  PT_SEM_INIT(&mutex, 1);
+
+  PT_INIT(&pt_producer);
+  PT_INIT(&pt_consumer);
+
+  PT_WAIT_THREAD(pt, producer(&pt_producer) &
+		     consumer(&pt_consumer));
+
+  PT_END(pt);
+}
+ \endcode
+ *
+ * The program uses three protothreads: one protothread that
+ * implements the consumer, one thread that implements the producer,
+ * and one protothread that drives the two other protothreads. The
+ * program uses three semaphores: "full", "empty" and "mutex". The
+ * "mutex" semaphore is used to provide mutual exclusion for the
+ * buffer, the "empty" semaphore is used to block the consumer is the
+ * buffer is empty, and the "full" semaphore is used to block the
+ * producer is the buffer is full.
+ *
+ * The "driver_thread" holds two protothread state variables,
+ * "pt_producer" and "pt_consumer". It is important to note that both
+ * these variables are declared as <i>static</i>. If the static
+ * keyword is not used, both variables are stored on the stack. Since
+ * protothreads do not store the stack, these variables may be
+ * overwritten during a protothread wait operation. Similarly, both
+ * the "consumer" and "producer" protothreads declare their local
+ * variables as static, to avoid them being stored on the stack.
+ * 
+ *
+ */
+   
+/**
+ * \file
+ * Counting semaphores implemented on protothreads
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __PT_SEM_H__
+#define __PT_SEM_H__
+
+#include "pt.h"
+
+struct pt_sem {
+  unsigned int count;
+};
+
+/**
+ * Initialize a semaphore
+ *
+ * This macro initializes a semaphore with a value for the
+ * counter. Internally, the semaphores use an "unsigned int" to
+ * represent the counter, and therefore the "count" argument should be
+ * within range of an unsigned int.
+ *
+ * \param s (struct pt_sem *) A pointer to the pt_sem struct
+ * representing the semaphore
+ *
+ * \param c (unsigned int) The initial count of the semaphore.
+ * \hideinitializer
+ */
+#define PT_SEM_INIT(s, c) (s)->count = c
+
+/**
+ * Wait for a semaphore
+ *
+ * This macro carries out the "wait" operation on the semaphore. The
+ * wait operation causes the protothread to block while the counter is
+ * zero. When the counter reaches a value larger than zero, the
+ * protothread will continue.
+ *
+ * \param pt (struct pt *) A pointer to the protothread (struct pt) in
+ * which the operation is executed.
+ *
+ * \param s (struct pt_sem *) A pointer to the pt_sem struct
+ * representing the semaphore
+ *
+ * \hideinitializer
+ */
+#define PT_SEM_WAIT(pt, s)	\
+  do {						\
+    PT_WAIT_UNTIL(pt, (s)->count > 0);		\
+    --(s)->count;				\
+  } while(0)
+
+/**
+ * Signal a semaphore
+ *
+ * This macro carries out the "signal" operation on the semaphore. The
+ * signal operation increments the counter inside the semaphore, which
+ * eventually will cause waiting protothreads to continue executing.
+ *
+ * \param pt (struct pt *) A pointer to the protothread (struct pt) in
+ * which the operation is executed.
+ *
+ * \param s (struct pt_sem *) A pointer to the pt_sem struct
+ * representing the semaphore
+ *
+ * \hideinitializer
+ */
+#define PT_SEM_SIGNAL(pt, s) ++(s)->count
+
+#endif /* __PT_SEM_H__ */
+
+/** @} */
+/** @} */
+   
diff --git a/contiki/ek/pt.h b/contiki/ek/pt.h
new file mode 100644
index 0000000..bbadd02
--- /dev/null
+++ b/contiki/ek/pt.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: pt.h,v 1.10 2005/04/01 09:07:49 adamdunkels Exp $
+ */
+
+/**
+ * \addtogroup pt
+ * @{
+ */
+
+/**
+ * \file
+ * Protothreads implementation.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __PT_H__
+#define __PT_H__
+
+#include "lc.h"
+
+struct pt {
+  lc_t lc;
+};
+
+#define PT_THREAD_WAITING 0
+#define PT_THREAD_EXITED  1
+
+/**
+ * Declaration of a protothread.
+ *
+ * This macro is used to declare a protothread. All protothreads must
+ * be declared with this macro.
+ *
+ * Example:
+ \code
+ PT_THREAD(consumer(struct pt *p, int event)) {
+   PT_BEGIN(p);
+   while(1) {
+     PT_WAIT_UNTIL(p, event == AVAILABLE);
+     consume();
+     PT_WAIT_UNTIL(p, event == CONSUMED);
+     acknowledge_consumed();
+   }
+   PT_END(p);
+ }
+ \endcode
+ *
+ * \param name_args The name and arguments of the C function
+ * implementing the protothread.
+ *
+ * \hideinitializer
+ */
+#define PT_THREAD(name_args) char name_args
+
+/**
+ * Initialize a protothread.
+ *
+ * Initializes a protothread. Initialization must be done prior to
+ * starting to execute the protothread.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * Example:
+ *
+ \code
+ void main(void) {
+   struct pt p;
+   int event;
+   
+   PT_INIT(&p);
+   while(PT_SCHEDULE(consumer(&p, event))) {
+     event = get_event();
+   }
+ }
+ \endcode
+ *
+ * \sa PT_SPAWN()
+ *
+ * \hideinitializer
+ */
+#define PT_INIT(pt)   LC_INIT((pt)->lc)
+
+/**
+ * Declare the start of a protothread inside the C function
+ * implementing the protothread.
+ *
+ * This macro is used to declare the starting point of a
+ * protothread. It should be placed at the start of the function in
+ * which the protothread runs. All C statements above the PT_BEGIN()
+ * invokation will be executed each time the protothread is scheduled.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * Example:
+ *
+ \code
+ PT_THREAD(producer(struct pt *p, int event)) {
+   PT_BEGIN(p);
+   while(1) {
+     PT_WAIT_UNTIL(p, event == CONSUMED || event == DROPPED);
+     produce();
+     PT_WAIT_UNTIL(p, event == PRODUCED);
+   }
+   
+   PT_END(p);
+ }
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define PT_BEGIN(pt) LC_RESUME((pt)->lc)
+
+/**
+ * Block and wait until condition is true.
+ *
+ * This macro blocks the protothread until the specified condition is
+ * true.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param condition The condition.
+ *
+ * Example:
+ \code
+ PT_THREAD(seconds(struct pt *p)) {
+   PT_BEGIN(p);
+
+   PT_WAIT_UNTIL(p, time >= 2 * SECOND);
+   printf("Two seconds have passed\n");
+   
+   PT_END(p);
+ }
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_UNTIL(pt, condition)	        \
+  do {						\
+    LC_SET((pt)->lc);				\
+    if(!(condition)) {				\
+      return PT_THREAD_WAITING;			\
+    }						\
+  } while(0)
+
+/**
+ * Block and wait while condition is true.
+ *
+ * This function blocks and waits while condition is true. See
+ * PT_WAIT_UNTIL().
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param cond The condition.
+ *
+ * \hideinitializer
+ */
+#define PT_WAIT_WHILE(pt, cond)  PT_WAIT_UNTIL((pt), !(cond))
+
+
+/**
+ * Block and wait until a child protothread completes.
+ *
+ * This macro schedules a child protothread. The current protothread
+ * will block until the child protothread completes.
+ *
+ * \note The child protothread must be manually initialized with the
+ * PT_INIT() function before this function is used.
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param thread The child protothread with arguments
+ *
+ * Example:
+ \code
+ PT_THREAD(child(struct pt *p, int event)) {
+   PT_BEGIN(p);
+
+   PT_WAIT_UNTIL(p, event == EVENT1);   
+   
+   PT_END(p);
+ }
+
+ PT_THREAD(parent(struct pt *p, struct pt *child_pt, int event)) {
+   PT_BEGIN(p);
+
+   PT_INIT(child_pt);
+   
+   PT_WAIT_THREAD(p, child(child_pt, event));
+   
+   PT_END(p);
+ }
+ \endcode
+ *
+ * \sa PT_SPAWN()
+ *
+ * \hideinitializer 
+ */
+#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))
+
+/**
+ * Spawn a child protothread and wait until it exits.
+ *
+ * This macro spawns a child protothread and waits until it exits. The
+ * macro can only be used within a protothread.
+ *
+ * Example:
+ \code
+ static struct pt parent_pt, child_pt;
+ int should_spawn_flag;
+
+ PT_THREAD(child(struct pt *pt)) {
+   PT_BEGIN(pt);
+
+   while(all_items_processed()) {
+     process_item();
+     PT_WAIT_UNTIL(pt, item_processed());
+   }
+   
+   PT_END(pt);
+ }
+ 
+ PT_THREAD(parent(void)) {
+   PT_BEGIN(&parent_pt);
+
+   if(should_spawn_flag) {
+     PT_SPAWN(&parent_pt, &child_pt, child(&child_pt));
+   }
+   
+   PT_END(&parent_pt);
+ }
+ \endcode
+ *
+ *
+ * \param pt A pointer to the protothread control structure.
+ * \param child A pointer to the child protothread's control structure.
+ * \param thread The child protothread with arguments
+ *
+ * \hideinitializer
+ */
+#define PT_SPAWN(pt, child, thread)		\
+  do {						\
+    PT_INIT((child));				\
+    PT_WAIT_THREAD((pt), (thread));		\
+  } while(0)
+
+/**
+ * Restart the protothread.
+ *
+ * This macro will block and cause the running protothread to restart
+ * its execution at the place of the PT_BEGIN() call.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_RESTART(pt)				\
+  do {						\
+    PT_INIT(pt);				\
+    return PT_THREAD_WAITING;			\
+  } while(0)
+
+/**
+ * Exit the protothread.
+ *
+ * This macro causes the protothread to exit. If the protothread was
+ * spawned by another protothread, the parent protothread will become
+ * unblocked and can continue to run.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_EXIT(pt)				\
+  do {						\
+    PT_INIT(pt);				\
+    return PT_THREAD_EXITED;			\
+  } while(0)
+
+/**
+ * Declare the end of a protothread.
+ *
+ * This macro is used for declaring that a protothread ends. It should
+ * always be used together with a matching PT_BEGIN() macro.
+ *
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_END(pt) LC_END((pt)->lc); PT_EXIT(pt)
+
+
+/**
+ * Schedule a protothread.
+ *
+ * This function shedules a protothread. The return value of the
+ * function is non-zero if the protothread is running or zero if the
+ * protothread has exited.
+ *
+ * Example
+ \code
+ void main(void) {
+   struct pt p;
+   int event;
+   
+   PT_INIT(&p);
+   while(PT_SCHEDULE(consumer(&p, event))) {
+     event = get_event();
+   }   
+ }
+ \endcode
+ *
+ * \param f The call to the C function implementing the protothread to
+ * be scheduled
+ *
+ * \hideinitializer
+ */
+#define PT_SCHEDULE(f) (f == PT_THREAD_WAITING)
+
+/**
+ * Declarare that a protothread can yield.
+ *
+ * If a protothread should be able to yield with the PT_YIELD()
+ * statement, this flag must be placed first in the protothread's
+ * function body.
+ *
+ * Example:
+ \code
+ static
+ PT_THREAD(loop_thread(struct pt *pt))
+ {
+   PT_YIELDING();
+   static int i;
+
+   PT_BEGIN(pt);
+   
+   for(i = 0; i < 200; ++i) {
+     handle_item(i);
+     PT_YIELD(pt);
+   }
+   
+   PT_END(pt);
+ }
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define PT_YIELDING() char pt_yielded = 1
+
+/**
+ * Yield from the current protothread.
+ *
+ * This function will yield the protothread, thereby allowing other
+ * processing to take place in the system.
+ *
+ * \note The PT_YIELDING() flag must be placed first in the
+ * protothread's body if the PT_YIELD() function should be used.
+ *
+ * Example
+ \code
+static
+PT_THREAD(fade(struct pt *pt))
+{
+  PT_YIELDING();
+  static int delay;
+  
+  PT_BEGIN(pt);
+  
+  for(delay = 3980; delay > 20; delay -= 20) {
+    leds_red(LEDS_ON);
+    clock_delay(4000 - delay);
+    leds_red(LEDS_OFF);
+    clock_delay(delay);
+    PT_YIELD(pt);
+  }
+  
+  PT_END(pt);
+}
+ \endcode
+ * \param pt A pointer to the protothread control structure.
+ *
+ * \hideinitializer
+ */
+#define PT_YIELD(pt)				\
+  do {						\
+    pt_yielded = 0;				\
+    PT_WAIT_UNTIL(pt, pt_yielded);		\
+  } while(0)
+
+#endif /* __PT_H__ */
+
+
+/** @} */
diff --git a/contiki/lib/FILES b/contiki/lib/FILES
new file mode 100644
index 0000000..d27acbc
--- /dev/null
+++ b/contiki/lib/FILES
@@ -0,0 +1,48 @@
+The contiki/lib/ directory contains the source code for a number of
+utility function that are part of Contiki but are optional and not
+generally required.
+
+cc.h
+
+  Header file for C compiler tweaks.
+
+cfs.[ch], cfs-service.[ch]
+
+  The Contiki filesystem service interface.
+
+cfs-posix.[ch]
+
+  A CFS implementation using POSIX functions.
+
+ctk-filedialog.[ch]
+
+  A CTK file dialog widget.
+
+ctk-textedit.[ch]
+
+  A CTK text editor widget.
+
+libconio.[ch]
+
+  An implementation of selected parts of the Borland conio
+  interface. Used for easy porting of the ctk-conio.c CTK driver.
+
+list.[ch]
+
+  A generic list library.
+
+memb.[ch]
+
+  A generic memory block allocator library.
+
+petsciiconv.[ch]
+
+  Conversion routines between ASCII and PETSCII character encodings.
+
+strncasecmp.c
+
+  Implementation of the strncasecmp() function.
+
+timer.[ch]
+
+  A generic timer library.                  
\ No newline at end of file
diff --git a/contiki/lib/cc.h b/contiki/lib/cc.h
new file mode 100644
index 0000000..3f66649
--- /dev/null
+++ b/contiki/lib/cc.h
@@ -0,0 +1,102 @@
+/**
+ * \file
+ * Default definitions of C compiler quirk work-arounds.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * This file is used for making use of extra functionality of some C
+ * compilers used for Contiki, and defining work-arounds for various
+ * quirks and problems with some other C compilers.
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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 OS
+ *
+ * $Id: cc.h,v 1.6 2004/03/18 23:03:56 adamdunkels Exp $
+ *
+ */
+#ifndef __CC_H__
+#define __CC_H__
+
+#include "cc-conf.h"
+
+/**
+ * Configure if the C compiler supports the "register" keyword for
+ * function arguments.
+ */
+#if CC_CONF_REGISTER_ARGS
+#define CC_REGISTER_ARG register
+#else /* CC_CONF_REGISTER_ARGS */
+#define CC_REGISTER_ARG
+#endif /* CC_CONF_REGISTER_ARGS */
+
+/**
+ * Configure if the C compiler supports the arguments for function
+ * pointers.
+ */
+#if CC_CONF_FUNCTION_POINTER_ARGS
+#define CC_FUNCTION_POINTER_ARGS 1
+#else /* CC_CONF_FUNCTION_POINTER_ARGS */
+#define CC_FUNCTION_POINTER_ARGS 0
+#endif /* CC_CONF_FUNCTION_POINTER_ARGS */
+
+/**
+ * Configure if the C compiler supports fastcall function
+ * declarations.
+ */
+#ifdef CC_CONF_FASTCALL
+#define CC_FASTCALL CC_CONF_FASTCALL
+#else /* CC_CONF_FASTCALL */
+#define CC_FASTCALL
+#endif /* CC_CONF_FASTCALL */
+
+/**
+ * Configure work-around for unsigned char bugs with sdcc.
+ */
+#if CC_CONF_UNSIGNED_CHAR_BUGS
+#define CC_UNSIGNED_CHAR_BUGS 1
+#else /* CC_CONF_UNSIGNED_CHAR_BUGS */
+#define CC_UNSIGNED_CHAR_BUGS 0
+#endif /* CC_CONF_UNSIGNED_CHAR_BUGS */
+
+/**
+ * Configure if C compiler supports double hash marks in C macros.
+ */
+#if CC_CONF_DOUBLE_HASH
+#define CC_DOUBLE_HASH 1
+#else /* CC_CONF_DOUBLE_HASH */
+#define CC_DOUBLE_HASH 0
+#endif /* CC_CONF_DOUBLE_HASH */
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+#endif /* __CC_H__ */
+
diff --git a/contiki/lib/cfs-posix.c b/contiki/lib/cfs-posix.c
new file mode 100644
index 0000000..9bcc06f
--- /dev/null
+++ b/contiki/lib/cfs-posix.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cfs-posix.c,v 1.4 2005/04/10 19:23:06 oliverschmidt Exp $
+ */
+#include "contiki.h"
+
+#include "cfs.h"
+#include "cfs-service.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+
+static int  s_open(const char *n, int f);
+static void s_close(int f);
+static int  s_read(int f, char *b, unsigned int l);
+static int  s_write(int f, char *b, unsigned int l);
+static int  s_opendir(struct cfs_dir *p, const char *n);
+static int  s_readdir(struct cfs_dir *p, struct cfs_dirent *e);
+static int  s_closedir(struct cfs_dir *p);
+
+static const struct cfs_service_interface interface =
+  {
+    CFS_SERVICE_VERSION,
+    s_open,
+    s_close,
+    s_read,
+    s_write,
+    s_opendir,
+    s_readdir,
+    s_closedir
+  };
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_PROCESS(proc, CFS_SERVICE_NAME ": POSIX", EK_PRIO_NORMAL,
+           eventhandler, NULL, (void *)&interface);
+
+struct cfs_posix_dir {
+  DIR *dirp;
+};
+
+/*---------------------------------------------------------------------------*/
+EK_PROCESS_INIT(cfs_posix_init, arg)
+{
+  arg_free(arg);
+  ek_service_start(CFS_SERVICE_NAME, &proc);
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  switch(ev) {
+  case EK_EVENT_INIT:
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    ek_replace((struct ek_proc *)data, &interface);
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    ek_exit();
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+static int
+s_open(const char *n, int f)
+{
+  char filename[255];
+  sprintf(filename, "cfs-root/%s", n);
+  if(f == CFS_READ) {
+    return open(filename, O_RDONLY);
+  } else {
+    return open(filename, O_CREAT|O_TRUNC|O_RDWR);
+  }
+}
+/*---------------------------------------------------------------------------*/
+static void
+s_close(int f)
+{
+  close(f);
+}
+/*---------------------------------------------------------------------------*/
+static int
+s_read(int f, char *b, unsigned int l)
+{
+  return read(f, b, l);
+}
+/*---------------------------------------------------------------------------*/
+static int
+s_write(int f, char *b, unsigned int l)
+{
+  return write(f, b, l);
+}
+/*---------------------------------------------------------------------------*/
+static int
+s_opendir(struct cfs_dir *p, const char *n)
+{
+  struct cfs_posix_dir *dir = (struct cfs_posix_dir *)p;
+  char dirname[255];
+
+  if(n == NULL) {
+    n = "";
+  }
+  sprintf(dirname, "cfs-root/%s", n);
+  
+  dir->dirp = opendir(dirname);
+    
+  return dir->dirp == NULL;
+}
+/*---------------------------------------------------------------------------*/
+static int
+s_readdir(struct cfs_dir *p, struct cfs_dirent *e)
+{
+  struct cfs_posix_dir *dir = (struct cfs_posix_dir *)p;
+  struct dirent *res;
+  int ret;
+  
+  res = readdir(dir->dirp);
+  if(res == NULL) {
+    return 1;
+  }
+  strncpy(e->name, res->d_name, sizeof(e->name));
+  e->size = 0;
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+static int
+s_closedir(struct cfs_dir *p)
+{
+  struct cfs_posix_dir *dir = (struct cfs_posix_dir *)p;
+  closedir(dir->dirp);
+  return 1;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/lib/cfs-posix.h b/contiki/lib/cfs-posix.h
new file mode 100644
index 0000000..df80f76
--- /dev/null
+++ b/contiki/lib/cfs-posix.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cfs-posix.h,v 1.2 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#ifndef __CFS_POSIX_H__
+#define __CFS_POSIX_H__
+
+#include "ek.h"
+
+EK_PROCESS_INIT(cfs_posix_init, arg);
+
+#endif /* __CFS_POSIX_H__ */
diff --git a/contiki/lib/cfs-service.h b/contiki/lib/cfs-service.h
new file mode 100644
index 0000000..58d096b
--- /dev/null
+++ b/contiki/lib/cfs-service.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cfs-service.h,v 1.3 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#ifndef __CFS_SERVICE_H__
+#define __CFS_SERVICE_H__
+
+#include "ek-service.h"
+#include "cfs.h"
+
+
+#define CFS_SERVICE_VERSION 0x01
+#define CFS_SERVICE_NAME "Filesystem"
+
+struct cfs_dir {
+  unsigned char dummy_space[32];
+};
+
+struct cfs_dirent {
+  unsigned char name[32];
+  unsigned int size;
+};
+
+struct cfs_service_interface {
+  unsigned char version;
+  int  (* open)(const char *name, int flags);
+  void (* close)(int fd);
+  int  (* read)(int fd, char *buf, unsigned int len);
+  int  (* write)(int fd, char *buf, unsigned int len);
+
+  int  (* opendir)(struct cfs_dir *dir, const char *name);
+  int  (* readdir)(struct cfs_dir *dir, struct cfs_dirent *dirent);
+  int  (* closedir)(struct cfs_dir *dir);
+};
+
+#endif /* __CFS_SERVICE_H__ */
diff --git a/contiki/lib/cfs.c b/contiki/lib/cfs.c
new file mode 100644
index 0000000..eb5353d
--- /dev/null
+++ b/contiki/lib/cfs.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cfs.c,v 1.3 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#include "contiki.h"
+
+#include "cfs.h"
+#include "cfs-service.h"
+
+
+static int  null_open(const char *n, int f)                       {return -1;}
+static void null_close(int f)                                     {return;}
+static int  null_read(int f, char *b, unsigned int l)             {return -1;}
+static int  null_write(int f, char *b, unsigned int l)            {return -1;}
+static int  null_opendir(struct cfs_dir *p, const char *n)        {return -1;}
+static int  null_readdir(struct cfs_dir *p, struct cfs_dirent *e) {return -1;}
+static int  null_closedir(struct cfs_dir *p)                      {return -1;}
+
+static const struct cfs_service_interface nullinterface =
+  {
+    CFS_SERVICE_VERSION,
+    null_open,
+    null_close,
+    null_read,
+    null_write,
+    null_opendir,
+    null_readdir,
+    null_closedir
+  };
+
+EK_SERVICE(service, CFS_SERVICE_NAME);
+
+/*---------------------------------------------------------------------------*/
+struct cfs_service_interface *
+cfs_find_service(void)
+{
+  struct cfs_service_interface *interface;
+  interface = (struct cfs_service_interface *)ek_service_state(&service);
+  if(interface != NULL &&
+     interface->version == CFS_SERVICE_VERSION) {
+    return interface;
+  } else {
+    return (struct cfs_service_interface *)&nullinterface;
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/lib/cfs.h b/contiki/lib/cfs.h
new file mode 100644
index 0000000..328d127
--- /dev/null
+++ b/contiki/lib/cfs.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: cfs.h,v 1.3 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#ifndef __CFS_H__
+#define __CFS_H__
+
+#include "cfs-service.h"
+
+#define CFS_READ  0
+#define CFS_WRITE 1
+int cfs_open(const char *name, int flags);
+void cfs_close(int fd);
+int cfs_read(int fd, char *buf, unsigned int len);
+int cfs_write(int fd, char *buf, unsigned int len);
+
+int cfs_opendir(struct cfs_dir *dirp, const char *name);
+int cfs_readdir(struct cfs_dir *dirp, struct cfs_dirent *dirent);
+int cfs_closedir(struct cfs_dir *dirp);
+
+struct cfs_service_interface *cfs_find_service(void);
+
+#define cfs_open(name, flags)   (cfs_find_service()->open(name, flags))
+#define cfs_close(fd)           (cfs_find_service()->close(fd))
+#define cfs_read(fd, buf, len)  (cfs_find_service()->read(fd, buf, len))
+#define cfs_write(fd, buf, len) (cfs_find_service()->write(fd, buf, len))
+
+#define cfs_opendir(dirp, name) (cfs_find_service()->opendir(dirp, name))
+#define cfs_readdir(dirp, ent)  (cfs_find_service()->readdir(dirp, ent))
+#define cfs_closedir(dirp)      (cfs_find_service()->closedir(dirp))
+
+
+#endif /* __CFS_H__ */
diff --git a/contiki/lib/clock.h b/contiki/lib/clock.h
new file mode 100644
index 0000000..594c2e9
--- /dev/null
+++ b/contiki/lib/clock.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: clock.h,v 1.2 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#ifndef __CLOCK_H__
+#define __CLOCK_H__
+
+#include "clock-conf.h"
+
+void clock_init(void);
+
+clock_time_t clock_time(void);
+
+#ifdef CLOCK_CONF_SECOND
+#define CLOCK_SECOND CLOCK_CONF_SECOND
+#else
+#define CLOCK_SECOND (clock_time_t)32
+#endif
+
+#endif /* __CLOCK_H__ */
diff --git a/contiki/lib/ctk-filedialog.c b/contiki/lib/ctk-filedialog.c
new file mode 100644
index 0000000..41e887f
--- /dev/null
+++ b/contiki/lib/ctk-filedialog.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ctk-filedialog.c,v 1.5 2005/05/08 10:40:10 oliverschmidt Exp $
+ */
+
+#include "contiki.h"
+#include "ctk-filedialog.h"
+#include "ctk.h"
+#include "cfs.h"
+
+#include <string.h>
+
+#define MAX_NUMFILES 40
+#define FILES_WIDTH 17
+#define FILES_HEIGHT 14
+
+static struct ctk_window dialog;
+static char leftptr[FILES_HEIGHT];
+static struct ctk_label leftptrlabel =
+  {CTK_LABEL(0, 1, 1, FILES_HEIGHT, leftptr)};
+
+static char files[FILES_WIDTH * MAX_NUMFILES];
+static struct ctk_label fileslabel =
+  {CTK_LABEL(1, 1,
+	     FILES_WIDTH, FILES_HEIGHT, files)};
+
+static char rightptr[FILES_HEIGHT];
+static struct ctk_label rightptrlabel =
+  {CTK_LABEL(1 + FILES_WIDTH, 1, 1, FILES_HEIGHT, rightptr)};
+
+static char filename[FILES_WIDTH + 1];
+static struct ctk_textentry filenameentry =
+  {CTK_TEXTENTRY(1, 2 + FILES_HEIGHT, FILES_WIDTH, 1, filename,
+		 FILES_WIDTH)};
+
+static struct ctk_button button;
+
+#define STATE_CLOSED 0
+#define STATE_OPEN 1
+static char state = STATE_CLOSED;
+static unsigned char fileptr, dirfileptr;
+static struct cfs_dir dir;
+/*---------------------------------------------------------------------------*/
+static void
+clearptr(void)
+{
+  leftptr[fileptr] = ' ';
+  rightptr[fileptr] = ' '; 
+}
+/*---------------------------------------------------------------------------*/
+static void
+showptr(void)
+{
+  leftptr[fileptr] = '>';
+  rightptr[fileptr] = '<';
+
+  strncpy(filename,
+	  &files[fileptr * FILES_WIDTH],
+	  FILES_WIDTH);
+  
+  CTK_WIDGET_REDRAW(&filenameentry);
+  CTK_WIDGET_REDRAW(&leftptrlabel);
+  CTK_WIDGET_REDRAW(&rightptrlabel);
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_filedialog_init(register struct ctk_filedialog_state *s)
+{
+  state = STATE_CLOSED;
+}
+/*---------------------------------------------------------------------------*/
+void
+ctk_filedialog_open(register struct ctk_filedialog_state *s,
+		    const char *buttontext, ek_event_t event)
+{
+  ctk_dialog_new(&dialog, 20, 5 + FILES_HEIGHT);
+  CTK_WIDGET_ADD(&dialog, &leftptrlabel);
+  CTK_WIDGET_ADD(&dialog, &fileslabel);
+  CTK_WIDGET_ADD(&dialog, &rightptrlabel);
+  CTK_WIDGET_ADD(&dialog, &filenameentry);
+  CTK_BUTTON_NEW(&button, 1, 4 + FILES_HEIGHT, strlen(buttontext), (char *)buttontext);
+  CTK_WIDGET_ADD(&dialog, &button);
+  ctk_dialog_open(&dialog);
+  state = STATE_OPEN;
+  memset(filename, 0, sizeof(filename));
+  memset(leftptr, ' ', sizeof(leftptr));
+  memset(rightptr, ' ', sizeof(rightptr));
+  memset(files, 0, sizeof(files));
+  
+  fileptr = 0;
+  dirfileptr = 0;
+  showptr();
+  cfs_opendir(&dir, ".");
+  ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, s);
+}
+/*---------------------------------------------------------------------------*/
+char
+ctk_filedialog_eventhandler(struct ctk_filedialog_state *s,
+			    ek_event_t ev, ek_data_t data)
+{
+  static struct cfs_dirent dirent;
+  
+  if(state == STATE_OPEN) {
+    if(ev == ctk_signal_widget_activate &&
+       data == (ek_data_t)&button) {
+      ctk_dialog_close();
+      state = STATE_CLOSED;
+      ek_post(EK_PROC_ID(EK_CURRENT()), s->ev, &filename);
+      return 1;
+    } else if(ev == EK_EVENT_CONTINUE &&
+	      (ek_data_t)s == data) {
+      if(cfs_readdir(&dir, &dirent) == 0 &&
+	 dirfileptr < MAX_NUMFILES) {
+	strncpy(&files[dirfileptr * FILES_WIDTH],
+		dirent.name, FILES_WIDTH);
+	CTK_WIDGET_REDRAW(&fileslabel);
+	++dirfileptr;
+	ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_CONTINUE, s);
+      } else {
+	fileptr = 0;	
+	cfs_closedir(&dir);
+      }
+      return 1; 
+    } else if(ev == ctk_signal_keypress) {
+      if((ctk_arch_key_t)data == CH_CURS_UP) {
+	clearptr();
+	if(fileptr > 0) {
+	  --fileptr;
+	}
+	showptr();
+	return 1;
+      } else if((ctk_arch_key_t)data == CH_CURS_DOWN) {
+	clearptr();
+	if(fileptr < FILES_HEIGHT - 1) {
+	  ++fileptr;
+	}
+	showptr();
+	return 1;
+      }
+    }
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/lib/ctk-filedialog.h b/contiki/lib/ctk-filedialog.h
new file mode 100644
index 0000000..6b00116
--- /dev/null
+++ b/contiki/lib/ctk-filedialog.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: ctk-filedialog.h,v 1.2 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+#ifndef __CTK_FILEDIALOG_H__
+#define __CTK_FILEDIALOG_H__
+
+#include "contiki.h"
+
+struct ctk_filedialog_state {
+  unsigned char fileptr;
+  ek_event_t ev;
+};
+
+void ctk_filedialog_init(register struct ctk_filedialog_state *s);
+void ctk_filedialog_open(register struct ctk_filedialog_state *s,
+			 const char *buttontext, ek_event_t event);
+char ctk_filedialog_eventhandler(struct ctk_filedialog_state *s,
+				 ek_event_t ev, ek_data_t data);
+
+#endif /* __CTK_FILEDIALOG_H__ */
diff --git a/contiki/lib/ctk-textedit.c b/contiki/lib/ctk-textedit.c
new file mode 100644
index 0000000..3a345ab
--- /dev/null
+++ b/contiki/lib/ctk-textedit.c
@@ -0,0 +1,181 @@
+/**
+ * \file
+ * An experimental CTK text edit widget.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * This module contains an experimental CTK widget which is
+ * implemented in the application process rather than in the CTK
+ * process. The widget is instantiated in a similar fashion as other
+ * CTK widgets, but is different from other widgets in that it
+ * requires a signal handler function to be called by the process
+ * signal handler function.
+ * 
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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: ctk-textedit.c,v 1.4 2004/09/01 18:26:55 adamdunkels Exp $
+ *
+ */
+
+
+#include "ctk-textedit.h"
+
+#include <string.h>
+
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_textedit_init(struct ctk_textedit *t)
+{
+  t->xpos = t->ypos = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Add a CTK textedit widget to a window.
+ *
+ * \param w A pointer to the window to which the entry is to be added.
+ * \param t A pointer to the CTK textentry structure.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_textedit_add(struct ctk_window *w,
+		 struct ctk_textedit *t)
+{
+  CTK_WIDGET_SET_FLAG(t, CTK_WIDGET_FLAG_MONOSPACE);
+  CTK_WIDGET_ADD(w, t);
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * The CTK textedit signal handler.
+ *
+ * This function must be called as part of the normal signal handler
+ * of the process that contains the CTK textentry structure.
+ *
+ * \param t A pointer to the CTK textentry structure.
+ * \param s The signal number.
+ * \param data The signal data.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+ctk_textedit_eventhandler(struct ctk_textedit *t,
+			  ek_event_t s,
+			  ek_data_t data)
+{
+  char *textptr, *textptr2;
+  unsigned char len;
+  
+  if(s == ctk_signal_keypress) {
+    CTK_WIDGET_FOCUS(t->label.window, &t->label);
+    textptr = &(t->label.text[t->ypos * t->label.w + t->xpos]);
+    *textptr &= 0x7f;
+    switch((ctk_arch_key_t)data) {
+    case CH_CURS_DOWN:
+      if(t->ypos < t->label.h - 1) {
+	++t->ypos;
+      }
+      break; 
+    case CH_CURS_UP:
+      if(t->ypos > 0) {
+	--t->ypos;
+      }
+      break; 
+    case CH_CURS_RIGHT:
+      len = strlen(&t->label.text[t->ypos * t->label.w]);
+      if(t->xpos < len) {
+	/*      if(t->xpos < t->label.w) {*/
+	++t->xpos;
+      } else {
+	t->xpos = len;
+      }
+      break; 
+    case CH_CURS_LEFT:
+      if(t->xpos > 0) {
+	--t->xpos;
+      } else {
+	if(t->ypos > 0) {
+	  --t->ypos;
+	  t->xpos = t->label.w - 1;
+	}       
+      }
+      break;
+    case CH_ENTER:
+      t->xpos = 0;
+      if(t->ypos < t->label.h - 1) {
+	++t->ypos;
+      }
+      break;
+    case CH_DEL:
+      len = t->label.w - t->xpos;
+      if(t->xpos > 0 && len > 0) {
+	strncpy(textptr - 1, textptr,
+		len);
+	*(textptr + len - 1) = 0;
+	--t->xpos;
+      }
+      break;      
+    default:
+      len = t->label.w - t->xpos;
+      if(len > 0) {
+	textptr2 = textptr + len - 1;
+	while(textptr2 + 1 > textptr) {
+	  *(textptr2 + 1) = *textptr2;
+	  --textptr2;
+	}
+	
+	*textptr = (char)data;
+	++t->xpos;
+	if(t->xpos == t->label.w) {
+	  t->xpos = 0;
+	  if(t->ypos < t->label.h - 1) {
+	    ++t->ypos;
+	  }
+	}
+      }
+      break;
+    }
+    textptr = &(t->label.text[t->ypos * t->label.w + t->xpos]);
+    *textptr |= 0x80;
+    CTK_WIDGET_REDRAW(&t->label);
+  } else if(s == ctk_signal_widget_activate &&
+	    data == (ek_data_t)t) {
+    textptr = &(t->label.text[t->ypos * t->label.w + t->xpos]);
+    *textptr &= 0x7f;
+    t->xpos = 0;
+    if(t->ypos < t->label.h - 1) {
+      ++t->ypos;
+    }
+    textptr = &(t->label.text[t->ypos * t->label.w + t->xpos]);
+    *textptr |= 0x80;
+    CTK_WIDGET_REDRAW(&t->label);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/ctk-textedit.h b/contiki/lib/ctk-textedit.h
new file mode 100644
index 0000000..3668946
--- /dev/null
+++ b/contiki/lib/ctk-textedit.h
@@ -0,0 +1,73 @@
+/**
+ * \file
+ * Header file for the experimental application level CTK textedit widget.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/*
+ * Copyright (c) 2003, 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. 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: ctk-textedit.h,v 1.4 2004/09/01 18:27:18 adamdunkels Exp $
+ *
+ */
+#ifndef __CTK_TEXTEDIT_H__
+#define __CTK_TEXTEDIT_H__
+
+#include "ctk.h"
+
+/**
+ * Instantiating macro for the CTK textedit widget.
+ *
+ *
+ * \param tx The x position of the widget.
+ * \param ty The y position of the widget.
+ * \param tw The width of the widget.
+ * \param th The height of the widget.
+ * \param ttext The text buffer to be edited.
+ */
+#define CTK_TEXTEDIT(tx, ty, tw, th, ttext) \
+  {CTK_LABEL(tx, ty, tw, th, ttext)}, 0, 0
+struct ctk_textedit {
+  struct ctk_label label;
+  unsigned char xpos, ypos;
+};
+
+void ctk_textedit_init(struct ctk_textedit *t);
+
+void ctk_textedit_add(struct ctk_window *w,
+		      struct ctk_textedit *t);
+
+void ctk_textedit_eventhandler(struct ctk_textedit *t,
+			       ek_event_t s,
+			       ek_data_t data);          
+
+#endif /* __CTK_TEXTEDIT_H__ */
diff --git a/contiki/lib/ctk-textentry-checkbox.c b/contiki/lib/ctk-textentry-checkbox.c
new file mode 100644
index 0000000..f8a73e5
--- /dev/null
+++ b/contiki/lib/ctk-textentry-checkbox.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002-2003, 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. 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 operating system.
+ *
+ * $Id: ctk-textentry-checkbox.c,v 1.1 2005/05/06 00:04:47 oliverschmidt Exp $
+ *
+ */
+
+#include "ctk.h"
+
+#include "ctk-textentry-checkbox.h"
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_textentry_checkbox_input(ctk_arch_key_t c,
+			     struct ctk_textentry *t)
+{
+  switch(c) {
+  case 'X':
+  case 'x':
+    *t->text = 'x';
+    return 1;
+
+  case ' ':
+    *t->text = *t->text == 'x'? 0:'x';
+    return 1;
+
+  case CH_DEL:
+  case CH_ENTER:
+  case CTK_CONF_WIDGETDOWN_KEY:
+  case CTK_CONF_WIDGETUP_KEY:
+    return 0;
+  }
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/ctk-textentry-checkbox.h b/contiki/lib/ctk-textentry-checkbox.h
new file mode 100644
index 0000000..473ec80
--- /dev/null
+++ b/contiki/lib/ctk-textentry-checkbox.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003, 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. 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: ctk-textentry-checkbox.h,v 1.1 2005/05/06 00:04:47 oliverschmidt Exp $
+ *
+ */
+#ifndef __CTK_TEXTENTRY_CHECKBOX_H__
+#define __CTK_TEXTENTRY_CHECKBOX_H__
+
+unsigned char ctk_textentry_checkbox_input(ctk_arch_key_t c,
+					   struct ctk_textentry *t);
+
+#endif /* __CTK_TEXTENTRY_CHECKBOX_H__ */
diff --git a/contiki/lib/ctk-textentry-cmdline.c b/contiki/lib/ctk-textentry-cmdline.c
new file mode 100644
index 0000000..01ed3b7
--- /dev/null
+++ b/contiki/lib/ctk-textentry-cmdline.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002-2003, 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. 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 operating system.
+ *
+ * $Id: ctk-textentry-cmdline.c,v 1.1 2005/05/05 23:29:50 oliverschmidt Exp $
+ *
+ */
+
+#include "ctk.h"
+
+#include "ctk-textentry-cmdline.h"
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_textentry_cmdline_input(ctk_arch_key_t c,
+			    struct ctk_textentry *t)
+{
+  if(c == CH_ENTER) {
+    ek_post(t->window->owner, ctk_signal_widget_activate, t);
+    return 1;
+  }
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/ctk-textentry-cmdline.h b/contiki/lib/ctk-textentry-cmdline.h
new file mode 100644
index 0000000..38e7ad7
--- /dev/null
+++ b/contiki/lib/ctk-textentry-cmdline.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003, 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. 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: ctk-textentry-cmdline.h,v 1.1 2005/05/05 23:29:50 oliverschmidt Exp $
+ *
+ */
+#ifndef __CTK_TEXTENTRY_CMDLINE_H__
+#define __CTK_TEXTENTRY_CMDLINE_H__
+
+unsigned char ctk_textentry_cmdline_input(ctk_arch_key_t c,
+					  struct ctk_textentry *t);
+
+#endif /* __CTK_TEXTENTRY_CMDLINE_H__ */
diff --git a/contiki/lib/ctk-textentry-multiline.c b/contiki/lib/ctk-textentry-multiline.c
new file mode 100644
index 0000000..26ae0de
--- /dev/null
+++ b/contiki/lib/ctk-textentry-multiline.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2002-2003, 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. 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 operating system.
+ *
+ * $Id: ctk-textentry-multiline.c,v 1.3 2005/05/05 20:55:50 oliverschmidt Exp $
+ *
+ */
+
+#include <string.h>
+
+#include "ctk.h"
+
+#include "ctk-textentry-multiline.h"
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+ctk_textentry_multiline_input(ctk_arch_key_t c,
+			      struct ctk_textentry *t)
+{
+  unsigned char len;
+
+  switch(c) {
+  case 0:
+    t->xpos = strlen(&t->text[t->ypos * (t->len + 1)]);
+    if(t->xpos == t->len) {
+      --t->xpos;
+    }
+    return 1;
+
+  case CH_CURS_UP:
+    if(t->ypos == 0) {
+      t->xpos = 0;
+      return 1;
+    }
+    --t->ypos;
+    break;
+
+  case CH_CURS_DOWN:
+    if(t->ypos == t->h - 1) {
+      t->xpos = strlen(&t->text[t->ypos * (t->len + 1)]);
+      if(t->xpos == t->len) {
+	--t->xpos;
+      }
+      return 1;
+    }
+    ++t->ypos;
+    break;
+
+  case CH_ENTER:
+    if(t->ypos == t->h - 1) {
+      return 0;
+    }
+    ++t->ypos;
+    t->xpos = 0;
+    return 1;
+
+  default:
+    return 0;
+  }
+
+  len = strlen(&t->text[t->ypos * (t->len + 1)]);
+  if(t->xpos > len) {
+    t->xpos = len;
+  }
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/ctk-textentry-multiline.h b/contiki/lib/ctk-textentry-multiline.h
new file mode 100644
index 0000000..68dc0bf
--- /dev/null
+++ b/contiki/lib/ctk-textentry-multiline.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003, 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. 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: ctk-textentry-multiline.h,v 1.1 2005/05/04 21:57:08 oliverschmidt Exp $
+ *
+ */
+#ifndef __CTK_TEXTENTRY_MULTILINE_H__
+#define __CTK_TEXTENTRY_MULTILINE_H__
+
+unsigned char ctk_textentry_multiline_input(ctk_arch_key_t c,
+					    struct ctk_textentry *t);
+
+#endif /* __CTK_TEXTENTRY_MULTILINE_H__ */
diff --git a/contiki/lib/libconio.c b/contiki/lib/libconio.c
new file mode 100644
index 0000000..07b8113
--- /dev/null
+++ b/contiki/lib/libconio.c
@@ -0,0 +1,190 @@
+/*
+ * 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. 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.6 2004/09/12 20:24:55 adamdunkels Exp $
+ *
+ */
+
+#include <string.h>
+#include "libconio.h"
+
+static unsigned char cursx, cursy;
+static unsigned char reversed;
+static unsigned char color;
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+wherex(void)
+{
+  return cursx;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+wherey(void)
+{
+  return cursy;
+}
+/*-----------------------------------------------------------------------------------*/
+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, color);
+  ++cursx;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+cputs(char *str)
+{
+  while(*str != 0) {
+    cputc(*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) {
+    cputc('|');
+    --cursx;
+    ++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)
+{
+  color = c;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+bgcolor(unsigned char c)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+void
+bordercolor(unsigned char c)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+void
+screensize(unsigned char *x, unsigned char *y)
+{
+  *x = LIBCONIO_SCREEN_WIDTH;
+  *y = LIBCONIO_SCREEN_HEIGHT;
+}
+/*-----------------------------------------------------------------------------------*/
diff --git a/contiki/lib/libconio.h b/contiki/lib/libconio.h
new file mode 100644
index 0000000..cf9d4e3
--- /dev/null
+++ b/contiki/lib/libconio.h
@@ -0,0 +1,87 @@
+/*
+ * 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. 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.5 2004/06/06 06:09:14 adamdunkels Exp $
+ *
+ */
+
+#ifndef __LIBCONIO_H__
+#define __LIBCONIO_H__
+
+#include "libconio-conf.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,
+			unsigned char color);
+
+/* Default definitions that should be overridden by calling module. */
+#ifndef LIBCONIO_CONF_SCREEN_WIDTH
+#define LIBCONIO_SCREEN_WIDTH 40
+#else
+#define LIBCONIO_SCREEN_WIDTH LIBCONIO_CONF_SCREEN_WIDTH
+#endif /* LIBCONIO_SCREEN_WIDTH */
+
+#ifndef LIBCONIO_CONF_SCREEN_HEIGHT
+#define LIBCONIO_SCREEN_HEIGHT 25
+#else
+#define LIBCONIO_SCREEN_HEIGHT LIBCONIO_CONF_SCREEN_HEIGHT
+#endif /* LIBCONIO_CONF_SCREEN_HEIGHT */
+
+
+
+/* These are function declarations for functions implemented in libconio.c */
+unsigned char wherex(void);
+unsigned char wherey(void);
+void clrscr(void);
+void bgcolor(unsigned char c);
+void bordercolor(unsigned char c);
+void screensize(unsigned char *x, unsigned char *y);
+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/list.c b/contiki/lib/list.c
new file mode 100644
index 0000000..4d8b505
--- /dev/null
+++ b/contiki/lib/list.c
@@ -0,0 +1,323 @@
+/**
+ * \defgroup list Linked list library
+ * @{
+ *
+ * The linked list library provides a set of functions for
+ * manipulating linked lists.
+ *
+ * A linked list is made up of elements where the first element \b
+ * must be a pointer. This pointer is used by the linked list library
+ * to form lists of the elements.
+ *
+ * Lists are declared with the LIST() macro. The declaration specifies
+ * the name of the list that later is used with all list functions.
+ *
+ * Example:
+ \code
+
+struct packet {
+   struct packet *next;
+   char data[1500];
+   int len;
+};
+
+LIST(packets);
+
+static void
+init_function(void) {
+   list_init(packets);
+}
+
+static void
+another_function(struct packet *p) {
+   list_add(packets, p);
+
+   p = list_head(packets);
+
+   p = list_tail(packets);
+}
+ \endcode 
+ *
+ * Lists can be manipulated by inserting or removing elements from
+ * either sides of the list (list_push(), list_add(), list_pop(),
+ * list_chop()). A specified element can also be removed from inside a
+ * list with list_remove(). The head and tail of a list can be
+ * extracted using list_head() and list_tail(), respecitively.
+ */
+
+/**
+ * \file
+ * Linked list library implementation.
+ *
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: list.c,v 1.4 2005/02/07 07:52:31 adamdunkels Exp $
+ */
+#include "list.h"
+
+#define NULL 0
+
+struct list {
+  struct list *next;
+};
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Initialize a list.
+ *
+ * This function initalizes a list. The list will be empty after this
+ * function has been called.
+ *
+ * \param list The list to be initialized.
+ */
+void
+list_init(list_t list)
+{
+  *list = NULL;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Get a pointer to the first element of a list.
+ *
+ * This function returns a pointer to the first element of the
+ * list. The element will \b not be removed from the list.
+ *
+ * \param list The list.
+ * \return A pointer to the first element on the list.
+ *
+ * \sa list_tail()
+ */
+void *
+list_head(list_t list)
+{
+  return *list;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Duplicate a list.
+ *
+ * This function duplicates a list by copying the list reference, but
+ * not the elements.
+ *
+ * \note This function does \b not copy the elements of the list, but
+ * merely duplicates the pointer to the first element of the list.
+ *
+ * \param dest The destination list.
+ * \param src The source list.
+ */
+void
+list_copy(list_t dest, list_t src)
+{
+  *dest = *src;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Get the tail of a list.
+ *
+ * This function returns a pointer to the elements following the first
+ * element of a list. No elements are removed by this function.
+ *
+ * \param list The list
+ * \return A pointer to the element after the first element on the list.
+ *
+ * \sa list_head()
+ */
+void *
+list_tail(list_t list)
+{
+  struct list *l;
+  
+  if(*list == NULL) {
+    return NULL;
+  }
+  
+  for(l = *list; l->next != NULL; l = l->next);
+  
+  return l;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Add an item at the end of a list.
+ *
+ * This function adds an item to the end of the list.
+ *
+ * \param list The list.
+ * \param item A pointer to the item to be added.
+ *
+ * \sa list_push()
+ *
+ */
+void
+list_add(list_t list, void *item)
+{
+  struct list *l;
+
+  ((struct list *)item)->next = NULL;
+  
+  l = list_tail(list);
+
+  if(l == NULL) {
+    *list = item;
+  } else {
+    l->next = item;
+  }
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Add an item to the start of the list.
+ */
+void
+list_push(list_t list, void *item)
+{
+  /*  struct list *l;*/
+
+  ((struct list *)item)->next = *list;
+  *list = item;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Remove the last object on the list.
+ *
+ * This function removes the last object on the list and returns it.
+ * 
+ * \param list The list
+ * \return The removed object
+ *
+ */
+void *
+list_chop(list_t list)
+{
+  struct list *l, *r;
+  
+  if(*list == NULL) {
+    return NULL;
+  }
+  if(((struct list *)*list)->next == NULL) {
+    l = *list;
+    *list = NULL;
+    return l;
+  }
+  
+  for(l = *list; l->next->next != NULL; l = l->next);
+
+  r = l->next;
+  l->next = NULL;
+  
+  return r;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Remove the first object on a list.
+ *
+ * This function removes the first object on the list and returns it.
+ *
+ * \param list The list.
+ * \return The new head of the list.
+ */
+/*---------------------------------------------------------------------------*/
+void *
+list_pop(list_t list)
+{
+  struct list *l;
+  
+  if(*list != NULL) {   
+    *list = ((struct list *)*list)->next;
+  }
+
+  return *list;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Remove a specific element from a list.
+ *
+ * This function removes a specified element from the list.
+ *
+ * \param list The list.
+ * \param item The item that is to be removed from the list.
+ *
+ */
+/*---------------------------------------------------------------------------*/
+void
+list_remove(list_t list, void *item)
+{
+  struct list *l, *r;
+  
+  if(*list == NULL) {
+    return;
+  }
+  
+  r = NULL;
+  for(l = *list; l != NULL; l = l->next) {
+    if(l == item) {
+      if(r == NULL) {
+	/* First on list */
+	*list = l->next;
+      } else {
+	/* Not first on list */
+	r->next = l->next;
+      }
+      l->next = NULL;
+      return;
+    }
+    r = l;
+  }
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Get the length of a list.
+ *
+ * This function counts the number of elements on a specified list.
+ *
+ * \param list The list.
+ * \return The length of the list.
+ */
+/*---------------------------------------------------------------------------*/
+int
+list_length(list_t list)
+{
+  struct list *l; 
+  int n = 0;
+
+  for(l = *list; l != NULL; l = l->next) {
+    ++n;
+  }
+
+  return n;
+}
+/*---------------------------------------------------------------------------*/
+
+/** @} */
diff --git a/contiki/lib/list.h b/contiki/lib/list.h
new file mode 100644
index 0000000..abf8c7d
--- /dev/null
+++ b/contiki/lib/list.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: list.h,v 1.3 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+/**
+ * \file
+ * Linked list manipulation routines.
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ *
+\code
+
+struct packet {
+   struct packet *next;
+   char data[1500];
+   int len;
+};
+
+LIST(packets, struct packet *);
+
+static void
+init_function(void) {
+   list_init(&packets);
+}
+
+static void
+another_function(struct packet *p) {
+   list_add(packets, p);
+
+   p = list_head(packets);
+
+   p = list_tail(packets);
+}
+
+\endcode 
+ */
+
+#ifndef __LIST_H__
+#define __LIST_H__
+
+/**
+ */
+#define LIST(name, type) \
+         static type name##_list; \
+         static void **name = (void **)&name##_list; 
+         
+
+void  list_init(void **list);
+void *list_head(void **list);
+void *list_tail(void **list);
+void *list_pop (void **list);
+void  list_push(void **list, void *item);
+
+void *list_chop(void **list);
+
+void  list_add(void **list, void *item);
+
+
+void  list_copy(void **dest, void **src);
+
+#endif /* __LIST_H__ */
+
+
+
+
diff --git a/contiki/lib/memb.c b/contiki/lib/memb.c
new file mode 100644
index 0000000..d4e8d09
--- /dev/null
+++ b/contiki/lib/memb.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: memb.c,v 1.5 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+/**
+ * \defgroup memb Memory block management functions
+ *
+ * The memory block allocation routines provide a simple yet powerful
+ * set of functions for managing a set of memory blocks of fixed
+ * size. A set of memory blocks is statically declared with the
+ * MEMB() macro. Memory blocks are allocated from the declared
+ * memory by the memb_alloc() function, and are deallocated with the
+ * memb_free() function.
+ *
+ * \note Because of namespace clashes only one MEMB() can be
+ * declared per C module, and the name scope of a MEMB() memory
+ * block is local to each C module.
+ *
+ * The following example shows how to declare and use a memory block
+ * called "cmem" which has 8 chunks of memory with each memory chunk
+ * being 20 bytes large.
+ *
+ \code
+ #include "memb.h"
+ 
+ MEMB(cmem, 20, 8);
+
+ int main(int argc, char *argv[]) {
+    char *ptr;
+    
+    memb_init(&cmem);
+
+    ptr = memb_alloc(&cmem);
+
+    if(ptr != NULL) {
+       do_something(ptr);
+    } else {
+       printf("Could not allocate memory.\n");
+    }
+
+    if(memb_free(&cmem, ptr) == 0) {
+       printf("Deallocation succeeded.\n");
+    }
+ }
+ \endcode
+ *
+ * @{
+ */
+
+ /**
+ * \file
+ * Memory block allocation routines.
+ * \author Adam Dunkels <adam@sics.se>
+ */
+#include <string.h>
+
+#include "memb.h"
+
+/*------------------------------------------------------------------------------*/
+/**
+ * Initialize a memory block that was declared with MEMB().
+ *
+ * \param m A memory block previosly declared with MEMB().
+ */
+/*------------------------------------------------------------------------------*/
+void
+memb_init(struct memb_blocks *m)
+{
+  memset(m->mem, 0, (m->size + 1) * m->num);
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Allocate a memory block from a block of memory declared with MEMB().
+ *
+ * \param m A memory block previosly declared with MEMB().
+ */
+/*------------------------------------------------------------------------------*/
+char *
+memb_alloc(struct memb_blocks *m)
+{
+  int i;
+  char *ptr;
+
+  ptr = m->mem;
+  for(i = 0; i < m->num; ++i) {
+    if(*ptr == 0) {
+      /* If this block was unused, we increase the reference count to
+	 indicate that it now is used and return a pointer to the
+	 first byte following the reference counter. */
+      ++*ptr;
+      return ptr + 1;
+    }
+    ptr += m->size + 1;
+  }
+
+  /* No free block was found, so we return NULL to indicate failure to
+     allocate block. */
+  return NULL;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Deallocate a memory block from a memory block previously declared
+ * with MEMB().
+ *
+ * \param m m A memory block previosly declared with MEMB().
+ *
+ * \param ptr A pointer to the memory block that is to be deallocated.
+ *
+ * \return The new reference count for the memory block (should be 0
+ * if successfully deallocated) or -1 if the pointer "ptr" did not
+ * point to a legal memory block.
+ */
+/*------------------------------------------------------------------------------*/
+char
+memb_free(struct memb_blocks *m, void *ptr)
+{
+  int i;
+  char *ptr2;
+
+  /* Walk through the list of blocks and try to find the block to
+     which the pointer "ptr" points to. */
+  ptr2 = m->mem;
+  for(i = 0; i < m->num; ++i) {
+    
+    if(ptr2 == (char *)ptr - 1) {
+      /* We've found to block to which "ptr" points so we decrease the
+	 reference count and return the new value of it. */      
+      return --*ptr2;
+    }
+    ptr2 += m->size + 1;
+  }
+  return -1;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Increase the reference count for a memory chunk.
+ *
+ * \note No sanity checks are currently made.
+ *
+ * \param m m A memory block previosly declared with MEMB().
+ *
+ * \param ptr A pointer to the memory chunk for which the reference
+ * count should be increased.
+ *
+ * \return The new reference count.
+ */
+/*------------------------------------------------------------------------------*/
+char
+memb_ref(struct memb_blocks *m, char *ptr)
+{
+  return ++*(ptr - 1);
+}
+/*------------------------------------------------------------------------------*/
+
+/** @} */
diff --git a/contiki/lib/memb.h b/contiki/lib/memb.h
new file mode 100644
index 0000000..1be35d4
--- /dev/null
+++ b/contiki/lib/memb.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: memb.h,v 1.6 2004/09/12 20:24:55 adamdunkels Exp $
+ */
+/**
+ * \addtogroup memb 
+ * @{
+ */
+
+/**
+ * \file
+ * Memory block allocation routines.
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __MEMB_H__
+#define __MEMB_H__
+
+/**
+ * Declare a memory block.
+ *
+ * This macro is used to staticall declare a block of memory that can
+ * be used by the block allocation functions. The macro statically
+ * declares a C array with a size that matches the specified number of
+ * blocks and their individual sizes.
+ *
+ * Example:
+ \code
+MEMB(connections, sizeof(struct connection), 16);
+ \endcode
+ *
+ * \param name The name of the memory block (later used with
+ * memb_init(), memb_alloc() and memb_free()).
+ *
+ * \param size The size of each memory chunk, in bytes.
+ *
+ * \param num The total number of memory chunks in the block.
+ *
+ */
+#if CC_DOUBLE_HASH
+#define MEMB(name, size, num) \
+        static char name##_memb_mem[(size + 1) * num]; \
+        static struct memb_blocks name = {size, num, name##_memb_mem}
+#else /* CC_DOUBLE_HASH */
+#define MEMB(name, size, num) \
+        static char name_memb_mem[(size + 1) * num]; \
+        static struct memb_blocks name = {size, num, name_memb_mem}
+#endif /* CC_DOUBLE_HASH */
+
+struct memb_blocks {
+  unsigned short size;
+  unsigned short num;
+  char *mem;
+};
+
+void  memb_init(struct memb_blocks *m);
+char *memb_alloc(struct memb_blocks *m);
+char  memb_ref(struct memb_blocks *m, char *ptr);
+char  memb_free(struct memb_blocks *m, void *ptr);
+
+/** @} */
+
+#endif /* __MEMB_H__ */
diff --git a/contiki/lib/petsciiconv.c b/contiki/lib/petsciiconv.c
new file mode 100644
index 0000000..7a46269
--- /dev/null
+++ b/contiki/lib/petsciiconv.c
@@ -0,0 +1,116 @@
+/*
+ * 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. 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.3 2003/09/02 21:47:28 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)
+{
+  static char c;
+  
+  ptr = buf;
+  for(i = len; i > 0; --i) {
+    c = *ptr;
+    if(c == 0x0a) {
+      c = 0x0d;
+    } else if(c == 0x0d) {
+      c = 0x0a;
+    } 
+    switch (c & 0xe0) {
+    case 0x40:                
+    case 0x60:
+      c ^= 0x20;
+      break;
+    case 0xc0:               
+      c ^= 0x80;
+      break;
+    }
+    *ptr = c & 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..13eb053
--- /dev/null
+++ b/contiki/lib/petsciiconv.h
@@ -0,0 +1,77 @@
+/**
+ * \file
+ * PETSCII/ASCII conversion functions.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * The Commodore based Contiki targets all have a special character
+ * encoding called PETSCII which differs from the ASCII encoding that
+ * normally is used for representing characters.
+ *
+ * \note For targets that do not use PETSCII encoding the C compiler
+ * define WITH_ASCII should be used to avoid the PETSCII converting
+ * functions.
+ *
+ */
+
+/*
+ * 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. 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.2 2003/09/02 21:47:28 adamdunkels Exp $
+ *
+ */
+#ifndef __PETSCIICONV_H__
+#define __PETSCIICONV_H__
+
+#ifdef WITH_ASCII
+
+#define petsciiconv_toascii(buf, len)
+#define petsciiconv_topetscii(buf, len)
+
+#else /* WITH_ASCII */
+
+/**
+ * Convert a text buffer from PETSCII to ASCII.
+ *
+ * \param buf A pointer to the buffer which is to be converted.
+ * \param len The length of the buffer to be converted.
+ */
+void petsciiconv_toascii(char *buf, unsigned int len);
+/**
+ * Convert a text buffer from ASCII to PETSCII.
+ *
+ * \param buf A pointer to the buffer which is to be converted.
+ * \param len The length of the buffer to be converted.
+ */
+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..ee64718
--- /dev/null
+++ b/contiki/lib/strncasecmp.c
@@ -0,0 +1,70 @@
+/*
+ * 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. 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.3 2004/06/06 06:09:14 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.
+*/
+
+#define MAX_STRLEN 40
+
+
+int strncmp(const char *s1, const char *s2, int len);
+
+/*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/lib/timer.c b/contiki/lib/timer.c
new file mode 100644
index 0000000..dbbe286
--- /dev/null
+++ b/contiki/lib/timer.c
@@ -0,0 +1,160 @@
+/**
+ * \defgroup timer Timer library
+ * @{
+ *
+ * The Contiki kernel does not provide support for timed
+ * events. Rather, an application that wants to use timers needs to
+ * explicitly use the timer library.
+ *
+ * The timer library provides functions for setting, resetting and
+ * restarting timers, and for checking if a timer has expired. An
+ * application must "manually" check if its timers have expired; this
+ * is not done automatically.
+ *
+ * A timer is declared as a \c struct \c timer and all access to the
+ * timer is made by a pointer to the declared timer.
+ *
+ * Example:
+ \code
+
+ static struct timer periodic;
+
+ LOADER_INIT_FUNC(example_init, arg) {
+   timer_set(&periodic, CLOCK_SECOND);
+ }
+ 
+ EK_POLLHANDLER(pollhandler) {
+   if(timer_expired(&periodic)) {
+     timer_restart(&periodic);
+     do_periodic_stuff();
+   }
+ }
+ 
+ \endcode
+ *
+ * \note The timer library uses the \ref clock "Clock library" to
+ * measure time. Intervals should be specified in the format used by
+ * the clock library.
+ *
+ * \sa \ref clock "Clock library"
+ */
+
+/**
+ * \file
+ * Timer library implementation.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: timer.c,v 1.5 2005/02/07 22:45:14 adamdunkels Exp $
+ */
+#include "timer.h"
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Set a timer.
+ *
+ * This function is used to set a timer for a time sometime in the
+ * future. The function timer_expired() will evaluate to true after
+ * the timer has expired.
+ *
+ * \param t A pointer to the timer
+ * \param interval The interval before the timer expires.
+ *
+ */
+void
+timer_set(struct timer *t, clock_time_t interval)
+{
+  t->interval = interval;
+  t->start = clock_time();
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Reset the timer with the same interval.
+ *
+ * This function resets the timer with the same interval that was
+ * given to the timer_set() function. The start point of the interval
+ * is the exact time that the timer last expired. Therefore, this
+ * function will cause the timer to be stable over time, unlike the
+ * timer_rester() function.
+ *
+ * \param t A pointer to the timer.
+ *
+ * \sa timer_restart()
+ */
+void
+timer_reset(struct timer *t)
+{
+  t->start += t->interval;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Restart the timer from the current point in time
+ *
+ * This function restarts a timer with the same interval that was
+ * given to the timer_set() function. The timer will start at the
+ * current time.
+ *
+ * \note A periodic timer will drift if this function is used to reset
+ * it. For preioric timers, use the timer_reset() function instead.
+ *
+ * \param t A pointer to the timer.
+ *
+ * \sa timer_reset()
+ */
+void
+timer_restart(struct timer *t)
+{
+  t->start = clock_time();
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Check if a timer has expired.
+ *
+ * This function tests if a timer has expired and returns true or
+ * false depending on its status.
+ *
+ * \param t A pointer to the timer
+ *
+ * \return Non-zero if the timer has expired, zero otherwise.
+ *
+ */
+int
+timer_expired(struct timer *t)
+{
+  return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval;
+}
+/*---------------------------------------------------------------------------*/
+
diff --git a/contiki/lib/timer.h b/contiki/lib/timer.h
new file mode 100644
index 0000000..a817d53
--- /dev/null
+++ b/contiki/lib/timer.h
@@ -0,0 +1,70 @@
+/**
+ * \addtogroup timer
+ * @{
+ */
+
+/**
+ * \file
+ * Timer library header file.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: timer.h,v 1.4 2005/02/07 22:45:15 adamdunkels Exp $
+ */
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+#include "clock.h"
+
+/**
+ * A timer.
+ *
+ * This structure is used for declaring a timer. The timer must be set
+ * with timer_set() before it can be used.
+ *
+ * \hideinitializer
+ */
+struct timer {
+  clock_time_t start;
+  clock_time_t interval;
+};
+
+void timer_set(struct timer *t, clock_time_t interval);
+void timer_reset(struct timer *t);
+void timer_restart(struct timer *t);
+int timer_expired(struct timer *t);
+
+#endif /* __TIMER_H__ */
diff --git a/contiki/ppp/ahdlc.c b/contiki/ppp/ahdlc.c
new file mode 100644
index 0000000..a3485cd
--- /dev/null
+++ b/contiki/ppp/ahdlc.c
@@ -0,0 +1,371 @@
+/*																www.mycal.com			
+ *---------------------------------------------------------------------------
+ * ahdlc.c - Ahdlc receive and transmit processor for PPP engine.
+ *
+ *---------------------------------------------------------------------------
+ * Version  
+ *		0.1 Original Version Jan 11, 1998
+ *
+ *--------------------------------------------------------------------------- 
+ *  
+ * Copyright (C) 1998, Mycal Labs www.mycal.com	
+ *  
+ *---------------------------------------------------------------------------
+ */
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: ahdlc.c,v 1.3 2005/01/26 23:36:22 oliverschmidt Exp $
+ *
+ */
+
+/*			*/ 
+/* include files 	*/
+/*			*/ 
+ 
+#include "uip.h"
+#include "ppp.h"
+
+#if 0
+#define DEBUG1(x)
+#else
+#include <stdio.h>
+#define DEBUG1(x) debug_printf x
+#endif
+
+#define	PACKET_TX_DEBUG	1
+
+/*---------------------------------------------------------------------------
+ * ahdlc flags bit defins, for ahdlc_flags variable
+ ---------------------------------------------------------------------------*/
+/* Escaped mode bit */
+#define AHDLC_ESCAPED		0x1
+/* Frame is ready bit */
+#define	AHDLC_RX_READY		0x2				
+#define	AHDLC_RX_ASYNC_MAP	0x4
+#define AHDLC_TX_ASYNC_MAP	0x8
+#define AHDLC_PFC		0x10
+#define AHDLC_ACFC		0x20
+
+/*---------------------------------------------------------------------------
+ * Private Local Globals
+ *	10 bytes	- standard
+ *			- with counters
+ ---------------------------------------------------------------------------*/
+/* running tx CRC */
+u16_t ahdlc_tx_crc;
+/* running rx CRC */
+u16_t ahdlc_rx_crc;
+/* number of rx bytes processed, cur frame */
+u16_t ahdlc_rx_count;
+/* ahdlc state flags, see above */
+u8_t ahdlc_flags;
+
+/*
+ * The following can be optimized out
+ */
+u8_t *ahdlc_rx_buffer;			/* What to do here? +++ */
+u16_t ahdlc_max_rx_buffer_size;
+
+/*
+ * Optional statistics counters.
+ */
+#ifdef AHDLC_COUNTERS
+u8_t ahdlc_rx_tobig_error;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Simple and fast CRC16 routine for embedded processors.
+ *	Just slightly slower than the table lookup method but consumes
+ *	almost no space.  Much faster and smaller than the loop and
+ *	shift method that is widely used in the embedded space. 
+ *	Can be optimized even more in .ASM
+ *
+ *	data = (crcvalue ^ inputchar) & 0xff;
+ *	data = (data ^ (data << 4)) & 0xff;
+ *	crc = (crc >> 8) ^ ((data << 8) ^ (data <<3) ^ (data >> 4))
+ */
+/*---------------------------------------------------------------------------*/
+static u16_t
+crcadd(u16_t crcvalue, u8_t c)
+{
+  u16_t b;
+
+  b = (crcvalue ^ c) & 0xFF;
+  b = (b ^ (b << 4) & 0xFF);
+  b = (b << 8) ^ (b << 3) ^ (b >> 4);
+  
+  return ((crcvalue >> 8) ^ b);
+}
+/*---------------------------------------------------------------------------*/
+/* ahdlc_init(buffer, buffersize) - this initializes the ahdlc engine to
+ *	allow for rx frames.
+ */
+/*---------------------------------------------------------------------------*/
+void
+ahdlc_init(u8_t *buffer, u16_t maxrxbuffersize)
+{
+  ahdlc_flags = 0;
+  ahdlc_rx_buffer = buffer;
+  ahdlc_max_rx_buffer_size = maxrxbuffersize;
+  /* ahdlc_async_map = 0; */
+#ifdef AHDLC_COUNTERS
+  ahdlc_rx_tobig_error = 0;
+#endif
+}
+/*---------------------------------------------------------------------------*/
+/* ahdlc_rx_ready() - resets the ahdlc engine to the beginning of frame 
+ *	state.
+ */
+/*---------------------------------------------------------------------------*/
+void
+ahdlc_rx_ready(void)
+{
+  ahdlc_rx_count = 0;
+  ahdlc_rx_crc = 0xffff;
+  ahdlc_flags |= AHDLC_RX_READY;
+}
+/*---------------------------------------------------------------------------*/
+/* ahdlc receive function - This routine processes incoming bytes and tries
+ *	to build a PPP frame.
+ *
+ *	Two possible reasons that ahdlc_rx will not process characters:
+ *		o Buffer is locked - in this case ahdlc_rx returns 1, char
+ *			sending routing should retry.
+ */
+/*---------------------------------------------------------------------------*/
+u8_t
+ahdlc_rx(u8_t c)   
+{    
+  static u16_t protocol;
+  
+  /* check to see if PPP packet is useable, we should have hardware
+     flow control set, but if host ignores it and sends us a char when
+     the PPP Receive packet is in use, discard the character. +++ */
+  
+  if(ahdlc_flags & AHDLC_RX_READY) {
+    /* check to see if character is less than 0x20 hex we really
+       should set AHDLC_RX_ASYNC_MAP on by default and only turn it
+       off when it is negotiated off to handle some buggy stacks. */
+    if((c < 0x20) &&
+       ((ahdlc_flags & AHDLC_RX_ASYNC_MAP) == 0)) {
+      /* discard character */
+      DEBUG1(("Discard because char is < 0x20 hex and asysnc map is 0\n"));
+      return 0;
+    }
+    /* are we in escaped mode? */
+    if(ahdlc_flags & AHDLC_ESCAPED) {
+      /* set escaped to FALSE */
+      ahdlc_flags &= ~AHDLC_ESCAPED;	
+      
+      /* if value is 0x7e then silently discard and reset receive packet */
+      if(c == 0x7e) {
+	ahdlc_rx_ready();
+	return 0;
+      }
+      /* incomming char = itself xor 20 */
+      c = c ^ 0x20;	
+    } else if(c == 0x7e) {
+      /* handle frame end */
+      if(ahdlc_rx_crc == CRC_GOOD_VALUE) {
+	DEBUG1(("\nReceiving packet with good crc value, len %d\n",ahdlc_rx_count));
+	/* we hae a good packet, turn off CTS until we are done with
+	   this packet */
+	/*CTS_OFF();*/
+	/* remove CRC bytes from packet */
+	ahdlc_rx_count -= 2;		
+	
+	/* lock PPP buffer */
+	ahdlc_flags &= ~AHDLC_RX_READY;
+	/*
+	 * upcall routine must fully process frame before return
+	 *	as returning signifies that buffer belongs to AHDLC again.
+	 */
+	if((c & 0x1) && (ahdlc_flags & PPP_PFC)) {
+	  /* Send up packet */
+	  ppp_upcall((u16_t)ahdlc_rx_buffer[0],
+		     (u8_t *)&ahdlc_rx_buffer[1],
+		     (u16_t)(ahdlc_rx_count - 1));
+	} else {
+	  /* Send up packet */
+	  ppp_upcall((u16_t)(ahdlc_rx_buffer[0] << 8 | ahdlc_rx_buffer[1]), 
+		     (u8_t *)&ahdlc_rx_buffer[2], (u16_t)(ahdlc_rx_count - 2));
+	}
+	ahdlc_rx_ready();
+	return 0;
+      } else if(ahdlc_rx_count > 3) {	
+	DEBUG1(("\nReceiving packet with bad crc value, was 0x%04x len %d\n",ahdlc_rx_crc, ahdlc_rx_count));
+#ifdef AHDLC_COUNTERS
+	++ahdlc_crc_error;
+#endif
+	/* Shouldn't we dump the packet and not pass it up? */
+	/*ppp_upcall((u16_t)ahdlc_rx_buffer[0],
+	  (u8_t *)&ahdlc_rx_buffer[0], (u16_t)(ahdlc_rx_count+2));
+	  dump_ppp_packet(&ahdlc_rx_buffer[0],ahdlc_rx_count);*/
+	
+      }
+      ahdlc_rx_ready();	
+      return 0;
+    } else if(c == 0x7d) {
+      /* handle escaped chars*/
+      ahdlc_flags |= PPP_ESCAPED;
+      return 0;
+    }
+    
+    /* try to store char if not to big */
+    if(ahdlc_rx_count >= ahdlc_max_rx_buffer_size /*PPP_RX_BUFFER_SIZE*/) { 
+#ifdef AHDLC_COUNTERS			
+      ++ahdlc_rx_tobig_error;
+#endif
+      ahdlc_rx_ready();
+    } else {
+      /* Add CRC in */
+      ahdlc_rx_crc = crcadd(ahdlc_rx_crc, c);
+      /* do auto ACFC, if packet len is zero discard 0xff and 0x03 */
+      if(ahdlc_rx_count == 0) {
+	if((c == 0xff) || (c == 0x03))
+	  return 0;
+      }
+      /* Store char */
+      ppp_rx_buffer[ahdlc_rx_count++] = c;
+    }		
+  } else {
+    /* we are busy and didn't process the character. */
+    DEBUG1(("Busy/not active\n"));
+    return 1;
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+/* ahdlc_tx_char(char) - write a character to the serial device, 
+ * escape if necessary.
+ *
+ * Relies on local global vars	:	ahdlc_tx_crc, ahdlc_flags.
+ * Modifies local global vars	:	ahdlc_tx_crc.
+ */
+/*---------------------------------------------------------------------------*/
+void
+ahdlc_tx_char(u16_t protocol, u8_t c)
+{
+  /* add in crc */
+  ahdlc_tx_crc = crcadd(ahdlc_tx_crc, c);
+  /*
+   * See if we need to escape char, we always escape 0x7d and 0x7e, in the case
+   * of char < 0x20 we only support async map of default or none, so escape if
+   * ASYNC map is not set.  We may want to modify this to support a bitmap set
+   * ASYNC map.
+   */
+  if((c == 0x7d) || (c == 0x7e) || 
+     ((c < 0x20) && ((protocol == LCP) ||
+		     (ahdlc_flags & PPP_TX_ASYNC_MAP) == 0))) {
+    /* send escape char and xor byte by 0x20 */
+    ppp_arch_putchar(0x7d);
+    c ^= 0x20;
+  }
+  ppp_arch_putchar(c);
+}
+/*---------------------------------------------------------------------------*/
+/* ahdlc_tx(protocol,buffer,len) - Transmit a PPP frame.
+ *	Buffer contains protocol data, ahdlc_tx addes address, control and
+ *	protocol data.
+ *
+ * Relies on local global vars	:	ahdlc_tx_crc, ahdlc_flags.
+ * Modifies local global vars	:	ahdlc_tx_crc.
+ */
+/*---------------------------------------------------------------------------*/
+u8_t
+ahdlc_tx(u16_t protocol, u8_t *header, u8_t *buffer,
+	 u16_t headerlen, u16_t datalen)
+{
+  u16_t i;
+  u8_t c;
+
+  DEBUG1(("\nAHDLC_TX - transmit frame, protocol 0x%04x, length %d\n",protocol,datalen+headerlen));
+  
+#if PACKET_TX_DEBUG
+  DEBUG1(("\n"));
+  for(i = 0; i < headerlen; ++i) {
+    DEBUG1(("0x%02x ", header[i]));
+  }
+  for(i = 0; i < datalen; ++i) {
+    DEBUG1(("0x%02x ", buffer[i]));
+  }
+  DEBUG1(("\n\n"));
+#endif
+
+  /* Check to see that physical layer is up, we can assume is some
+     cases */
+  
+  /* write leading 0x7e */
+  ppp_arch_putchar(0x7e);
+
+  /* set initial CRC value */
+  ahdlc_tx_crc = 0xffff;
+  /* send HDLC control and address if not disabled or of LCP frame type */
+  /*if((0==(ahdlc_flags & PPP_ACFC)) || ((0xc0==buffer[0]) && (0x21==buffer[1]))) */
+  if((0 == (ahdlc_flags & PPP_ACFC)) || (protocol == LCP)) {
+    ahdlc_tx_char(protocol, 0xff);
+    ahdlc_tx_char(protocol, 0x03);
+  }
+  
+  /* Write Protocol */
+  ahdlc_tx_char(protocol,(u8_t)(protocol >> 8));
+  ahdlc_tx_char(protocol,(u8_t)(protocol & 0xff));
+
+  /* write header if it exists */
+  for(i = 0; i < headerlen; ++i) {
+    /* Get next byte from buffer */
+    c = header[i];
+    /* Write it...*/
+    ahdlc_tx_char(protocol, c);
+  }
+
+  /* Write frame bytes */
+  for(i = 0; i < datalen; ++i) {    
+    /* Get next byte from buffer */
+    c = buffer[i];
+    /* Write it...*/
+    ahdlc_tx_char(protocol, c);
+  }
+	
+  /* send crc, lsb then msb */
+  i = ahdlc_tx_crc ^ 0xffff;
+  ahdlc_tx_char(protocol, (u8_t)(i & 0xff));
+  ahdlc_tx_char(protocol, (u8_t)((i >> 8) & 0xff));
+
+  /* write trailing 0x7e, probably not needed but it doesn't hurt*/
+  ppp_arch_putchar(0x7e);
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/ppp/ahdlc.h b/contiki/ppp/ahdlc.h
new file mode 100644
index 0000000..16392d5
--- /dev/null
+++ b/contiki/ppp/ahdlc.h
@@ -0,0 +1,57 @@
+#ifndef __AHDLC_H__
+#define __AHDLC_H__
+
+/*---------------------------------------------------------------------------
+ ahdlc.h - ahdlc header file  					  
+---------------------------------------------------------------------------
+ Version    
+		0.1 Original Version Jan 11, 1998				
+ (c)1998 Mycal Labs, All Rights Reserved
+ ---------------------------------------------------------------------------*/
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: ahdlc.h,v 1.2 2004/08/22 12:37:00 oliverschmidt Exp $
+ *
+ */
+
+#include "uip.h"
+
+void ahdlc_init(u8_t *, u16_t);
+void ahdlc_rx_ready(void);
+u8_t ahdlc_rx(u8_t);  
+u8_t ahdlc_tx(u16_t protocol, u8_t *header, u8_t *buffer,
+	      u16_t headerlen, u16_t datalen);
+
+#endif /* __AHDLC_H__ */
diff --git a/contiki/ppp/ipcp.c b/contiki/ppp/ipcp.c
new file mode 100644
index 0000000..2a2f812
--- /dev/null
+++ b/contiki/ppp/ipcp.c
@@ -0,0 +1,448 @@
+/*															
+ *---------------------------------------------------------------------------
+ * ipcp.c - PPP IPCP (intrnet protocol) Processor/Handler
+ *
+ *---------------------------------------------------------------------------
+ *
+ * Version 
+ *		0.1 Original Version Jun 3, 2000
+ *	
+ *---------------------------------------------------------------------------
+ *        
+ * Copyright (C) 2000, Mycal Labs www.mycal.com
+ * 
+ *---------------------------------------------------------------------------
+ */
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: ipcp.c,v 1.3 2005/01/26 23:36:22 oliverschmidt Exp $
+ *
+ */
+
+/*			*/ 
+/* include files 	*/
+/*			*/ 
+
+#if 0
+#define DEBUG1(x)
+#else
+#include <stdio.h>
+#define DEBUG1(x) debug_printf x
+#endif
+
+#include "uip.h"
+/*#include "time.h"*/
+#include "ipcp.h"
+#include "ppp.h"
+#include "ahdlc.h"
+
+#define TIMER_expire()
+#define TIMER_set()
+#define TIMER_timeout(x) 1
+
+#ifdef IPCP_GET_PEER_IP
+uip_ipaddr_t	peer_ip_addr;
+#endif
+
+#ifdef IPCP_GET_PRI_DNS
+uip_ipaddr_t	pri_dns_addr;
+#endif
+
+#ifdef IPCP_GET_SEC_DNS
+uip_ipaddr_t	sec_dns_addr;
+#endif
+
+/*
+ * Local IPCP state
+ */
+u8_t ipcp_state;
+
+/*
+ * in the future add copression protocol and name servers (possibly for servers only)
+ */
+u8_t ipcplist[] = {0x3, 0};	
+
+/*---------------------------------------------------------------------------*/
+/*void
+printip(uip_ipaddr_t ip)
+{
+DEBUG1((" %d.%d.%d.%d ",ip.ipb1,ip.ip8[1],ip.ip8[2],ip.ip8[3]));
+    }*/
+#define printip(x)
+/*---------------------------------------------------------------------------*/
+void
+ipcp_init(void)
+{
+  DEBUG1(("ipcp init\n"));
+  ipcp_state = 0;
+  ppp_retry = 0;
+  our_ipaddr.ip16[0] = our_ipaddr.ip16[1] = 0;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * IPCP RX protocol Handler
+ */
+void
+ipcp_rx(u8_t *buffer, u16_t count)
+{
+  u8_t *bptr = buffer;
+  IPCPPKT *pkt=(IPCPPKT *)buffer;
+  u16_t len;
+
+  DEBUG1(("IPCP len %d\n",count));
+	
+  switch(*bptr++) {
+  case CONF_REQ:
+    /* parce request and see if we can ACK it */
+    ++bptr;
+    len = (*bptr++ << 8);
+    len |= *bptr++;
+    /* len-=2; */
+
+    DEBUG1(("check lcplist\n"));
+    if(scan_packet(IPCP, ipcplist, buffer, bptr, (u16_t)(len - 4))) {
+      DEBUG1(("option was bad\n"));
+    } else {
+      DEBUG1(("IPCP options are good\n"));
+      /*
+       * Parse out the results
+       */
+      /* lets try to implement what peer wants */
+      /* Reject any protocol not */
+      /* Error? if we we need to send a config Reject ++++ this is
+	 good for a subroutine*/
+      /* All we should get is the peer IP address */
+      if(IPCP_IPADDRESS == *bptr++) {
+	/* dump length */
+	++bptr;
+#ifdef IPCP_GET_PEER_IP
+	peer_ip_addr.ip8[0] = *bptr++;
+	peer_ip_addr.ip8[1] = *bptr++;
+	peer_ip_addr.ip8[2] = *bptr++;
+	peer_ip_addr.ip8[3] = *bptr++;
+	DEBUG1(("Peer IP "));
+	/*	printip(peer_ip_addr);*/
+	DEBUG1(("\n"));
+#else
+	bptr += 4;
+#endif
+      } else {
+	DEBUG1(("HMMMM this shouldn't happen IPCP1\n"));
+      }
+      
+#if 0			
+      if(error) {
+	/* write the config NAK packet we've built above, take on the header */
+	bptr = buffer;
+	*bptr++ = CONF_NAK;		/* Write Conf_rej */
+	*bptr++;
+	/*tptr++;*/  /* skip over ID */
+
+	/* Write new length */
+	*bptr++ = 0;
+	*bptr = tptr - buffer;
+	
+	/* write the reject frame */
+	DEBUG1(("Writing NAK frame \n"));
+	ahdlc_tx(IPCP, buffer, (u16_t)(tptr - buffer));
+	DEBUG1(("- End NAK Write frame\n"));
+	
+      } else {
+      }
+#endif
+      /*
+       * If we get here then we are OK, lets send an ACK and tell the rest
+       * of our modules our negotiated config.
+       */
+      ipcp_state |= IPCP_RX_UP;
+      DEBUG1(("Send IPCP ACK!\n"));
+      bptr = buffer;
+      *bptr++ = CONF_ACK;		/* Write Conf_ACK */
+      bptr++;				/* Skip ID (send same one) */
+      /*
+       * Set stuff
+       */
+      /* ppp_flags |= tflag; */
+      DEBUG1(("SET- stuff -- are we up? c=%d dif=%d \n", count, (u16_t)(bptr-buffer)));
+	
+      /* write the ACK frame */
+      DEBUG1(("Writing ACK frame \n"));
+      /* Send packet ahdlc_txz(procol,header,data,headerlen,datalen);	*/
+      ahdlc_tx(IPCP, 0, buffer, 0, count /*bptr-buffer*/);
+      DEBUG1(("- End ACK Write frame\n"));
+	
+      /* expire the timer to make things happen after a state change */
+      /*timer_expire(); */
+	
+      /*			} */
+    }
+    break;
+  case CONF_ACK:			/* config Ack */
+    DEBUG1(("CONF ACK\n"));
+    /*
+     * Parse out the results
+     *
+     * Dump the ID and get the length.
+     */
+    /* dump the ID */
+    bptr++;
+
+    /* get the length */
+    len = (*bptr++ << 8);
+    len |= *bptr++;
+#if 0
+    /* Parse ACK and set data */
+    while(bptr < buffer + len) {
+      switch(*bptr++) {
+      case IPCP_IPADDRESS:
+	/* dump length */
+	bptr++;		
+	ipaddr.ip8[0] = *bptr++;
+	ipaddr.ip8[1] = *bptr++;
+	ipaddr.ip8[2] = *bptr++;
+	ipaddr.ip8[3] = *bptr++;
+	break;
+      case IPCP_PRIMARY_DNS:
+	bptr++;
+	pri_dns_addr.ip8[0] = *bptr++;
+	pri_dns_addr.ip8[1] = *bptr++;
+	pri_dns_addr.ip8[2] = *bptr++;
+	pri_dns_addr.ip8[3] = *bptr++;
+	break;
+      case IPCP_SECONDARY_DNS:
+	bptr++;
+	sec_dns_addr.ip8[0] = *bptr++;
+	sec_dns_addr.ip8[1] = *bptr++;
+	sec_dns_addr.ip8[2] = *bptr++;
+	sec_dns_addr.ip8[3] = *bptr++;
+	break;
+      default:
+	DEBUG1(("IPCP CONFIG_ACK problem1\n"));
+      }
+    }
+#endif
+    ipcp_state |= IPCP_TX_UP;
+    /*ipcp_state &= ~IPCP_RX_UP;*/
+    DEBUG1(("were up! \n"));
+    printip(our_ipaddr);
+#ifdef IPCP_GET_PRI_DNS
+    printip(pri_dns_addr);
+#endif
+#ifdef IPCP_GET_SEC_DNS
+    printip(sec_dns_addr);
+#endif
+    DEBUG1(("\n"));
+		
+    /* expire the timer to make things happen after a state change */
+    TIMER_expire();
+    break;
+  case CONF_NAK:			/* Config Nack */
+    DEBUG1(("CONF NAK\n"));
+    /* dump the ID */
+    bptr++;
+    /* get the length */
+    len = (*bptr++ << 8);
+    len |= *bptr++;
+
+    /* Parse ACK and set data */
+    while(bptr < buffer + len) {
+      switch(*bptr++) {
+      case IPCP_IPADDRESS:
+	/* dump length */
+	bptr++;
+	our_ipaddr.ip8[0] = *bptr++;
+	our_ipaddr.ip8[1] = *bptr++;
+	our_ipaddr.ip8[2] = *bptr++;
+	our_ipaddr.ip8[3] = *bptr++;
+	break;
+#ifdef IPCP_GET_PRI_DNS
+      case IPCP_PRIMARY_DNS:
+	bptr++;
+	pri_dns_addr.ip8[0] = *bptr++;
+	pri_dns_addr.ip8[1] = *bptr++;
+	pri_dns_addr.ip8[2] = *bptr++;
+	pri_dns_addr.ip8[3] = *bptr++;
+	break;
+#endif
+#ifdef IPCP_GET_SEC_DNS
+      case IPCP_SECONDARY_DNS:
+	bptr++;
+	sec_dns_addr.ip8[0] = *bptr++;
+	sec_dns_addr.ip8[1] = *bptr++;
+	sec_dns_addr.ip8[2] = *bptr++;
+	sec_dns_addr.ip8[3] = *bptr++;
+	break;
+#endif
+      default:
+	DEBUG1(("IPCP CONFIG_ACK problem 2\n"));
+      }
+    }
+    ppp_id++;
+    printip(our_ipaddr);
+#ifdef IPCP_GET_PRI_DNS
+    printip(pri_dns_addr);
+#endif
+#ifdef IPCP_GET_PRI_DNS
+    printip(sec_dns_addr);
+#endif
+    DEBUG1(("\n"));
+    /* expire the timer to make things happen after a state change */
+    TIMER_expire();
+    break;
+  case CONF_REJ:			/* Config Reject */
+    DEBUG1(("CONF REJ\n"));
+    /* Remove the offending options*/
+    ppp_id++;
+    /* dump the ID */
+    bptr++;
+    /* get the length */
+    len = (*bptr++ << 8);
+    len |= *bptr++;
+
+    /* Parse ACK and set data */
+    while(bptr < buffer + len) {
+      switch(*bptr++) {
+      case IPCP_IPADDRESS:
+	ipcp_state |= IPCP_IP_BIT;
+	bptr += 5;
+	break;
+#ifdef IPCP_GET_PRI_DNS
+      case IPCP_PRIMARY_DNS:
+	ipcp_state |= IPCP_PRI_DNS_BIT;
+	bptr += 5;
+	break;
+#endif
+#ifdef IPCP_GET_PRI_DNS
+      case IPCP_SECONDARY_DNS:
+	ipcp_state |= IPCP_SEC_DNS_BIT;
+	bptr += 5;
+	break;
+#endif
+      default:
+	DEBUG1(("IPCP this shoudln't happen 3\n"));
+      }
+    }
+    /* expire the timer to make things happen after a state change */
+    /*timer_expire(); */
+    break;
+  default:
+    DEBUG1(("-Unknown 4\n"));
+  }
+}
+  
+/*---------------------------------------------------------------------------*/
+void
+ipcp_task(u8_t *buffer)
+{
+  u8_t *bptr;
+  u16_t	t;
+  IPCPPKT *pkt;
+
+  /* IPCP tx not up and hasn't timed out then lets see if we need to
+     send a request */
+  if(!(ipcp_state & IPCP_TX_UP) && !(ipcp_state & IPCP_TX_TIMEOUT)) {
+    /* Check if we have a request pending */
+    /*t=get_seconds()-ipcp_tx_time;*/
+    if(TIMER_timeout(IPCP_TIMEOUT)) {
+      /*
+       * No pending request, lets build one
+       */
+      pkt=(IPCPPKT *)buffer;		
+      
+      /* Configure-Request only here, write id */
+      pkt->code = CONF_REQ;
+      pkt->id = ppp_id;
+			
+      bptr = pkt->data;       
+
+      /*
+       * Write options, we want IP address, and DNS addresses if set.
+       */
+			
+      /* Write zeros for IP address the first time */
+      *bptr++ = IPCP_IPADDRESS;
+      *bptr++ = 0x6;
+      *bptr++ = our_ipaddr.ip8[0];
+      *bptr++ = our_ipaddr.ip8[1];
+      *bptr++ = our_ipaddr.ip8[2];
+      *bptr++ = our_ipaddr.ip8[3];
+
+#ifdef IPCP_GET_PRI_DNS
+      if(!(ipcp_state & IPCP_PRI_DNS_BIT)) {
+	/* Write zeros for IP address the first time */
+	*bptr++ = IPCP_PRIMARY_DNS;
+	*bptr++ = 0x6;
+	*bptr++ = pri_dns_addr.ip8[0];
+	*bptr++ = pri_dns_addr.ip8[1];
+	*bptr++ = pri_dns_addr.ip8[2];
+	*bptr++ = pri_dns_addr.ip8[3];
+      }
+#endif
+#ifdef IPCP_GET_SEC_DNS
+      if(!(ipcp_state & IPCP_SEC_DNS_BIT)) {
+	/* Write zeros for IP address the first time */
+	*bptr++ = IPCP_SECONDARY_DNS;
+	*bptr++ = 0x6;
+	*bptr++ = sec_dns_addr.ip8[0];
+	*bptr++ = sec_dns_addr.ip8[1];
+	*bptr++ = sec_dns_addr.ip8[2];
+	*bptr++ = sec_dns_addr.ip8[3];
+      }
+#endif
+      /* Write length */
+      t = bptr - buffer;
+      /* length here -  code and ID + */
+      pkt->len = htons(t);	
+      
+      DEBUG1(("\n**Sending IPCP Request packet\n"));
+      
+      /* Send packet ahdlc_txz(procol,header,data,headerlen,datalen); */
+      ahdlc_tx(IPCP, 0, buffer, 0, t);
+
+      /* Set timer */
+      /*ipcp_tx_time=get_seconds();*/
+      TIMER_set();
+      /* Inc retry */
+      /*ipcp_retry++;*/
+      ppp_retry++;
+      /*
+       * Have we timed out? (combide the timers?)
+       */
+      if(ppp_retry > IPCP_RETRY_COUNT)
+	ipcp_state &= IPCP_TX_TIMEOUT;	
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/ 
diff --git a/contiki/ppp/ipcp.h b/contiki/ppp/ipcp.h
new file mode 100644
index 0000000..fef006d
--- /dev/null
+++ b/contiki/ppp/ipcp.h
@@ -0,0 +1,95 @@
+#ifndef __IPCP_H__
+#define __IPCP_H__
+/*  www.mycal.com
+    ---------------------------------------------------------------------------
+    IPCP.h - Internet Protocol Control Protocol header file 
+    ---------------------------------------------------------------------------
+    Version 
+    0.1 Original Version June 3, 2000
+    (c)2000 Mycal Labs, All Rights Reserved
+    ---------------------------------------------------------------------------
+*/
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: ipcp.h,v 1.2 2004/08/22 12:37:00 oliverschmidt Exp $
+ *
+ */
+#include "uip.h"
+#include "ppp-conf.h"
+
+/* Config options (move to pppconfig)
+   #define  IPCP_RETRY_COUNT	5
+   #define  IPCP_TIMEOUT	5
+*/
+
+/* IPCP Option Types */
+#define IPCP_IPADDRESS		0x03
+#define IPCP_PRIMARY_DNS	0x81
+#define IPCP_SECONDARY_DNS	0x83
+
+/* IPCP state machine flags */
+#define	IPCP_TX_UP		0x01
+#define IPCP_RX_UP		0x02
+#define IPCP_IP_BIT		0x04
+#define IPCP_TX_TIMEOUT		0x08
+#define IPCP_PRI_DNS_BIT	0x08
+#define IPCP_SEC_DNS_BIT	0x10
+
+typedef struct  _ipcp
+{
+  u8_t code;
+  u8_t id;
+  u16_t len;
+  u8_t data[0];	
+} IPCPPKT;
+
+/*
+ * Export IP addresses.
+ */
+#if 0	/* moved to mip.c */
+extern	IPAddr our_ipaddr;
+extern	IPAddr peer_ip_addr;
+extern	IPAddr pri_dns_addr;
+extern	IPAddr sec_dns_addr;
+#endif
+
+extern	u8_t ipcp_state;
+
+void ipcp_init(void);
+void ipcp_task(u8_t *buffer);
+void ipcp_rx(u8_t *, u16_t);
+
+#endif /* __IPCP_H__ */
+
diff --git a/contiki/ppp/lcp.c b/contiki/ppp/lcp.c
new file mode 100644
index 0000000..8ae98ab
--- /dev/null
+++ b/contiki/ppp/lcp.c
@@ -0,0 +1,413 @@
+/*  www.mycal.com
+ *---------------------------------------------------------------------------
+ *lcp.c - Link Configuration Protocol Handler.  - -
+ *---------------------------------------------------------------------------
+ *Version - 0.1 Original Version June 3, 2000 -
+ *
+ *---------------------------------------------------------------------------
+ *- Copyright (C) 2000, Mycal Labs www.mycal.com - -
+ *---------------------------------------------------------------------------
+ *
+ *
+*/
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: lcp.c,v 1.3 2005/01/26 23:36:22 oliverschmidt Exp $
+ *
+ */
+
+/*			*/ 
+/* include files 	*/
+/*			*/ 
+
+#include "ppp-conf.h"
+
+/*#include "time.h"*/
+#include "ppp.h"
+#include "ahdlc.h"
+#include "lcp.h"
+
+#if 0
+#define DEBUG1(x)
+#define DEBUG2(x)
+#else
+#include <stdio.h>
+#define DEBUG1(x) debug_printf x
+#define DEBUG2(x) debug_printf x
+#endif
+
+#define TIMER_expire()
+#define TIMER_set()
+#define TIMER_timeout(x) 1
+
+/*u8_t				tflag;
+u8_t				*lcp_buffer;
+u16_t				lcp_tx_time;
+u8_t				lcp_retry;
+u16_t				lcp_timeout=5;*/
+
+u8_t lcp_state;
+u16_t ppp_tx_mru = 0;
+
+/* We need this when we neg our direction.
+   u8_t				lcp_tx_options; */
+
+/*
+ * Define the supported paramets for this module here.
+ */
+u8_t lcplist[] = {
+  LPC_MAGICNUMBER,
+  LPC_PFC,
+  LPC_ACFC,
+  LPC_AUTH,
+  LPC_ACCM,
+  LPC_MRU,
+  0};	
+
+/*---------------------------------------------------------------------------*/
+/* lcp_init() - Initialize the LCP engine to startup values */
+/*---------------------------------------------------------------------------*/
+void
+lcp_init(void)
+{
+  lcp_state = 0;
+  ppp_retry = 0;
+  TIMER_expire();
+}
+/*---------------------------------------------------------------------------*/
+/* lcp_rx() - Receive an LCP packet and process it.  
+ *	This routine receives a LCP packet in buffer of length count.
+ *	Process it here, support for CONF_REQ, CONF_ACK, CONF_NACK, CONF_REJ or
+ *	TERM_REQ.
+ */
+/*---------------------------------------------------------------------------*/
+void
+lcp_rx(u8_t *buffer, u16_t count)
+{
+  u8_t *bptr = buffer, *tptr;
+  u8_t error = 0;
+  u8_t id;
+  u16_t len, j;
+
+  switch(*bptr++) {
+  case CONF_REQ:			/* config request */
+    /* parce request and see if we can ACK it */
+    id = *bptr++;
+    len = (*bptr++ << 8);
+    len |= *bptr++;
+    /*len -= 2;*/
+    DEBUG1(("received [LCP Config Request id %u\n",id));
+    if(scan_packet((u16_t)LCP, lcplist, buffer, bptr, (u16_t)(len-4))) {
+      /* must do the -4 here, !scan packet */
+      
+      DEBUG1((" options were rejected\n"));
+    } else {
+      /* lets try to implement what peer wants */
+      tptr = bptr = buffer;
+      bptr += 4;			/* skip code, id, len */
+      error = 0;
+      /* first scan for unknown values */
+      while(bptr < buffer+len) {
+	switch(*bptr++) {
+	case LPC_MRU:	/* mru */
+	  j = *bptr++;
+	  j -= 2;
+	  if(j == 2) {
+	    ppp_tx_mru = ((*bptr++<<8) || (*bptr++));
+	    DEBUG1(("<mru %d> ",ppp_tx_mru));
+	  } else {
+	    DEBUG1(("<mru ??> "));
+	  }
+	  break;
+	case LPC_ACCM:	/*		*/
+	  bptr++;		/* skip length */	
+	  j = *bptr++;
+	  j += *bptr++;
+	  j += *bptr++;
+	  j += *bptr++;
+	  if((j==0) || (j==0x3fc)) {
+	    // ok
+	    DEBUG1(("<asyncmap 0x%04x>",j));
+	  } else {
+	    /*
+	     * fail we only support default or all zeros
+	     */
+	    DEBUG1(("We only support default or all zeros for ACCM "));
+	    error = 1;
+	    *tptr++ = LPC_ACCM;
+	    *tptr++ = 0x6;
+	    *tptr++ = 0;
+	    *tptr++ = 0;
+	    *tptr++ = 0;
+	    *tptr++ = 0;
+	  }
+	  break;
+	case LPC_AUTH:
+	  bptr++;
+	  if((*bptr++==0xc0) && (*bptr++==0x23)) {
+	    DEBUG1(("<auth pap> "));
+	    /* negotiate PAP */
+	    lcp_state |= LCP_RX_AUTH;	
+	  } else {
+	    /* we only support PAP */
+	    DEBUG1(("<auth ??>"));
+	    error = 1;
+	    *tptr++ = LPC_AUTH;
+	    *tptr++ = 0x4;
+	    *tptr++ = 0xc0;
+	    *tptr++ = 0x23;
+	  }
+	  break;
+	case LPC_MAGICNUMBER:
+	  DEBUG1(("<magic > "));
+	  /*
+	   * Compair incoming number to our number (not implemented)
+	   */
+	  bptr++;		/* for now just dump */
+	  bptr++;
+	  bptr++;
+	  bptr++;
+	  bptr++;
+	  break;
+	case LPC_PFC:
+	  bptr++;
+	  DEBUG1(("<pcomp> "));
+	  /*tflag|=PPP_PFC;*/
+	  break;
+	case LPC_ACFC:
+	  bptr++;
+	  DEBUG1(("<accomp> "));
+	  /*tflag|=PPP_ACFC;*/
+	  break;
+	  
+	}
+      }
+      /* Error? if we we need to send a config Reject ++++ this is good for a subroutine */
+      if(error) {
+	/* write the config NAK packet we've built above, take on the header */
+	bptr = buffer;
+	*bptr++ = CONF_NAK;		/* Write Conf_rej */
+	*bptr++;/*tptr++;*/		/* skip over ID */
+
+	/* Write new length */
+	*bptr++ = 0;
+	*bptr = tptr - buffer;
+
+	/* write the reject frame */
+	DEBUG1(("\nWriting NAK frame \n"));
+	// Send packet ahdlc_txz(procol,header,data,headerlen,datalen);				
+	ahdlc_tx(LCP, 0, buffer, 0, (u16_t)(tptr-buffer));
+	DEBUG1(("- end NAK Write frame\n"));
+	
+      } else {
+	/*
+	 * If we get here then we are OK, lets send an ACK and tell the rest
+	 * of our modules our negotiated config.
+	 */
+	DEBUG1(("\nSend ACK!\n"));
+	bptr = buffer;
+	*bptr++ = CONF_ACK;		/* Write Conf_ACK */
+	bptr++;				/* Skip ID (send same one) */
+	/*
+	 * Set stuff
+	 */
+	/*ppp_flags|=tflag;*/
+	/* DEBUG2("SET- stuff -- are we up? c=%d dif=%d \n", count, (u16_t)(bptr-buffer)); */
+	
+	/* write the ACK frame */
+	DEBUG2(("Writing ACK frame \n"));
+	/* Send packet ahdlc_txz(procol,header,data,headerlen,datalen);	*/
+	ahdlc_tx(LCP, 0, buffer, 0, count /*bptr-buffer*/);
+       DEBUG2(("- end ACK Write frame\n"));
+	
+	/* expire the timer to make things happen after a state change */
+	/*timer_expire();*/
+	
+      }
+    }
+    break;
+  case CONF_ACK:			/* config Ack   Anytime we do an ack reset the timer to force send. */
+    DEBUG1(("LCP-ACK - "));
+    /* check that ID matches one sent */
+    if(*bptr++ == ppp_id) {	
+      /* Change state to PPP up. */
+      DEBUG1((">>>>>>>> good ACK id up!\n",ppp_id));
+      /* copy negotiated values over */
+      
+      lcp_state |= LCP_TX_UP;		
+      
+      /* expire the timer to make things happen after a state change */
+      TIMER_expire();
+    }
+    else
+      DEBUG1(("*************++++++++++ bad id %d\n",ppp_id));
+    break;
+  case CONF_NAK:			/* Config Nack */
+    DEBUG1(("LCP-CONF NAK\n"));
+    ppp_id++;
+    break;
+  case CONF_REJ:			/* Config Reject */
+    DEBUG1(("LCP-CONF REJ\n"));
+    ppp_id++;
+    break;
+  case TERM_REQ:			/* Terminate Request */
+    DEBUG1(("LCP-TERM-REQ -"));
+    bptr = buffer;
+    *bptr++ = TERM_ACK;			/* Write TERM_ACK */
+    /* write the reject frame */
+    DEBUG1(("Writing TERM_ACK frame \n"));
+    /* Send packet ahdlc_txz(procol,header,data,headerlen,datalen); */
+    ahdlc_tx(LCP, 0, buffer, 0, count);
+    lcp_state &= ~LCP_TX_UP;	
+    lcp_state |= LCP_TERM_PEER;
+    break;
+  case TERM_ACK:
+    DEBUG1(("LCP-TERM ACK\n"));
+    break;
+  default:
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+/* lcp_task(buffer) - This routine see if a lcp request needs to be sent
+ *	out.  It uses the passed buffer to form the packet.  This formed LCP
+ *	request is what we negotiate for sending options on the link.
+ *
+ *	Currently we negotiate : Magic Number Only, but this will change.
+ */
+/*---------------------------------------------------------------------------*/
+void
+lcp_task(u8_t *buffer)
+{
+  u8_t *bptr;
+  u16_t t;
+  LCPPKT *pkt;
+
+  /* lcp tx not up and hasn't timed out then lets see if we need to send a request */
+  if(!(lcp_state & LCP_TX_UP) && !(lcp_state & LCP_TX_TIMEOUT)) {
+    /* Check if we have a request pending */
+    /*t=get_seconds()-lcp_tx_time;*/
+    if(1 == TIMER_timeout(LCP_TX_TIMEOUT)) {
+      DEBUG1(("\nSending LCP request packet - "));
+      /*
+       * No pending request, lets build one
+       */
+      pkt = (LCPPKT *)buffer;		
+
+      /* Configure-Request only here, write id */
+      pkt->code = CONF_REQ;
+      pkt->id = ppp_id;
+      
+      bptr = pkt->data;
+      
+      /* Write options */
+      
+      /* Write magic number */
+      DEBUG1(("LPC_MAGICNUMBER -"));
+      *bptr++ = LPC_MAGICNUMBER;
+      *bptr++ = 0x6;
+      *bptr++ = 0;
+      *bptr++ = 0;
+      *bptr++ = 0;
+      *bptr++ = 0;
+      
+      /* ACCM */
+#if 0
+      if((lcp_tx_options & LCP_OPT_ACCM) & 0) {
+	*bptr++ = LPC_ACCM;
+	*bptr++ = 0x6;
+	*bptr++ = 0;
+	*bptr++ = 0;
+	*bptr++ = 0;
+	*bptr++ = 0;
+      }
+      /*
+       * Authentication protocol
+       */
+      if((lcp_tx_options & LCP_OPT_AUTH) && 0) {
+	/*
+	 * If turned on, we only negotiate PAP
+	 */
+	*bptr++ = LPC_AUTH;
+	*bptr++ = 0x4;
+	*bptr++ = 0xc0;
+	*bptr++ = 0x23;
+      }
+      /*
+       * PFC
+       */
+      if((lcp_tx_options & LCP_OPT_PFC) && 0) {
+	/*
+	 * If turned on, we only negotiate PAP
+	 */
+	*bptr++ = LPC_PFC;
+	*bptr++ = 0x2;
+      }
+      /*
+       * ACFC
+       */
+      if((lcp_tx_options & LCP_OPT_ACFC) && 0) {
+	/*
+	 * If turned on, we only negotiate PAP
+	 */
+	*bptr++ = LPC_ACFC;
+	*bptr++ = 0x2;
+      }
+#endif
+      /* Write length */
+      t = bptr - buffer;
+      pkt->len = htons(t);			/* length here -  code and ID + */
+      
+      DEBUG1((" len %d\n",t));
+      
+      /* Send packet */
+      /* Send packet ahdlc_txz(procol,header,data,headerlen,datalen); */
+      ahdlc_tx(LCP, 0, buffer, 0, t);
+      
+      /* Set timer */
+      TIMER_set();
+      /*lcp_tx_time=get_seconds();*/
+      /* Inc retry */
+      ppp_retry++;
+      /*
+       * Have we timed out?
+       */
+      if(ppp_retry > LCP_RETRY_COUNT) {
+	lcp_state &= LCP_TX_TIMEOUT;
+      }
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/ppp/lcp.h b/contiki/ppp/lcp.h
new file mode 100644
index 0000000..911f1f3
--- /dev/null
+++ b/contiki/ppp/lcp.h
@@ -0,0 +1,95 @@
+#ifndef __LCP_H__
+#define __LCP_H__
+/* www.mycal.com
+   ---------------------------------------------------------------------------
+   LCP.h - LCP header file
+   ---------------------------------------------------------------------------
+   Version                                                                  -
+   0.1 Original Version June 3, 2000
+   (c)2000 Mycal Labs, All Rights Reserved
+   ---------------------------------------------------------------------------
+*/
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: lcp.h,v 1.2 2004/08/22 12:37:00 oliverschmidt Exp $
+ *
+ */
+
+#include "uip.h"
+#include "ppp-conf.h"
+
+/* LCP Option Types */
+#define LPC_VENDERX		0x0
+#define	LPC_MRU			0x1
+#define LPC_ACCM		0x2
+#define LPC_AUTH		0x3
+#define LPC_QUALITY		0x4
+#define LPC_MAGICNUMBER		0x5
+#define LPC_PFC			0x7
+#define LPC_ACFC		0x8
+
+/* LCP Negotiated options flag equates */
+#define LCP_OPT_ACCM		0x1
+#define LCP_OPT_AUTH		0x2
+#define LCP_OPT_PFC		0x4
+#define LCP_OPT_ACFC		0x4
+
+/* LCP state machine flags */
+#define	LCP_TX_UP		0x1
+#define LCP_RX_UP		0x2
+
+#define LCP_RX_AUTH		0x10
+/* LCP request for auth */
+#define LCP_TERM_PEER		0x20
+/* LCP Terminated by peer */
+#define LCP_RX_TIMEOUT		0x40
+#define LCP_TX_TIMEOUT		0x80
+
+typedef struct _lcppkt
+{
+  u8_t code;
+  u8_t id;
+  u16_t len;
+  u8_t data[0];	
+} LCPPKT;
+
+/* Exported Vars */
+extern	u8_t lcp_state;
+
+void	lcp_init(void);
+void	lcp_rx(u8_t *, u16_t);
+void	lcp_task(u8_t *buffer);
+
+#endif /* __LCP_H__ */
diff --git a/contiki/ppp/pap.c b/contiki/ppp/pap.c
new file mode 100644
index 0000000..9e55220
--- /dev/null
+++ b/contiki/ppp/pap.c
@@ -0,0 +1,186 @@
+/*www.mycal.net
+ *---------------------------------------------------------------------------
+ *pap.c - PAP processor for the PPP module - -
+ *---------------------------------------------------------------------------
+ *Version - 0.1 Original Version Jun 3, 2000 - -
+ *---------------------------------------------------------------------------
+ *- Copyright (C) 2000, Mycal Labs www.mycal.com - -
+ *---------------------------------------------------------------------------
+*/
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: pap.c,v 1.4 2005/01/26 23:36:22 oliverschmidt Exp $
+ *
+ */
+
+/*			*/ 
+/* include files 	*/
+/*			*/ 
+
+#include	<string.h>
+#include	"ppp.h"
+#include	"pap.h"
+#include	"lcp.h"
+
+#if 0
+#define DEBUG1(x)
+#else
+#include <stdio.h>
+#define DEBUG1(x) debug_printf x
+#endif
+
+/*#include	"time.h"*/
+/*#include	"utils.h" */
+#define TIMER_expire()
+#define TIMER_set()
+#define TIMER_timeout(x) 1
+
+
+u8_t pap_state;
+
+u8_t pap_username[PAP_USERNAME_SIZE];
+u8_t pap_password[PAP_PASSWORD_SIZE];
+
+/*u16_t			pap_tx_time;
+  u8_t			pap_timeout;*/
+
+/*---------------------------------------------------------------------------*/
+void
+pap_init(void)
+{
+  ppp_retry = 0;			/* We reuse ppp_retry */
+  pap_state = 0;
+}
+/*---------------------------------------------------------------------------*/
+/* pap_rx() - PAP RX protocol Handler */
+/*---------------------------------------------------------------------------*/
+void
+pap_rx(u8_t *buffer, u16_t count)
+{
+  u8_t *bptr=buffer;
+  u8_t len;
+
+  switch(*bptr++) {
+  case CONF_REQ:	
+    DEBUG1(("CONF ACK - only for server, no support\n"));
+    break;
+  case CONF_ACK:			/* config Ack */
+    DEBUG1(("CONF ACK - PAP good - "));
+    /* Display message if debug */
+    len = *bptr++;
+    *(bptr + len) = 0;
+    DEBUG1((" %s \n",bptr));
+    pap_state |= PAP_TX_UP;
+    /* expire the timer to make things happen after a state change */
+    TIMER_expire();
+    break;
+  case CONF_NAK:
+    DEBUG1(("CONF NAK - Failed Auth - "));
+    pap_state |= PAP_TX_AUTH_FAIL;
+    /* display message if debug */
+    len = *bptr++;
+    *(bptr + len)=0;
+    DEBUG1((" %s \n",bptr));
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+/* pap_task() - This task needs to be called every so often during the PAP
+ *	negotiation phase.  This task sends PAP REQ packets.
+ */
+/*---------------------------------------------------------------------------*/
+void
+pap_task(u8_t *buffer)	
+{
+  u8_t *bptr;
+  u16_t t;
+  PAPPKT *pkt;
+
+  /* If LCP is up and PAP negotiated, try to bring up PAP */
+  if(!(pap_state & PAP_TX_UP) && !(pap_state & PAP_TX_TIMEOUT)) {
+    /* Do we need to send a PAP auth packet?
+       Check if we have a request pending*/
+    if(1 == TIMER_timeout(PAP_TIMEOUT)) {
+      /* Check if we have a request pending */
+      /* t=get_seconds()-pap_tx_time;
+	 if(	t > pap_timeout)
+      {
+      */
+      /* We need to send a PAP authentication request */
+      DEBUG1(("\nSending PAP Request packet - "));
+
+      /* Build a PAP request packet */
+      pkt = (PAPPKT *)buffer;		
+      
+      /* Configure-Request only here, write id */
+      pkt->code = CONF_REQ;
+      pkt->id = ppp_id;
+      bptr = pkt->data;
+      
+      /* Write options */
+      t = strlen(pap_username);
+      /* Write peer length */
+      *bptr++ = (u8_t)t;	
+      bptr = memcpy(bptr, pap_username, t);
+
+      t = strlen(pap_password);
+      *bptr++ = (u8_t)t;
+      bptr = memcpy(bptr, pap_password, t);
+			
+      /* Write length */
+      t = bptr - buffer;
+      /* length here -  code and ID +  */
+      pkt->len = htons(t);	
+      
+      DEBUG1((" Len %d\n",t));
+      
+      /* Send packet */
+      ahdlc_tx(PAP, buffer, 0, t, 0);
+
+      /* Set timer */
+      TIMER_set();
+      
+      ppp_retry++;
+
+      /* Have we failed? */
+      if(ppp_retry > 3) {
+	DEBUG1(("PAP - timout\n"));
+	pap_state &= PAP_TX_TIMEOUT;
+	
+      }
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/ppp/pap.h b/contiki/ppp/pap.h
new file mode 100644
index 0000000..104a79c
--- /dev/null
+++ b/contiki/ppp/pap.h
@@ -0,0 +1,83 @@
+#ifndef __PAP_H__
+#define __PAP_H__
+/*
+  www.mycal.com
+  ---------------------------------------------------------------------------
+  pap.h - pap header file 
+  ---------------------------------------------------------------------------
+  Version 
+  0.1 Original Version June 3, 2000
+  (c)2000 Mycal Labs, All Rights Reserved
+  ---------------------------------------------------------------------------
+*/
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: pap.h,v 1.3 2004/08/22 21:10:02 oliverschmidt Exp $
+ *
+ */
+
+#include "uip.h"
+
+/* PAP state machine flags */
+/* client only */
+#define PAP_TX_UP		0x01
+/* server only */
+#define PAP_RX_UP		0x02
+
+#define PAP_RX_AUTH_FAIL	0x10
+#define PAP_TX_AUTH_FAIL	0x20
+#define PAP_RX_TIMEOUT		0x80
+#define PAP_TX_TIMEOUT		0x80
+
+typedef struct _pappkt {
+  u8_t code;
+  u8_t id;
+  u16_t len;
+  u8_t data[0];	
+} PAPPKT;
+
+/* Export pap_state */
+extern u8_t pap_state;
+
+extern u8_t pap_username[];
+extern u8_t pap_password[];
+
+/* Function prototypes */
+void	pap_init(void);
+void	pap_rx(u8_t *, u16_t);
+void	pap_task(u8_t *buffer);	
+
+#endif /* __PAP_H__ */
+
diff --git a/contiki/ppp/ppp-service.c b/contiki/ppp/ppp-service.c
new file mode 100644
index 0000000..842f1c4
--- /dev/null
+++ b/contiki/ppp/ppp-service.c
@@ -0,0 +1,57 @@
+
+#include "packet-service.h"
+#include "ppp.h"
+
+static void output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen);
+
+static const struct packet_service_state state =
+  {
+    PACKET_SERVICE_VERSION,
+    output
+  };
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_POLLHANDLER(pollhandler);
+EK_PROCESS(proc, PACKET_SERVICE_NAME, EK_PRIO_NORMAL,
+	   eventhandler, pollhandler, (void *)&state);
+
+/*---------------------------------------------------------------------------*/
+EK_PROCESS_INIT(ppp_service_init, arg)
+{
+  ek_service_start(PACKET_SERVICE_NAME, &proc);
+}
+/*---------------------------------------------------------------------------*/
+static void
+output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen)
+{
+  ppp_send();
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  switch(ev) {
+  case EK_EVENT_INIT:
+  case EK_EVENT_REPLACE:
+//    ppp_init();
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    ek_replace((struct ek_proc *)data, NULL);
+    LOADER_UNLOAD();
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    ek_exit();
+    LOADER_UNLOAD();
+    break;
+  default:
+    break;
+  }
+}
+/*---------------------------------------------------------------------------*/
+EK_POLLHANDLER(pollhandler)
+{
+  ppp_poll();
+  if(uip_len > 0) {
+    tcpip_input();
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/ppp/ppp.c b/contiki/ppp/ppp.c
new file mode 100644
index 0000000..ba993a3
--- /dev/null
+++ b/contiki/ppp/ppp.c
@@ -0,0 +1,443 @@
+/*															
+ *---------------------------------------------------------------------------
+ * ppp.c - PPP Processor/Handler											-
+ *																			-
+ *---------------------------------------------------------------------------
+ * 
+ * Version                                                                  -
+ *		0.1 Original Version Jun 3, 2000									-        
+ *																			-
+ *---------------------------------------------------------------------------    
+ */
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: ppp.c,v 1.5 2005/02/23 22:38:43 oliverschmidt Exp $
+ *
+ */
+
+/*			*/ 
+/* include files 	*/
+/*			*/ 
+
+
+#include "lcp.h"
+#include "pap.h"
+#include "ipcp.h"
+/*#include "time.h"*/
+/*#include "mip.h"*/
+
+#if 0
+#define DEBUG1(x)
+#else
+#include <stdio.h>
+#define DEBUG1(x) debug_printf x
+#endif
+
+/*
+  Set the debug message level
+*/
+#define	PACKET_RX_DEBUG	1
+
+/*
+  Include stuff
+*/
+/*#include "mTypes.h"*/
+#include "ppp.h"
+#include "ahdlc.h"
+#include "ipcp.h"
+#include "lcp.h"
+
+
+/*
+  Buffers that this layer needs (this can be optimized out)
+*/
+u8_t ppp_rx_buffer[PPP_RX_BUFFER_SIZE];
+/*u8_t ppp_tx_buffer[PPP_TX_BUFFER_SIZE];*/
+
+/*
+ * IP addr set by PPP server
+ */
+uip_ipaddr_t our_ipaddr;
+
+/*
+ * Other state storage (this can be placed in a struct and this could could
+ *	support multiple PPP connections, would have to embedded the other ppp
+ *	module state also)
+ */
+u8_t ppp_flags;
+u8_t ppp_id;
+u8_t ppp_retry;
+
+#if PACKET_RX_DEBUG
+u16_t ppp_rx_frame_count=0;
+u16_t ppp_rx_tobig_error;
+u8_t done;    /* temporary variable */
+#endif
+
+/*---------------------------------------------------------------------------*/
+static u8_t
+check_ppp_errors(void)
+{
+  u8_t ret = 0;
+
+  /* Check Errors */
+  if(lcp_state & LCP_TX_TIMEOUT) {
+    ret = 1;
+  }
+  if(lcp_state & LCP_RX_TIMEOUT) {
+    ret = 2;
+  }
+
+  if(pap_state & PAP_TX_AUTH_FAIL) {
+    ret = 3;
+  }
+  if(pap_state & PAP_RX_AUTH_FAIL) {
+    ret = 4;
+  }
+
+  if(pap_state & PAP_TX_TIMEOUT) {
+    ret = 5;
+  }
+  if(pap_state & PAP_RX_TIMEOUT) {
+    ret = 6;
+  }
+
+  if(ipcp_state & IPCP_TX_TIMEOUT) {
+    ret = 7;
+  }
+
+  return ret;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * Unknown Protocol Handler, sends reject
+ */
+static void
+ppp_reject_protocol(u16_t protocol, u8_t *buffer, u16_t count)
+{
+  u16_t	i;
+  u8_t *dptr, *sptr;
+  LCPPKT *pkt;
+	
+  /* first copy rejected packet back, start from end and work forward,
+     +++ Pay attention to buffer managment when updated. Assumes fixed
+     PPP blocks. */
+  DEBUG1(("Rejecting Protocol\n"));
+  if((count + 6) > PPP_RX_BUFFER_SIZE) {
+    /* This is a fatal error +++ do somthing about it. */
+    DEBUG1(("Cannot Reject Protocol, PKT to big\n"));
+    return;
+  }
+  dptr = buffer + count + 6;
+  sptr = buffer + count;
+  for(i = 0; i < count; ++i) {
+    *dptr-- = *sptr--;
+  }
+
+  pkt = (LCPPKT *)buffer;
+  pkt->code = PROT_REJ;		/* Write Conf_rej */
+  /*pkt->id = tid++;*/			/* write tid */
+  pkt->len = htons(count + 6);
+  *((u16_t *)(&pkt->data[0])) = htons(protocol);
+
+  ahdlc_tx(LCP, buffer, 0, (u16_t)(count + 6), 0);
+}
+/*---------------------------------------------------------------------------*/
+#if PACKET_RX_DEBUG
+void
+dump_ppp_packet(u8_t *buffer, u16_t len)
+{
+  int i;
+
+  DEBUG1(("\n"));
+  for(i = 0;i < len; ++i) {
+    if((i & 0x1f) == 0x10) {
+      DEBUG1(("\n"));
+    }
+    DEBUG1(("0x%02x ",buffer[i]));
+  }
+  DEBUG1(("\n\n"));
+}
+#endif
+/*---------------------------------------------------------------------------*/
+/* Initialize and start PPP engine.  This just sets things up to
+ * starting values.  This can stay a private method.
+ */
+/*---------------------------------------------------------------------------*/
+void
+ppp_init()
+{
+#if PACKET_RX_DEBUG
+  ppp_rx_frame_count = 0;
+  done = 0;
+#endif
+  ppp_flags = 0;
+  pap_init();
+  ipcp_init();
+  lcp_init();
+  ppp_flags = 0;
+	
+  ahdlc_init(ppp_rx_buffer, PPP_RX_BUFFER_SIZE);
+  ahdlc_rx_ready();
+}
+/*---------------------------------------------------------------------------*/
+/* raise_ppp() - This routine will try to bring up a PPP connection, 
+ *  It is blocking. In the future we probably want to pass a
+ *  structure with all the options on bringing up a PPP link, like
+ *  server/client, DSN server, username password for PAP... +++ for
+ *  now just use config and bit defines
+ */
+/*---------------------------------------------------------------------------*/
+#if 0
+u16_t
+ppp_raise(u8_t config, u8_t *username, u8_t *password)
+{
+  u16_t	status = 0;
+
+  /* Initialize PPP engine */
+  /* init_ppp(); */
+  pap_init();
+  ipcp_init();
+  lcp_init();
+
+  /* Enable PPP */
+  ppp_flags = PPP_RX_READY;
+
+  /* Try to bring up the layers */
+  while(status == 0) {
+#ifdef SYSTEM_POLLER
+    /* If the the serial interrupt is not hooked to ahdlc_rx, or the
+       system needs to handle other stuff while were blocking, call
+       the system poller.*/
+      system_poller();
+#endif		
+
+      /* call the lcp task to bring up the LCP layer */
+      lcp_task(ppp_tx_buffer);
+
+      /* If LCP is up, neg next layer */
+      if(lcp_state & LCP_TX_UP) {
+	/* If LCP wants PAP, try to authenticate, else bring up IPCP */
+	if((lcp_state & LCP_RX_AUTH) && (!(pap_state & PAP_TX_UP))) {
+	  pap_task(ppp_tx_buffer,username,password);  
+	} else {
+	  ipcp_task(ppp_tx_buffer);
+	}
+      }
+
+
+      /* If IPCP came up then our link should be up. */
+      if((ipcp_state & IPCP_TX_UP) && (ipcp_state & IPCP_RX_UP)) {
+	break;
+      }
+      
+      status = check_ppp_errors();
+    }
+  
+  return status;
+}
+#endif
+/*---------------------------------------------------------------------------*/
+void
+ppp_connect(void)
+{
+  /* Initialize PPP engine */
+  /* init_ppp(); */
+  pap_init();
+  ipcp_init();
+  lcp_init();
+  
+  /* Enable PPP */
+  ppp_flags = PPP_RX_READY;
+}
+/*---------------------------------------------------------------------------*/
+void
+ppp_send(void)
+{
+  /* If IPCP came up then our link should be up. */
+  if((ipcp_state & IPCP_TX_UP) && (ipcp_state & IPCP_RX_UP)) {
+    ahdlc_tx(IPV4, uip_buf,        uip_appdata,
+		   UIP_TCPIP_HLEN, uip_len - UIP_TCPIP_HLEN);
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+ppp_poll(void)
+{
+  u8_t c;
+
+  uip_len = 0;
+
+  if(!(ppp_flags & PPP_RX_READY)) {
+    return;
+  }
+
+  while(uip_len == 0 && ppp_arch_getchar(&c)) {
+    ahdlc_rx(c);
+  }
+
+  /* If IPCP came up then our link should be up. */
+  if((ipcp_state & IPCP_TX_UP) && (ipcp_state & IPCP_RX_UP)) {
+    return;
+  }
+
+  /* call the lcp task to bring up the LCP layer */
+  lcp_task(uip_buf);
+
+  /* If LCP is up, neg next layer */
+  if(lcp_state & LCP_TX_UP) {
+    /* If LCP wants PAP, try to authenticate, else bring up IPCP */
+    if((lcp_state & LCP_RX_AUTH) && (!(pap_state & PAP_TX_UP))) {
+      pap_task(uip_buf);  
+    } else {
+      ipcp_task(uip_buf);
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+/* ppp_upcall() - this is where valid PPP frames from the ahdlc layer are
+ *	sent to be processed and demuxed.
+ */
+/*---------------------------------------------------------------------------*/
+void
+ppp_upcall(u16_t protocol, u8_t *buffer, u16_t len)
+{
+#if PACKET_RX_DEBUG
+  ++ppp_rx_frame_count;
+  dump_ppp_packet(buffer, len);
+  if(ppp_rx_frame_count > 18) {
+    done = 1;
+  }
+#endif
+
+  /* check to see if we have a packet waiting to be processed */
+  if(ppp_flags & PPP_RX_READY) {	
+    /* demux on protocol field */
+    switch(protocol) {
+    case LCP:	/* We must support some level of LCP */
+      DEBUG1(("LCP Packet - "));
+      lcp_rx(buffer, len);
+      DEBUG1(("\n"));
+      break;
+    case PAP:	/* PAP should be compile in optional */
+      DEBUG1(("PAP Packet - "));
+      pap_rx(buffer, len);
+      DEBUG1(("\n"));
+      break;
+    case IPCP:	/* IPCP should be compile in optional. */
+      DEBUG1(("IPCP Packet - "));
+      ipcp_rx(buffer, len);
+      DEBUG1(("\n"));
+      break;
+    case IPV4:	/* We must support IPV4 */
+      DEBUG1(("IPV4 Packet---\n"));
+      memcpy(uip_buf, buffer, len);
+      uip_len = len;
+      DEBUG1(("\n"));
+      break;
+    default:
+      DEBUG1(("Unknown PPP Packet Type 0x%04x - ",protocol));
+      ppp_reject_protocol(protocol, buffer, len);
+      DEBUG1(("\n"));
+      break;
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+/* scan_packet(list,buffer,len)
+ *
+ * list = list of supported ID's
+ * *buffer pointer to the first code in the packet
+ * length of the codespace
+ */
+u16_t
+scan_packet(u16_t protocol, u8_t *list, u8_t *buffer, u8_t *options, u16_t len)
+{
+  u8_t *tlist, *bptr;
+  u8_t *tptr;
+  u8_t bad = 0;
+  u8_t i, j, good;
+
+  bptr = tptr = options;
+  /* scan through the packet and see if it has any unsupported codes */
+  while(bptr < options + len) {
+    /* get code and see if it matches somwhere in the list, if not
+       we don't support it */
+    i = *bptr++;
+    
+    /*    DEBUG2("%x - ",i);*/
+    tlist = list;
+      good = 0;
+      while(*tlist) {
+	/*	DEBUG2("%x ",*tlist);*/
+	if(i == *tlist++) {
+	  good = 1;
+	  break;
+	}
+      }
+      if(!good) {
+	/* we don't understand it, write it back */
+	DEBUG1(("We don't understand option 0x%02x\n",i));
+	bad = 1;
+	*tptr++ = i;
+	j = *tptr++ = *bptr++;
+	for(i = 0; i < j - 2; ++i) {
+	  *tptr++ = *bptr++;
+	}
+      } else {
+	/* advance over to next option */
+	bptr += *bptr - 1;
+      }
+  }
+  
+  /* Bad? if we we need to send a config Reject */
+  if(bad) {
+    /* write the config Rej packet we've built above, take on the header */
+    bptr = buffer;
+    *bptr++ = CONF_REJ;		/* Write Conf_rej */
+    bptr++;			/* skip over ID */
+    *bptr++ = 0;
+    *bptr = tptr - buffer;
+    /* length right here? */
+		
+    /* write the reject frame */
+    DEBUG1(("Writing Reject frame --\n"));
+    ahdlc_tx(protocol, buffer, 0, (u16_t)(tptr - buffer), 0);
+    DEBUG1(("\nEnd writing reject \n"));
+    
+  }		
+  return bad;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/ppp/ppp.h b/contiki/ppp/ppp.h
new file mode 100644
index 0000000..c9991fe
--- /dev/null
+++ b/contiki/ppp/ppp.h
@@ -0,0 +1,135 @@
+#ifndef __PPP_H__
+#define __PPP_H__
+/*																www.mycal.net
+---------------------------------------------------------------------------
+ ppp.h - ppp header file      									 
+---------------------------------------------------------------------------
+ Version                                                                 
+ 0.1 Original Version June 3, 2000					      
+ (c)2000 Mycal Labs, All Rights Reserved	     
+ --------------------------------------------------------------------------- */
+/*
+ * Copyright (c) 2003, Mike Johnson, Mycal Labs, www.mycal.net
+ * 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 Mike Johnson/Mycal Labs
+ *		www.mycal.net.
+ * 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 Mycal Modified uIP TCP/IP stack.
+ *
+ * $Id: ppp.h,v 1.4 2005/01/26 23:36:22 oliverschmidt Exp $
+ *
+ */
+#include "uip.h"
+#include "ppp-conf.h"
+#include "ahdlc.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "pap.h"
+#include "ppp_arch.h"
+/*#include "mip.h"*/
+
+/* moved to pppconfig.h
+#define PPP_RX_BUFFER_SIZE	1024 
+#define PPP_TX_BUFFER_SIZE	64*/
+
+#define CRC_GOOD_VALUE		0xf0b8
+
+/* ppp_rx_status values */
+#define	PPP_RX_IDLE		0
+#define PPP_READY		1
+
+/* ppp flags */
+#define PPP_ESCAPED		0x1
+#define	PPP_RX_READY		0x2
+#define	PPP_RX_ASYNC_MAP	0x8
+#define PPP_TX_ASYNC_MAP	0x8
+#define PPP_PFC			0x10
+#define PPP_ACFC		0x20
+
+/* Supported PPP Protocols */
+#define LCP			0xc021
+#define PAP			0xc023
+#define IPCP			0x8021
+#define	IPV4			0x0021
+
+/* LCP codes packet types */
+#define CONF_REQ		0x1			
+#define CONF_ACK		0x2
+#define CONF_NAK		0x3
+#define CONF_REJ		0x4
+#define TERM_REQ		0x5
+#define TERM_ACK		0x6
+#define PROT_REJ		0x8
+
+/* Raise PPP config bits */
+#define USE_PAP			0x1
+#define USE_NOACCMBUG		0x2
+#define USE_GETDNS		0x4
+
+#define ppp_setusername(un)	strncpy(pap_username, (un), PAP_USERNAME_SIZE)
+#define ppp_setpassword(pw)	strncpy(pap_password, (pw), PAP_PASSWORD_SIZE)
+
+/*
+ * Export Variables
+ */
+/*extern u8_t ppp_tx_buffer[PPP_TX_BUFFER_SIZE];*/
+extern u8_t ppp_rx_buffer[];
+extern u8_t ppp_rx_count;
+
+typedef union {
+  u8_t ip8[4];
+  u16_t ip16[2];
+} uip_ipaddr_t;
+
+extern uip_ipaddr_t our_ipaddr;
+
+/*extern u16_t ppp_crc_error;*/
+
+extern u8_t ppp_flags;
+extern u8_t ppp_status;
+/*extern u16_t ppp_rx_crc; */
+extern u16_t ppp_rx_tobig_error;
+extern u8_t ppp_lcp_state;
+
+extern u8_t ppp_id;
+extern u8_t ppp_retry;
+
+/*
+ * Function Prototypes
+ */
+void ppp_init(void);
+void ppp_connect(void);
+
+void ppp_send(void);
+void ppp_poll(void);
+
+void ppp_upcall(u16_t, u8_t *, u16_t);
+u16_t scan_packet(u16_t, u8_t *list, u8_t *buffer, u8_t *options, u16_t len);
+
+#endif /* __PPP_H__ */
diff --git a/contiki/uip/FILES b/contiki/uip/FILES
new file mode 100644
index 0000000..fea1922
--- /dev/null
+++ b/contiki/uip/FILES
@@ -0,0 +1,65 @@
+The contiki/uip/ directory contains the source code for the uIP TCP/IP
+stack and associated utility libraries.
+
+dhcpc.[ch]
+
+  A rudimentary DHCP client.
+
+packet-service.h
+
+  The Contiki/uIP packet driver interface, used by network device
+  drivers.
+  
+packet-service.c.example
+
+  An example implementation of the packet driver interface.
+
+resolv.[ch]
+
+  DNS hostname resolver library.
+
+slipdev.[ch]
+
+  A generic SLIP implementation.
+
+socket.[ch]
+
+  A BSD socket-like API built on top of the uIP API using
+  protothreads.
+
+tcpip.[ch]
+
+  The glue module between Contiki and uIP.
+
+uip-fw*.[ch]
+
+  uIP packet routing/forwarding.
+
+uip-split.[ch]
+
+  uIP TCP throughput booster hack.
+
+uip.[ch]
+
+  The uIP TCP/IP stack.
+
+uip_arch.h
+
+  The uIP architecture dependant functions interface.
+
+uip_arp.[ch]
+
+  ARP protocol implementation.
+
+uipbuf.[ch]
+
+  uIP input buffering utility functions.
+
+uiplib.[ch]
+
+  uIP conversion utility functions.
+
+uipopt.h
+
+  uIP options file with Contiki-specific settings.    
+            
\ No newline at end of file
diff --git a/contiki/uip/dhcpc.c b/contiki/uip/dhcpc.c
new file mode 100644
index 0000000..932f1f7
--- /dev/null
+++ b/contiki/uip/dhcpc.c
@@ -0,0 +1,312 @@
+
+#include "contiki.h"
+#include "dhcpc.h"
+#include "uip_arp.h"
+#include "pt.h"
+
+#include <string.h>
+
+#define STATE_INITIAL         0
+#define STATE_SENDING         1
+#define STATE_OFFER_RECEIVED  2
+#define STATE_CONFIG_RECEIVED 3
+
+static struct {
+  struct pt pt;
+  char state;
+  struct uip_udp_conn *conn;
+  struct timer timer;
+  u16_t secs;
+  
+  u8_t serverid[4];
+  
+  u16_t ipaddr[2];
+  u16_t netmask[2];
+  u16_t dnsaddr[2];
+  u16_t default_router[2];
+} s;
+
+struct dhcp_msg {
+  u8_t op, htype, hlen, hops;
+  u8_t xid[4];
+  u16_t secs, flags;
+  u8_t ciaddr[4];
+  u8_t yiaddr[4];
+  u8_t siaddr[4];
+  u8_t giaddr[4];
+  u8_t chaddr[16];
+  u8_t sname[64];
+  u8_t file[128];
+  u8_t options[312];
+};
+#define DHCP_REQUEST        1
+#define DHCP_REPLY          2
+#define DHCP_HTYPE_ETHERNET 1
+#define DHCP_HLEN_ETHERNET  6
+#define DHCP_MSG_LEN      236
+
+#define DHCPC_SERVER_PORT  67
+#define DHCPC_CLIENT_PORT  68
+
+#define DHCPDISCOVER  1
+#define DHCPOFFER     2
+#define DHCPREQUEST   3
+#define DHCPDECLINE   4
+#define DHCPACK       5
+#define DHCPNAK       6
+#define DHCPRELEASE   7 
+
+#define DHCP_OPTION_SUBNET_MASK   1
+#define DHCP_OPTION_ROUTER        3
+#define DHCP_OPTION_DNS_SERVER    6
+#define DHCP_OPTION_REQ_IPADDR   50
+#define DHCP_OPTION_MSG_TYPE     53
+#define DHCP_OPTION_SERVER_ID    54
+#define DHCP_OPTION_REQ_LIST     55
+#define DHCP_OPTION_END         255
+
+static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
+static const u8_t magic_cookie[4] = {99, 130, 83, 99};
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_msg_type(u8_t *optptr, u8_t type)
+{
+  *optptr++ = DHCP_OPTION_MSG_TYPE;
+  *optptr++ = 1;
+  *optptr++ = type;
+  return optptr;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_server_id(u8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_SERVER_ID;
+  *optptr++ = 4;
+  memcpy(optptr, s.serverid, 4);  
+  return optptr + 4;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_req_ipaddr(u8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_REQ_IPADDR;
+  *optptr++ = 4;
+  memcpy(optptr, s.ipaddr, 4);  
+  return optptr + 4;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_req_options(u8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_REQ_LIST;
+  *optptr++ = 3;
+  *optptr++ = DHCP_OPTION_SUBNET_MASK;
+  *optptr++ = DHCP_OPTION_ROUTER;
+  *optptr++ = DHCP_OPTION_DNS_SERVER;
+  return optptr;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_end(u8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_END;
+  return optptr;
+}
+/*---------------------------------------------------------------------------*/
+static void
+create_msg(register struct dhcp_msg *m)
+{
+  m->op = DHCP_REQUEST;
+  m->htype = DHCP_HTYPE_ETHERNET;
+  m->hlen = DHCP_HLEN_ETHERNET;
+  m->hops = 0;
+  memcpy(m->xid, xid, sizeof(m->xid));
+  m->secs = 0;
+  m->flags = 0;
+  /*  uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
+  memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
+  memset(m->yiaddr, 0, sizeof(m->yiaddr));
+  memset(m->siaddr, 0, sizeof(m->siaddr));
+  memset(m->giaddr, 0, sizeof(m->giaddr));
+  memcpy(m->chaddr, &uip_ethaddr, 6);
+  memset(&m->chaddr[6], 0, 10);
+  memset(m->sname, 0, sizeof(m->sname));
+  memset(m->file, 0, sizeof(m->file));
+
+  memcpy(m->options, magic_cookie, sizeof(magic_cookie));
+}
+/*---------------------------------------------------------------------------*/
+static void
+send_discover(void)
+{
+  struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
+
+  create_msg(m);
+
+  add_end(add_req_options(add_msg_type(&m->options[4], DHCPDISCOVER)));
+
+
+  uip_udp_send(300);
+}
+/*---------------------------------------------------------------------------*/
+static void
+send_request(void)
+{
+  struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
+
+  create_msg(m);
+  
+  add_end(add_req_ipaddr(add_server_id(add_msg_type(&m->options[4],
+						    DHCPREQUEST))));
+  
+  uip_udp_send(300);
+}
+/*---------------------------------------------------------------------------*/
+static u8_t
+parse_options(u8_t *optptr, int len)
+{
+  u8_t *optptr2;
+  u8_t type;
+
+  type = 0;
+  optptr2 = NULL;
+  
+  while(*optptr != DHCP_OPTION_END) {
+    switch(*optptr) {
+    case DHCP_OPTION_SUBNET_MASK:
+      memcpy(s.netmask, optptr + 2, 4);
+      break;
+    case DHCP_OPTION_ROUTER:
+      memcpy(s.default_router, optptr + 2, 4);
+      break;
+    case DHCP_OPTION_DNS_SERVER:
+      memcpy(s.dnsaddr, optptr + 2, 4);
+      break;
+    case DHCP_OPTION_MSG_TYPE:
+      type = *(optptr + 2);
+      break;
+    case DHCP_OPTION_SERVER_ID:
+      memcpy(s.serverid, optptr + 2, 4);
+      break;
+    }
+
+    /*    printf("option type %d len %d\n", *optptr, *(optptr + 1));*/
+    len -= *(optptr + 1) + 2;
+    optptr += *(optptr + 1) + 2;
+    if(len <= 0) {
+      return 0;
+    }
+
+    if(optptr == optptr2) {
+      /* Abort if we don't make progress. */
+      return 0;
+    }
+  }
+  return type;
+}
+/*---------------------------------------------------------------------------*/
+static void
+parse_msg(void)
+{
+  struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
+  
+  if(m->op == DHCP_REPLY &&
+     memcmp(m->xid, xid, sizeof(xid)) == 0/* &&
+					     memcmp(m->chaddr, &uip_ethaddr, sizeof(uip_ethaddr))*/) {
+    memcpy(s.ipaddr, m->yiaddr, 4);
+    parse_options(&m->options[4], uip_datalen());
+  }
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_dhcp(void))
+{
+  PT_BEGIN(&s.pt);
+  
+  PT_WAIT_UNTIL(&s.pt, s.state == STATE_SENDING);
+
+  s.secs = 0;
+  timer_set(&s.timer, CLOCK_SECOND * 2);
+
+  while(s.state != STATE_OFFER_RECEIVED) {
+    send_discover();
+    PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
+
+    timer_reset(&s.timer);
+    
+    if(uip_newdata()) {
+      parse_msg();
+      s.state = STATE_OFFER_RECEIVED;
+    }
+    ++s.secs;
+  }
+  
+  while(s.state != STATE_CONFIG_RECEIVED) {
+    
+    send_request();
+    
+    PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
+
+    timer_reset(&s.timer);
+    
+    if(uip_newdata()) {
+      s.state = STATE_CONFIG_RECEIVED;
+    }
+    ++s.secs;
+  }
+  
+  /*  printf("Got IP address %d.%d.%d.%d\n",
+	 uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr),
+	 uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr));
+  printf("Got netmask %d.%d.%d.%d\n",
+	 uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask),
+	 uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask));
+  printf("Got DNS server %d.%d.%d.%d\n",
+	 uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr),
+	 uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr));
+  printf("Got default router %d.%d.%d.%d\n",
+	 uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router),
+	 uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router));*/
+
+  uip_sethostaddr(s.ipaddr);
+  uip_setnetmask(s.netmask);
+  uip_setdraddr(s.default_router);
+  resolv_conf(s.dnsaddr);
+  dhcpc_configured();
+  
+  PT_END(&s.pt);
+}
+/*---------------------------------------------------------------------------*/
+void
+dhcpc_init(void)
+{
+  u16_t addr[2];
+  
+  s.state = STATE_INITIAL;
+  uip_ipaddr(addr, 255,255,255,255);
+  s.conn = udp_new(addr, HTONS(DHCPC_SERVER_PORT), NULL);
+  if(s.conn != NULL) {
+    udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
+  }
+  PT_INIT(&s.pt);
+}
+/*---------------------------------------------------------------------------*/
+void
+dhcpc_appcall(void *state)
+{
+  handle_dhcp();
+}
+/*---------------------------------------------------------------------------*/
+void
+dhcpc_request(void)
+{
+  u16_t ipaddr[2];
+  
+  if(s.state == STATE_INITIAL) {
+    uip_ipaddr(ipaddr, 0,0,0,0);
+    uip_sethostaddr(ipaddr);
+    s.state = STATE_SENDING;
+    tcpip_poll_udp(s.conn);
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/uip/dhcpc.h b/contiki/uip/dhcpc.h
new file mode 100644
index 0000000..d0cdf11
--- /dev/null
+++ b/contiki/uip/dhcpc.h
@@ -0,0 +1,11 @@
+#ifndef __DHCPC_H__
+#define __DHCPC_H__
+
+void dhcpc_init(void);
+void dhcpc_request(void);
+
+void dhcpc_appcall(void *state);
+
+void dhcpc_configured(void);
+
+#endif /* __DHCPC_H__ */
diff --git a/contiki/uip/packet-service.c.example b/contiki/uip/packet-service.c.example
new file mode 100644
index 0000000..b3824a8
--- /dev/null
+++ b/contiki/uip/packet-service.c.example
@@ -0,0 +1,54 @@
+
+#include "packet-service.h"
+
+static void output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen);
+
+static const struct tcpip_packetservice_state state =
+  {
+    TCPIP_PACKETSERVICE_VERSION,
+    output
+  };
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_POLLHANDLER(pollhandler);
+EK_PROCESS(proc, TCPIP_PACKETSERVICE_NAME, EK_PRIO_NORMAL,
+	   eventhandler, pollhandler, (void *)&state);
+
+/*---------------------------------------------------------------------------*/
+EK_PROCESS_INIT(packet_service_init, arg)
+{
+  ek_service_start(tcpip_packetservice_name, &proc);
+}
+/*---------------------------------------------------------------------------*/
+static void
+output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen)
+{
+  printf("packet-service: output (%p, %d) (%p, %d)\n",
+	 hdr, hdrlen, data, datalen);
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  printf("packet-service: event %d\n", ev);
+  switch(ev) {
+  case EK_EVENT_STARTED:
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    ek_replace((struct ek_proc *)data, state);
+    LOADER_UNLOAD();
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    ek_exit();
+    LOADER_UNLOAD();
+    break;
+  default:
+    break;
+  }
+
+}
+/*---------------------------------------------------------------------------*/
+EK_POLLHANDLER(pollhandler)
+{
+
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/uip/packet-service.h b/contiki/uip/packet-service.h
new file mode 100644
index 0000000..05220b7
--- /dev/null
+++ b/contiki/uip/packet-service.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: packet-service.h,v 1.3 2004/09/12 20:24:56 adamdunkels Exp $
+ */
+#ifndef __PACKET_SERVICE_H__
+#define __PACKET_SERVICE_H__
+
+#include "ek-service.h"
+
+#include "uip.h"
+
+/* Packet service interface. */
+
+#define PACKET_SERVICE_NAME "Packet driver"
+#define PACKET_SERVICE_VERSION 0x01
+struct packet_service_state {
+  u8_t version;
+  void (* output)(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen);
+};
+
+EK_PROCESS_INIT(packet_service_init, arg);
+
+#endif /* __PACKET_SERVICE_H__ */
diff --git a/contiki/uip/psock.c b/contiki/uip/psock.c
new file mode 100644
index 0000000..4e5daaf
--- /dev/null
+++ b/contiki/uip/psock.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: psock.c,v 1.1 2005/02/22 22:23:07 adamdunkels Exp $
+ */
+
+#include "psock.h"
+
+#define PSOCK_STATE_NONE 0
+#define PSOCK_STATE_ACKED 1
+#define PSOCK_STATE_READ 2
+#define PSOCK_STATE_BLOCKED_NEWDATA 3
+#define PSOCK_STATE_BLOCKED_CLOSE 4
+#define PSOCK_STATE_BLOCKED_SEND 5
+#define PSOCK_STATE_DATA_SENT 6
+
+/*---------------------------------------------------------------------------*/
+static char
+send_data(register struct psock *s)
+{
+  if(s->state != PSOCK_STATE_DATA_SENT || uip_rexmit()) {
+    if(s->sendlen > uip_mss()) {
+      uip_send(s->sendptr, uip_mss());
+    } else {
+      uip_send(s->sendptr, s->sendlen);
+    }
+    s->state = PSOCK_STATE_DATA_SENT;
+    return 1;
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+static char
+data_sent(register struct psock *s)
+{
+  if(s->state == PSOCK_STATE_DATA_SENT && uip_acked()) {
+    if(s->sendlen > uip_mss()) {
+      s->sendlen -= uip_mss();
+      s->sendptr += uip_mss();
+    } else {
+      s->sendptr += s->sendlen;
+      s->sendlen = 0;
+    }
+    s->state = PSOCK_STATE_ACKED;
+    return 1;
+  }
+  return 0;
+}
+/*---------------------------------------------------------------------------*/
+PT_THREAD(psock_send(register struct psock *s, const char *buf, unsigned int len))
+{
+  PT_BEGIN(&s->psockpt);
+
+  if(len == 0) {
+    PT_EXIT(&s->psockpt);
+  }
+  
+  s->sendptr = buf;
+  s->sendlen = len;
+
+  s->state = PSOCK_STATE_NONE;
+  
+  while(s->sendlen > 0) {
+    PT_WAIT_UNTIL(&s->psockpt, data_sent(s) & send_data(s));
+  }
+
+  s->state = PSOCK_STATE_NONE;
+  
+  PT_END(&s->psockpt);
+}
+/*---------------------------------------------------------------------------*/
+PT_THREAD(psock_generator_send(register struct psock *s,
+			       unsigned short (*generate)(void *), void *arg))
+{
+  PT_BEGIN(&s->psockpt);
+
+  if(generate == NULL) {
+    PT_EXIT(&s->psockpt);
+  }
+  
+  s->state = PSOCK_STATE_NONE;
+  s->sendlen = generate(arg);
+  s->sendptr = uip_appdata;
+  do {
+
+    if(uip_rexmit()) {
+      generate(arg);
+    }
+    PT_WAIT_UNTIL(&s->psockpt, data_sent(s) & send_data(s));
+  } while(s->sendlen > 0);    
+  
+  s->state = PSOCK_STATE_NONE;
+  
+  PT_END(&s->psockpt);
+}
+/*---------------------------------------------------------------------------*/
+char
+psock_newdata(struct psock *s)
+{
+  if(s->readlen > 0) {
+    /* Data in uip_appdata buffer that has not yet been read. */
+    return 1;
+  } else if(s->state == PSOCK_STATE_READ) {
+    /* Data in uip_appdata buffer already consumed. */
+    s->state = PSOCK_STATE_BLOCKED_NEWDATA;
+    return 0;
+  } else if(uip_newdata()) {
+    /* There is new data that has not been consumed. */
+    return 1;
+  } else {
+    /* There is no new data. */
+    return 0;
+  }
+}
+/*---------------------------------------------------------------------------*/
+PT_THREAD(psock_readto(register struct psock *psock, unsigned char c))
+{
+  PT_BEGIN(&psock->psockpt);
+
+  uipbuf_setup(&psock->buf, psock->bufptr, psock->bufsize);
+  
+  /* XXX: Should add uipbuf_checkmarker() before do{} loop, if
+     incoming data has been handled while waiting for a write. */
+
+  do {
+    if(psock->readlen == 0) {
+      PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
+      psock->state = PSOCK_STATE_READ;
+      psock->readptr = (u8_t *)uip_appdata;
+      psock->readlen = uip_datalen();
+    }
+  } while((uipbuf_bufto(&psock->buf, c,
+			&psock->readptr,
+			&psock->readlen) & UIPBUF_FOUND) == 0);
+
+  if(uipbuf_len(&psock->buf) == 0) {
+    psock->state = PSOCK_STATE_NONE;
+    PT_RESTART(&psock->psockpt);
+  }  
+  PT_END(&psock->psockpt);
+}
+/*---------------------------------------------------------------------------*/
+void
+psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)
+{
+  psock->state = PSOCK_STATE_NONE;
+  psock->readlen = 0;
+  psock->bufptr = buffer;
+  psock->bufsize = buffersize;
+  uipbuf_setup(&psock->buf, buffer, buffersize);
+  PT_INIT(&psock->pt);
+  PT_INIT(&psock->psockpt);
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/uip/psock.h b/contiki/uip/psock.h
new file mode 100644
index 0000000..287bf44
--- /dev/null
+++ b/contiki/uip/psock.h
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: psock.h,v 1.1 2005/02/22 22:23:07 adamdunkels Exp $
+ */
+
+/**
+ * \defgroup psock Protosockets library
+ * @{
+ *
+ * The protosocket library provides an interface to the uIP stack that is
+ * similar to the traditional BSD socket interface. Unlike programs
+ * written for the ordinary uIP event-driven interface, programs
+ * written with the protosocket library are executed in a sequential
+ * fashion and does not have to be implemented as explicit state
+ * machines.
+ *
+ * Protosockets only work with TCP connections. 
+ *
+ * The protosocket library uses \ref pt protothreads to provide
+ * sequential control flow. This makes the protosockets lightweight in
+ * terms of memory, but also means that protosockets inherits the
+ * functional limitations of protothreads. Each protosocket lives only
+ * within a single function block. Automatic variables (stack
+ * variables) are not necessarily retained across a protosocket
+ * library function call.
+ *
+ * \note Because the protosocket library uses protothreads, local variables
+ * will not always be saved across a call to a protosocket library
+ * function. It is therefore advised that local variables are used
+ * with extreme care.
+ *
+ * The protosocket library provides functions for sending data without
+ * having to deal with retransmissions and acknowledgements, as well
+ * as functions for reading data without having to deal with data
+ * being split across more than one TCP segment.
+ *
+ * Because each protosocket runs as a protothread, the protosocket has to be
+ * started with a call to PSOCK_BEGIN() at the start of the function
+ * in which the protosocket is used. Similarly, the protosocket protothread can
+ * be terminated by a call to PSOCK_EXIT().
+ *
+ * The example code below illustrates how to use the protosocket
+ * library. The program implements a simple SMTP client that sends a
+ * short email. The program is divided into two functions, one uIP
+ * event handler (smtp_uipcall()) and one function that runs the
+ * protosocket protothread and performs the SMTP communication
+ * (smtp_socketthread()).
+ *
+ * An SMTP connection is represented by a smtp_state structure
+ * containing a struct psock and a small input buffer. The input
+ * buffer only needs to be 3 bytes long to accomodate the 3 byte
+ * status codes used by SMTP. Connection structures can be allocated
+ * from the memory buffer called connections, which is declared with
+ * the MEMB() macro.
+ *
+ * The convenience macro SEND_STRING() is defined in order to simplify
+ * the code, as it mostly involves sending strings.
+ *  
+ * The function smtp_socketthread() is declared as a protothread using
+ * the PT_THREAD() macro. The PSOCK_BEGIN() call at the first line of
+ * the smtp_socketthread() function starts the protothread. SMTP
+ * specifies that the server will start with sending a welcome message
+ * that should include the status code 220 if the server is ready to
+ * accept messages. Therefore, the smtp_socketthread() first calls
+ * PSOCK_READTO() to read all incoming data up to the first
+ * newline. If the status code was anything else but 220, the protosocket
+ * is closed and the protosocket's protothread is terminated with the call
+ * to PSOCK_CLOSE_EXIT().
+ *
+ * If the connection is accepted by the server, smtp_socketthread()
+ * continues with sending the HELO message. If this gets a positive
+ * reply (a status code beginning with a 2), the protothread moves on
+ * with the rest of the SMTP procedure. Finally, after all headers and
+ * data is sent, the program sends a QUIT before it finally closes the
+ * protosocket and exits the protosocket's protothread.
+ * 
+ *
+ \code
+#include <string.h>
+
+#include "psock.h"
+#include "memb.h"
+
+struct smtp_state {  
+  struct psock psock;
+  char inputbuffer[3];
+};
+
+MEMB(connections, sizeof(struct smtp_state), 2);
+
+#define SEND_STRING(s, str) PSOCK_SEND(s, str, strlen(str))
+
+static
+PT_THREAD(smtp_socketthread(struct smtp_state *s))
+{
+  PSOCK_BEGIN(&s->psock);
+
+  PSOCK_READTO(&s->psock, '\n');
+   
+  if(strncmp(s->inputbuffer, "220", 3) != 0) {
+    PSOCK_CLOSE_EXIT(&s->psock);
+  }
+
+  SEND_STRING(&s->psock, "HELO contiki.example.com\r\n");
+
+  PSOCK_READTO(&s->psock, '\n');  
+  if(s->inputbuffer[0] != '2') {
+    PSOCK_CLOSE_EXIT(&s->psock);
+  }
+
+  SEND_STRING(&s->psock, "MAIL FROM: contiki@example.com\r\n");
+
+  PSOCK_READTO(&s->psock, '\n');  
+  if(s->inputbuffer[0] != '2') {
+    PSOCK_CLOSE_EXIT(&s->psock);
+  }
+
+  SEND_STRING(&s->psock, "RCPT TO: contiki@example.com\r\n");
+
+  PSOCK_READTO(&s->psock, '\n');  
+  if(s->inputbuffer[0] != '2') {
+    PSOCK_CLOSE_EXIT(&s->psock);
+  }
+  
+  SEND_STRING(&s->psock, "DATA\r\n");
+  
+  PSOCK_READTO(&s->psock, '\n');
+  if(s->inputbuffer[0] != '3') {
+    PSOCK_CLOSE_EXIT(&s->psock);
+  }
+
+  SEND_STRING(&s->psock, "To: contiki@example.com\r\n");
+  SEND_STRING(&s->psock, "From: contiki@example.com\r\n");
+  SEND_STRING(&s->psock, "Subject: Example\r\n");
+
+  SEND_STRING(&s->psock, "A test message from Contiki.\r\n");
+  
+  SEND_STRING(&s->psock, "\r\n.\r\n");
+
+  PSOCK_READTO(&s->psock, '\n');  
+  if(s->inputbuffer[0] != '2') {
+    PSOCK_CLOSE_EXIT(&s->psock);
+  }
+
+  SEND_STRING(&s->psock, "QUIT\r\n");
+  
+  PSOCK_END(&s->psock);
+}
+
+void
+smtp_uipcall(void *state)
+{
+  struct smtp_state *s = (struct smtp_state *)state;
+  
+  if(uip_closed() || uip_aborted() || uip_timedout()) {
+    memb_free(&connections, s);
+  } else if(uip_connected()) {
+    PSOCK_INIT(s, s->inputbuffer, sizeof(s->inputbuffer));
+  } else {
+    smtp_socketthread(s);
+  }
+}
+ \endcode
+ *
+ */
+
+/**
+ * \file
+ * Protosocket library header file
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __PSOCK_H__
+#define __PSOCK_H__
+
+#include "pt.h"
+#include "uipbuf.h"
+#include "memb.h"
+
+/**
+ * The representation of a protosocket.
+ *
+ * The protosocket structrure is an opaque structure with no user-visible
+ * elements.
+ */
+struct psock {
+  struct pt pt, psockpt;
+  unsigned char state;
+  const u8_t *sendptr;
+  u16_t sendlen;
+  u8_t *readptr;
+  u16_t readlen;
+
+  struct uipbuf_buffer buf;
+  char *bufptr;
+  unsigned int bufsize;
+};
+
+void psock_init(struct psock *psock, char *buffer, unsigned int buffersize);
+/**
+ * Initialize a protosocket.
+ *
+ * This macro initializes a protosocket and must be called before the
+ * protosocket is used. The initialization also specifies the input buffer
+ * for the protosocket.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket to be
+ * initialized
+ *
+ * \param buffer (char *) A pointer to the input buffer for the
+ * protosocket.
+ *
+ * \param buffersize (unsigned int) The size of the input buffer.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_INIT(psock, buffer, buffersize) \
+  psock_init(psock, buffer, buffersize)
+
+/**
+ * Start the protosocket protothread in a function.
+ *
+ * This macro starts the protothread associated with the protosocket and
+ * must come before other protosocket calls in the function it is used.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket to be
+ * started.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))
+
+PT_THREAD(psock_send(struct psock *psock, const char *buf, unsigned int len));
+/**
+ * Send data.
+ *
+ * This macro sends data over a protosocket. The protosocket protothread blocks
+ * until all data has been sent and is known to have been received by
+ * the remote end of the TCP connection.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket over which
+ * data is to be sent.
+ *
+ * \param data (char *) A pointer to the data that is to be sent.
+ *
+ * \param datalen (unsigned int) The length of the data that is to be
+ * sent.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_SEND(psock, data, datalen)		\
+    PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen))
+
+PT_THREAD(psock_generator_send(struct psock *psock,
+				unsigned short (*f)(void *), void *arg));
+
+#define PSOCK_GENERATOR_SEND(psock, generator, arg)     \
+    PT_WAIT_THREAD(&((psock)->pt),					\
+		   psock_generator_send(psock, generator, arg))
+
+
+/*PT_THREAD(psock_closew(struct psock *psock));
+#define PSOCK_CLOSEW(psock)				\
+  PT_WAIT_THREAD(&(psock)->pt, psock_closew(psock))
+*/
+
+/**
+ * Close a protosocket.
+ *
+ * This macro closes a protosocket and can only be called from within the
+ * protothread in which the protosocket lives.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket that is to
+ * be closed.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_CLOSE(psock) uip_close()
+
+PT_THREAD(psock_readto(struct psock *psock, unsigned char c));
+
+/**
+ * Read data up to a specified character.
+ *
+ * This macro will block waiting for data and read the data into the
+ * input buffer specified with the call to PSOCK_INIT(). Data is only
+ * read until the specifieed character appears in the data stream.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket from which
+ * data should be read.
+ *
+ * \param c (char) The character at which to stop reading.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_READTO(psock, c)				\
+  PT_WAIT_THREAD(&((psock)->pt), psock_readto(psock, c))
+
+/**
+ * The length of the data that was previously read.
+ *
+ * This macro returns the length of the data that was previously read
+ * using PSOCK_READTO() or PSOCK_READ().
+ *
+ * \param psock (struct psock *) A pointer to the protosocket holding the data.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_DATALEN(psock) uipbuf_len(&(psock)->buf)
+
+/**
+ * Exit the protosocket's protothread.
+ *
+ * This macro terminates the protothread of the protosocket and should
+ * almost always be used in conjunction with PSOCK_CLOSE().
+ *
+ * \sa PSOCK_CLOSE_EXIT()
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt))
+
+/**
+ * Close a protosocket and exit the protosocket's protothread.
+ *
+ * This macro closes a protosocket and exits the protosocket's protothread.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_CLOSE_EXIT(psock)		\
+  do {						\
+    PSOCK_CLOSE(psock);			\
+    PSOCK_EXIT(psock);			\
+  } while(0)
+
+#define PSOCK_END(psock) PT_END(&((psock)->pt))
+
+char psock_newdata(struct psock *s);
+
+/**
+ * Check if new data has arrived on a protosocket.
+ *
+ * This macro is used in conjunction with the PSOCK_WAIT_UNTIL()
+ * macro to check if data has arrived on a protosocket.
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_NEWDATA(psock) psock_newdata(psock)
+
+/**
+ * Wait until a condition is true.
+ *
+ * This macro blocks the protothread until the specified condition is
+ * true. The macro PSOCK_NEWDATA() can be used to check if new data
+ * arrives when the protosocket is waiting.
+ *
+ * Typically, this macro is used as follows:
+ *
+ \code
+ PT_THREAD(thread(struct psock *s, struct timer *t))
+ {
+   PSOCK_BEGIN(s);
+
+   PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t));
+   
+   if(PSOCK_NEWDATA(s)) {
+     PSOCK_READTO(s, '\n');
+   } else {
+     handle_timed_out(s);
+   }
+   
+   PSOCK_END(s);
+ }
+ \endcode 
+ *
+ * \param psock (struct psock *) A pointer to the protosocket.
+ * \param condition The condition to wait for.
+ *
+ * \hideinitializer
+ */
+#define PSOCK_WAIT_UNTIL(psock, condition)    \
+  PT_WAIT_UNTIL(&((psock)->pt), (condition));
+
+#define PSOCK_WAIT_THREAD(psock, condition)   \
+  PT_WAIT_THREAD(&((psock)->pt), (condition))
+
+#endif /* __PSOCK_H__ */
diff --git a/contiki/uip/resolv.c b/contiki/uip/resolv.c
new file mode 100644
index 0000000..2af92f0
--- /dev/null
+++ b/contiki/uip/resolv.c
@@ -0,0 +1,510 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uipdns uIP hostname resolver functions
+ * @{
+ *
+ * The uIP DNS resolver functions are used to lookup a hostname and
+ * map it to a numerical IP address. It maintains a list of resolved
+ * hostnames that can be queried with the resolv_lookup()
+ * function. New hostnames can be resolved using the resolv_query()
+ * function.
+ *
+ * The event resolv_event_found is posted when a hostname has been
+ * resolved. It is up to the receiving process to determine if the
+ * correct hostname has been found by calling the resolv_lookup()
+ * function with the hostname.
+ */
+
+/**
+ * \file
+ * DNS host name to IP address resolver.
+ * \author Adam Dunkels <adam@dunkels.com>
+ * 
+ * This file implements a DNS host name to IP address resolver.
+ */
+
+/*
+ * Copyright (c) 2002-2003, 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. 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.15 2005/02/07 07:08:03 adamdunkels Exp $
+ *
+ */
+
+#include "ek.h"
+#include "tcpip.h"
+#include "resolv.h"
+
+#include <string.h>
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+/** \internal The maximum number of retries when asking for a name. */
+#define MAX_RETRIES 8
+
+/** \internal The DNS message header. */
+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;
+};
+
+/** \internal The DNS answer message structure. */
+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];
+};
+
+struct namemap {
+#define STATE_UNUSED 0
+#define STATE_NEW    1
+#define STATE_ASKING 2
+#define STATE_DONE   3
+#define STATE_ERROR  4
+  u8_t state;
+  u8_t tmr;
+  u8_t retries;
+  u8_t seqno;
+  u8_t err;
+  char name[32];
+  u16_t ipaddr[2];
+};
+
+#ifndef UIP_CONF_RESOLV_ENTRIES
+#define RESOLV_ENTRIES 4
+#else /* UIP_CONF_RESOLV_ENTRIES */
+#define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES
+#endif /* UIP_CONF_RESOLV_ENTRIES */
+
+
+static struct namemap names[RESOLV_ENTRIES];
+
+static u8_t seqno;
+
+static struct uip_udp_conn *resolv_conn = NULL;
+
+ek_event_t resolv_event_found;
+
+/*static DISPATCHER_UIPCALL(udp_appcall, arg);
+static struct dispatcher_proc p =
+{DISPATCHER_PROC("DNS resolver", NULL, NULL, udp_appcall)};*/
+EK_EVENTHANDLER(resolv_eventhandler, ev, data);
+EK_PROCESS(p, "DNS resolver", EK_PRIO_NORMAL, resolv_eventhandler, NULL, NULL);
+static ek_id_t id = EK_ID_NONE;
+
+enum {
+  EVENT_NEW_SERVER=0
+};
+
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Walk through a compact encoded DNS name and return the end of it.
+ *
+ * \return 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;
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Runs through the list of names to see if there are any that have
+ * not yet been queried and, if so, sends out a query.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+check_entries(void)
+{
+  register struct dns_hdr *hdr;
+  char *query, *nptr, *nameptr;
+  static u8_t i;
+  static u8_t n;
+  register struct namemap *namemapptr;
+  
+  for(i = 0; i < RESOLV_ENTRIES; ++i) {    
+    namemapptr = &names[i];
+    if(namemapptr->state == STATE_NEW ||
+       namemapptr->state == STATE_ASKING) {
+      if(namemapptr->state == STATE_ASKING) {
+	if(--namemapptr->tmr == 0) {
+	  if(++namemapptr->retries == MAX_RETRIES) {
+	    namemapptr->state = STATE_ERROR;
+	    resolv_found(namemapptr->name, NULL);
+	    continue;
+	  }
+	  namemapptr->tmr = namemapptr->retries;	  
+	} else {
+	  /*	  printf("Timer %d\n", namemapptr->tmr);*/
+	  /* Its timer has not run out, so we move on to next
+	     entry. */
+	  continue;
+	}
+      } else {
+	namemapptr->state = STATE_ASKING;
+	namemapptr->tmr = 1;
+	namemapptr->retries = 0;
+      }
+      hdr = (struct dns_hdr *)uip_appdata;
+      memset(hdr, 0, sizeof(struct dns_hdr));
+      hdr->id = htons(i);
+      hdr->flags1 = DNS_FLAG1_RD;
+      hdr->numquestions = HTONS(1);
+      query = (char *)uip_appdata + 12;
+      nameptr = namemapptr->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);
+      {
+	static unsigned char endquery[] =
+	  {0,0,1,0,1};
+	memcpy(query, endquery, 5);
+      }
+      uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata));
+      break;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Called when new UDP data arrives.
+ */
+/*-----------------------------------------------------------------------------------*/
+static void
+newdata(void)
+{
+  char *nameptr;
+  struct dns_answer *ans;
+  struct dns_hdr *hdr;
+  static u8_t nquestions, nanswers;
+  static u8_t i;
+  register struct namemap *namemapptr;
+  
+  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);
+  namemapptr = &names[i];
+  if(i < RESOLV_ENTRIES &&
+     namemapptr->state == STATE_ASKING) {
+
+    /* This entry is now finished. */
+    namemapptr->state = STATE_DONE;
+    namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
+
+    /* Check for error. If so, call callback to inform. */
+    if(namemapptr->err != 0) {
+      namemapptr->state = STATE_ERROR;
+      resolv_found(namemapptr->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. */
+	namemapptr->ipaddr[0] = ans->ipaddr[0];
+	namemapptr->ipaddr[1] = ans->ipaddr[1];
+	
+	resolv_found(namemapptr->name, namemapptr->ipaddr);
+	return;
+      } else {
+	nameptr = nameptr + 10 + htons(ans->len);
+      }
+      --nanswers;
+    }
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * The main UDP function.
+ */
+/*-----------------------------------------------------------------------------------*/
+EK_EVENTHANDLER(resolv_eventhandler, ev, data)
+{
+  EK_EVENTHANDLER_ARGS(ev, data);
+  if(ev == EVENT_NEW_SERVER) {
+    if(resolv_conn != NULL) {
+      uip_udp_remove(resolv_conn);
+    }
+    
+    resolv_conn = udp_new((u16_t *)data, HTONS(53), NULL);
+
+  } else if(ev == tcpip_event) {
+    if(uip_udp_conn->rport == HTONS(53)) {
+      if(uip_poll()) {
+	check_entries();
+      }
+      if(uip_newdata()) {
+	newdata();
+      }       
+    }
+  } 
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Queues a name so that a question for the name will be sent out.
+ *
+ * \param name The hostname that is to be queried.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+resolv_query(char *name)
+{
+  static u8_t i;
+  static u8_t lseq, lseqi;
+  register struct namemap *nameptr;
+      
+  lseq = lseqi = 0;
+  
+  for(i = 0; i < RESOLV_ENTRIES; ++i) {
+    nameptr = &names[i];
+    if(nameptr->state == STATE_UNUSED) {
+      break;
+    }
+    if(seqno - nameptr->seqno > lseq) {
+      lseq = seqno - nameptr->seqno;
+      lseqi = i;
+    }
+  }
+
+  if(i == RESOLV_ENTRIES) {
+    i = lseqi;
+    nameptr = &names[i];
+  }
+
+  strncpy(nameptr->name, name, sizeof(nameptr->name));
+  nameptr->state = STATE_NEW;
+  nameptr->seqno = seqno;
+  ++seqno;
+
+  if(resolv_conn != NULL) {
+    tcpip_poll_udp(resolv_conn);
+    /*ek_post(EK_BROADCAST, uip_event_poll_udp, resolv_conn);*/
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Look up a hostname in the array of known hostnames.
+ *
+ * \note This function only looks in the internal array of known
+ * hostnames, it does not send out a query for the hostname if none
+ * was found. The function resolv_query() can be used to send a query
+ * for a hostname.
+ *
+ * \return A pointer to a 4-byte representation of the hostname's IP
+ * address, or NULL if the hostname was not found in the array of
+ * hostnames.
+ */
+/*-----------------------------------------------------------------------------------*/
+u16_t *
+resolv_lookup(char *name)
+{
+  static u8_t i;
+  struct namemap *nameptr;
+  
+  /* 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) {
+    nameptr = &names[i];
+    if(nameptr->state == STATE_DONE &&
+       strcmp(name, nameptr->name) == 0) {            
+      return nameptr->ipaddr;
+    }
+  }
+  return NULL;
+}  
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Obtain the currently configured DNS server.
+ *
+ * \return A pointer to a 4-byte representation of the IP address of
+ * the currently configured DNS server or NULL if no DNS server has
+ * been configured.
+ */
+/*-----------------------------------------------------------------------------------*/
+u16_t *
+resolv_getserver(void)
+{
+  if(resolv_conn == NULL) {
+    return NULL;
+  }
+  return resolv_conn->ripaddr;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Configure a DNS server.
+ *
+ * \param dnsserver A pointer to a 4-byte representation of the IP
+ * address of the DNS server to be configured.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+resolv_conf(u16_t *dnsserver)
+{
+  static u16_t server[2];
+  uip_ipaddr_copy(server, dnsserver);
+  ek_post(id, EVENT_NEW_SERVER, server);
+  
+  /*  if(resolv_conn != NULL) {
+    uip_udp_remove(resolv_conn);
+  }
+  
+  resolv_conn = udp_new(dnsserver, 53, NULL);*/
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Initalize the resolver.
+ */
+/*-----------------------------------------------------------------------------------*/
+/*LOADER_INIT_FUNC(resolv_init, arg)*/
+void
+resolv_init(char *arg)
+{
+  static u8_t i;
+  arg_free(arg);
+  
+  id = ek_start(&p);
+  
+  for(i = 0; i < RESOLV_ENTRIES; ++i) {
+    names[i].state = STATE_UNUSED;
+  }
+  resolv_conn = NULL;
+  resolv_event_found = ek_alloc_event();    
+}
+/*-----------------------------------------------------------------------------------*/
+/** \internal
+ * Callback function which is called when a hostname is found.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+resolv_found(char *name, u16_t *ipaddr)
+{
+  ek_post(EK_BROADCAST, resolv_event_found, name);
+}
+/*-----------------------------------------------------------------------------------*/
+
+/** @} */
+/** @} */
diff --git a/contiki/uip/resolv.h b/contiki/uip/resolv.h
new file mode 100644
index 0000000..c1067fc
--- /dev/null
+++ b/contiki/uip/resolv.h
@@ -0,0 +1,61 @@
+/**
+ * \file
+ * uIP DNS resolver code header file.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2002-2003, 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. 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.7 2005/02/07 07:08:03 adamdunkels Exp $
+ *
+ */
+#ifndef __RESOLV_H__
+#define __RESOLV_H__
+
+#include "uip.h"
+
+/**
+ * Event that is broadcasted when a DNS name has been resolved.
+ */
+extern ek_event_t resolv_event_found;
+
+/* Callbacks. */
+void resolv_found(char *name, u16_t *ipaddr);
+
+/* Functions. */
+void resolv_conf(u16_t *dnsserver);
+u16_t *resolv_getserver(void);
+/*LOADER_INIT_FUNC(resolv_init, arg);*/
+void resolv_init(char *arg);
+u16_t *resolv_lookup(char *name);
+void resolv_query(char *name);
+
+#endif /* __RESOLV_H__ */
diff --git a/contiki/uip/slipdev.c b/contiki/uip/slipdev.c
new file mode 100644
index 0000000..f66405f
--- /dev/null
+++ b/contiki/uip/slipdev.c
@@ -0,0 +1,208 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup slip Serial Line IP (SLIP) protocol
+ * @{
+ *
+ * The SLIP protocol is a very simple way to transmit IP packets over
+ * a serial line. It does not provide any framing or error control,
+ * and is therefore not very widely used today.
+ *
+ * This SLIP implementation requires two functions for accessing the
+ * serial device: slipdev_char_poll() and slipdev_char_put(). These
+ * must be implemented specifically for the system on which the SLIP
+ * protocol is to be run.
+ */
+
+/**
+ * \file
+ * SLIP protocol implementation
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * 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. 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: slipdev.c,v 1.2 2003/11/27 15:54:20 adamdunkels Exp $
+ *
+ */
+
+/*
+ * This is a generic implementation of the SLIP protocol over an RS232
+ * (serial) device. 
+ *
+ * Huge thanks to Ullrich von Bassewitz <uz@cc65.org> of cc65 fame for
+ * and endless supply of bugfixes, insightsful comments and
+ * suggestions, and improvements to this code!
+ */
+
+#include "uip.h"
+#include "uip-fw.h"
+#include "slipdev.h"
+#include <string.h>  /* For memcpy() */
+
+#define SLIP_END     0300
+#define SLIP_ESC     0333
+#define SLIP_ESC_END 0334
+#define SLIP_ESC_ESC 0335
+
+static u8_t slip_buf[UIP_BUFSIZE];
+
+static u16_t len, tmplen;
+static u8_t lastc;
+
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Send the packet in the uip_buf and uip_appdata buffers using the
+ * SLIP protocol.
+ *
+ * The first 40 bytes of the packet (the IP and TCP headers) are read
+ * from the uip_buf buffer, and the following bytes (the application
+ * data) are read from the uip_appdata buffer.
+ *
+ * \return This function will always return UIP_FW_OK.
+ */
+/*-----------------------------------------------------------------------------------*/
+u8_t
+slipdev_send(void)
+{
+  u16_t i;
+  u8_t *ptr;
+  u8_t c;
+
+  slipdev_char_put(SLIP_END);
+
+  ptr = &uip_buf[UIP_LLH_LEN];
+  for(i = 0; i < uip_len; ++i) {
+    if(i == UIP_TCPIP_HLEN) {
+      ptr = (char *)uip_appdata;
+    }
+    c = *ptr++;
+    switch(c) {
+    case SLIP_END:
+      slipdev_char_put(SLIP_ESC);
+      slipdev_char_put(SLIP_ESC_END);
+      break;
+    case SLIP_ESC:
+      slipdev_char_put(SLIP_ESC);
+      slipdev_char_put(SLIP_ESC_ESC);
+      break;
+    default:
+      slipdev_char_put(c);
+      break;
+    }
+  }
+  slipdev_char_put(SLIP_END);
+
+  return UIP_FW_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+/** 
+ * Poll the SLIP device for an available packet.
+ *
+ * This function will poll the SLIP device to see if a packet is
+ * available. It uses a buffer in which all avaliable bytes from the
+ * RS232 interface are read into. When a full packet has been read
+ * into the buffer, the packet is copied into the uip_buf buffer and
+ * the length of the packet is returned.
+ *
+ * \return The length of the packet placed in the uip_buf buffer, or
+ * zero if no packet is available.
+ */
+/*-----------------------------------------------------------------------------------*/
+u16_t
+slipdev_poll(void)
+{
+  u8_t c;
+  
+  while(slipdev_char_poll(&c)) {
+    switch(c) {
+    case SLIP_ESC:
+      lastc = c;
+      break;
+      
+    case SLIP_END:
+      lastc = c;
+      /* End marker found, we copy our input buffer to the uip_buf
+	 buffer and return the size of the packet we copied. */
+      memcpy(&uip_buf[UIP_LLH_LEN], slip_buf, len);
+      tmplen = len;
+      len = 0;
+      return tmplen;
+      
+    default:     
+      if(lastc == SLIP_ESC) {
+	lastc = c;
+	/* Previous read byte was an escape byte, so this byte will be
+	   interpreted differently from others. */
+	switch(c) {
+	case SLIP_ESC_END:
+	  c = SLIP_END;
+	  break;
+	case SLIP_ESC_ESC:
+	  c = SLIP_ESC;
+	  break;
+	}
+      } else {
+	lastc = c;
+      }
+      
+      slip_buf[len] = c;
+      ++len;
+      
+      if(len > UIP_BUFSIZE) {
+	len = 0;
+      }
+    
+      break;
+    }
+  }
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Initialize the SLIP module.
+ *
+ * This function does not initialize the underlying RS232 device, but
+ * only the SLIP part.
+ */ 
+/*-----------------------------------------------------------------------------------*/
+void
+slipdev_init(void)
+{
+  lastc = len = 0;
+}
+/*-----------------------------------------------------------------------------------*/
+
+/** @} */
+/** @} */
diff --git a/contiki/uip/slipdev.h b/contiki/uip/slipdev.h
new file mode 100644
index 0000000..f0114f6
--- /dev/null
+++ b/contiki/uip/slipdev.h
@@ -0,0 +1,88 @@
+/**
+ * \addtogroup slip
+ * @{
+ */
+
+/**
+ * \file
+ * SLIP header file.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * 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. 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: slipdev.h,v 1.2 2003/11/27 15:54:20 adamdunkels Exp $
+ *
+ */
+
+#ifndef __SLIPDEV_H__
+#define __SLIPDEV_H__
+
+#include "uip.h"
+
+/**
+ * Put a character on the serial device.
+ *
+ * This function is used by the SLIP implementation to put a character
+ * on the serial device. It must be implemented specifically for the
+ * system on which the SLIP implementation is to be run.
+ *
+ * \param c The character to be put on the serial device.
+ */
+void slipdev_char_put(u8_t c);
+
+/**
+ * Poll the serial device for a character.
+ *
+ * This function is used by the SLIP implementation to poll the serial
+ * device for a character. It must be implemented specifically for the
+ * system on which the SLIP implementation is to be run.
+ *
+ * The function should return immediately regardless if a character is
+ * available or not. If a character is available it should be placed
+ * at the memory location pointed to by the pointer supplied by the
+ * arguement c.
+ *
+ * \param c A pointer to a byte that is filled in by the function with
+ * the received character, if available.
+ *
+ * \retval 0 If no character is available.
+ * \retval Non-zero If a character is available.
+ */
+u8_t slipdev_char_poll(u8_t *c);
+
+void slipdev_init(void);
+u8_t slipdev_send(void);
+u16_t slipdev_poll(void);
+
+#endif /* __SLIPDEV_H__ */
+
+/** @} */
diff --git a/contiki/uip/tcpdump.c b/contiki/uip/tcpdump.c
new file mode 100644
index 0000000..226dda8
--- /dev/null
+++ b/contiki/uip/tcpdump.c
@@ -0,0 +1,254 @@
+
+#include "cc.h"
+#include "uip.h"
+
+#include <string.h>
+#include <stdio.h>
+
+ struct ip_hdr {
+  /* IP header. */
+   u8_t vhl,
+    tos,          
+     len[2],       
+     ipid[2],        
+     ipoffset[2],  
+     ttl,          
+     proto;     
+   u16_t ipchksum;
+   u8_t srcipaddr[4], 
+     destipaddr[4];
+ };
+
+#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
+
+struct tcpip_hdr {
+  /* IP header. */
+   u8_t vhl,
+    tos,          
+     len[2],       
+     ipid[2],        
+     ipoffset[2],  
+     ttl,          
+     proto;     
+   u16_t ipchksum;
+   u8_t srcipaddr[4], 
+     destipaddr[4];
+  /* 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];
+};
+
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ECHO       8     
+
+struct icmpip_hdr {
+  /* IP header. */
+   u8_t vhl,
+    tos,          
+     len[2],       
+     ipid[2],        
+     ipoffset[2],  
+     ttl,          
+     proto;     
+  u16_t ipchksum;
+  u8_t srcipaddr[4], 
+    destipaddr[4];
+  /* The ICMP and IP headers. */
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+  u16_t id, seqno;  
+};
+
+
+/* The UDP and IP headers. */
+struct udpip_hdr {
+  /* IP header. */
+   u8_t vhl,
+    tos,          
+     len[2],       
+     ipid[2],        
+     ipoffset[2],  
+     ttl,          
+     proto;     
+   u16_t ipchksum;
+  u8_t srcipaddr[4], 
+    destipaddr[4];
+  
+  /* UDP header. */
+  u16_t srcport,
+    destport;
+  u16_t udplen;
+  u16_t udpchksum;
+};
+
+#define ETHBUF    ((struct eth_hdr *)&uip_buf[0])
+#define IPBUF     ((struct ip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define UDPBUF  ((struct udpip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define TCPBUF  ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+
+/*---------------------------------------------------------------------------*/
+static void
+tcpflags(unsigned char flags, char *flagsstr)
+{
+  if(flags & TCP_FIN) {
+    *flagsstr++ = 'F';
+  }
+  if(flags & TCP_SYN) {
+    *flagsstr++ = 'S';
+  }
+  if(flags & TCP_RST) {
+    *flagsstr++ = 'R';
+  }
+  if(flags & TCP_ACK) {
+    *flagsstr++ = 'A';
+  }
+  if(flags & TCP_URG) {
+    *flagsstr++ = 'U';
+  }
+
+  *flagsstr = 0;
+}
+/*---------------------------------------------------------------------------*/
+static char * CC_FASTCALL 
+n(u16_t num, char *ptr)
+{
+  u16_t d;
+  u8_t a, f;
+
+  if(num == 0) {
+    *ptr = '0';
+    return ptr + 1;    
+  } else {
+    f = 0;
+    for(d = 10000; d >= 1; d /= 10) {
+      a = (num / d) % 10;
+      if(f == 1 || a > 0) {
+	*ptr = a + '0';
+	++ptr;
+	f = 1;
+      }
+    }
+  }
+  return ptr;
+}
+/*---------------------------------------------------------------------------*/
+static char * CC_FASTCALL 
+d(char *ptr)
+{
+  *ptr = '.';
+  return ptr + 1;
+}
+/*---------------------------------------------------------------------------*/
+static char * CC_FASTCALL
+s(char *str, char *ptr)
+{
+  strcpy(ptr, str);
+  return ptr + strlen(str);
+}
+/*---------------------------------------------------------------------------*/
+int
+tcpdump_print(char *buf, u16_t buflen)
+{
+  char flags[8];
+  if(IPBUF->proto == UIP_PROTO_ICMP) {
+    if(ICMPBUF->type == ICMP_ECHO) {
+      return s(" ping",
+	     n(IPBUF->destipaddr[3], d(
+	     n(IPBUF->destipaddr[2], d(	       
+	     n(IPBUF->destipaddr[1], d(	       
+	     n(IPBUF->destipaddr[0],
+             s(" ",
+	     n(IPBUF->srcipaddr[3], d(	       
+	     n(IPBUF->srcipaddr[2], d(	       
+	     n(IPBUF->srcipaddr[1], d(	       
+             n(IPBUF->srcipaddr[0],
+	     buf)))))))))))))))) - buf;
+	     
+      /*      return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d ping",
+		     IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
+		     IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
+		     IPBUF->destipaddr[0], IPBUF->destipaddr[1],
+		     IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/
+    } else if(ICMPBUF->type == ICMP_ECHO_REPLY) {
+      return s(" pong",
+	     n(IPBUF->destipaddr[3], d(
+	     n(IPBUF->destipaddr[2], d(	       
+	     n(IPBUF->destipaddr[1], d(	       
+	     n(IPBUF->destipaddr[0],
+             s(" ",
+	     n(IPBUF->srcipaddr[3], d(	       
+	     n(IPBUF->srcipaddr[2], d(	       
+	     n(IPBUF->srcipaddr[1], d(	       
+             n(IPBUF->srcipaddr[0],
+	     buf)))))))))))))))) - buf;
+      /*      return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d pong",
+		     IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
+		     IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
+		     IPBUF->destipaddr[0], IPBUF->destipaddr[1],
+		     IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/
+    }
+  } else if(IPBUF->proto == UIP_PROTO_UDP) {
+      return s(" UDP",
+	     n(htons(UDPBUF->destport), d(	       
+	     n(IPBUF->destipaddr[3], d(
+	     n(IPBUF->destipaddr[2], d(	       
+	     n(IPBUF->destipaddr[1], d(	       
+	     n(IPBUF->destipaddr[0],
+             s(" ",
+	     n(htons(UDPBUF->srcport), d(
+	     n(IPBUF->srcipaddr[3], d(	       
+	     n(IPBUF->srcipaddr[2], d(	       
+	     n(IPBUF->srcipaddr[1], d(	       
+             n(IPBUF->srcipaddr[0],
+	     buf)))))))))))))))))))) - buf;
+      /*    return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d UDP",
+		   IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
+		   IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
+		   htons(UDPBUF->srcport),
+		   IPBUF->destipaddr[0], IPBUF->destipaddr[1],
+		   IPBUF->destipaddr[2], IPBUF->destipaddr[3],
+		   htons(UDPBUF->destport));*/
+  } else if(IPBUF->proto == UIP_PROTO_TCP) {
+    tcpflags(TCPBUF->flags, flags);
+      return s(flags,
+             s(" ",
+	     n(htons(TCPBUF->destport), d(	       
+	     n(IPBUF->destipaddr[3], d(
+	     n(IPBUF->destipaddr[2], d(	       
+	     n(IPBUF->destipaddr[1], d(	       
+	     n(IPBUF->destipaddr[0],
+             s(" ",
+	     n(htons(TCPBUF->srcport), d(
+	     n(IPBUF->srcipaddr[3], d(	       
+	     n(IPBUF->srcipaddr[2], d(	       
+	     n(IPBUF->srcipaddr[1], d(	       
+             n(IPBUF->srcipaddr[0],
+	     buf))))))))))))))))))))) - buf;
+    /*    return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d %s",
+		   IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
+		   IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
+		   htons(TCPBUF->srcport),
+		   IPBUF->destipaddr[0], IPBUF->destipaddr[1],
+		   IPBUF->destipaddr[2], IPBUF->destipaddr[3],
+		   htons(TCPBUF->destport),
+		   flags);  */
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/uip/tcpdump.h b/contiki/uip/tcpdump.h
new file mode 100644
index 0000000..3d6eccb
--- /dev/null
+++ b/contiki/uip/tcpdump.h
@@ -0,0 +1,8 @@
+#ifndef __TCPDUMP_H__
+#define __TCPDUMP_H__
+
+#include "uip.h"
+
+int tcpdump_print(char *buf, u16_t buflen);
+
+#endif /* __TCPDUMP_H__ */
diff --git a/contiki/uip/tcpip.c b/contiki/uip/tcpip.c
new file mode 100644
index 0000000..4aef8c9
--- /dev/null
+++ b/contiki/uip/tcpip.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: tcpip.c,v 1.6 2005/02/27 09:44:33 adamdunkels Exp $
+ */
+#include "tcpip.h"
+
+#include "ek-service.h"
+
+#include "tcpip.h"
+
+#include "uip.h"
+#include "uip-fw.h"
+
+#include "timer.h"
+
+#include "packet-service.h"
+
+#include "uip-split.h"
+
+#include <string.h>
+
+ek_event_t tcpip_event;
+
+EK_SERVICE(packetservice, PACKET_SERVICE_NAME);
+
+/**
+ * \internal Structure for holding a TCP port and a process ID.
+ */
+struct listenport {
+  u16_t port;
+  ek_id_t id;
+};
+
+/*static struct tcpip_event_args ev_args;*/
+
+static struct timer periodic;
+
+static struct internal_state {
+  struct listenport listenports[UIP_LISTENPORTS];
+  ek_event_t event;
+  ek_id_t id;
+} s;
+
+enum {
+  TCP_POLL,
+  UDP_POLL
+};
+
+static unsigned char forwarding = 0;
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_POLLHANDLER(pollhandler);
+EK_PROCESS(proc, "TCP/IP stack", EK_PRIO_NORMAL,
+	   eventhandler, pollhandler, NULL);
+/*---------------------------------------------------------------------------*/
+EK_PROCESS_INIT(tcpip_init, arg)
+{
+  uip_init();
+  ek_start(&proc);
+  forwarding = 0;
+}
+/*---------------------------------------------------------------------------*/
+void
+tcpip_set_forwarding(unsigned char f)
+{
+  forwarding = f;
+}
+/*---------------------------------------------------------------------------*/
+void
+tcpip_input(void)
+{
+  if(uip_len > 0) {
+    if(forwarding) {
+      if(uip_fw_forward() == 0) {
+	uip_input();
+	if(uip_len > 0) {
+#if UIP_CONF_TCP_SPLIT
+	  uip_split_output();
+#else
+	  tcpip_output();
+#endif
+	}
+      }
+    } else {
+      uip_input();
+      if(uip_len > 0) {
+#if UIP_CONF_TCP_SPLIT
+	uip_split_output();
+#else
+	tcpip_output();
+#endif
+      }
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+tcpip_output(void)
+{
+  struct packet_service_state *state;
+  u16_t hdrlen, datalen;  
+  
+  state = (struct packet_service_state *)ek_service_state(&packetservice);
+
+  if(state != NULL &&
+     state->version == PACKET_SERVICE_VERSION) {
+
+    hdrlen = UIP_TCPIP_HLEN;
+    if(uip_len < UIP_TCPIP_HLEN) {
+      hdrlen = uip_len;
+      datalen = 0;
+    } else {
+      datalen = uip_len - UIP_TCPIP_HLEN;
+    }
+    
+    state->output(&uip_buf[UIP_LLH_LEN], hdrlen, uip_appdata, datalen);
+  }
+}
+/*---------------------------------------------------------------------------*/
+struct uip_conn *
+tcp_connect(u16_t *ripaddr, u16_t port, void *appstate)
+{
+  struct uip_conn *c;
+  
+  c = uip_connect(ripaddr, port);
+  if(c == NULL) {
+    return NULL;
+  }
+
+  ((struct tcpip_uipstate *)(c->appstate))->id = EK_PROC_ID(EK_CURRENT());
+  ((struct tcpip_uipstate *)(c->appstate))->state = appstate;
+
+  ek_post(s.id, TCP_POLL, c);
+  
+  return c;
+}
+/*---------------------------------------------------------------------------*/
+void
+tcp_unlisten(u16_t port)
+{
+  static unsigned char i;
+  struct listenport *l;
+
+  l = s.listenports;
+  for(i = 0; i < UIP_LISTENPORTS; ++i) {
+    if(l->port == port &&
+       l->id == EK_PROC_ID(EK_CURRENT())) {
+      l->port = 0;      
+      uip_unlisten(port);
+      break;
+    }
+    ++l;
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+tcp_listen(u16_t port)
+{
+  static unsigned char i;
+  struct listenport *l;
+
+  l = s.listenports;
+  for(i = 0; i < UIP_LISTENPORTS; ++i) {
+    if(l->port == 0) {
+      l->port = port;
+      l->id = EK_PROC_ID(EK_CURRENT());
+      uip_listen(port);
+      break;
+    }
+    ++l;
+  }
+}
+/*---------------------------------------------------------------------------*/
+void
+tcp_markconn(struct uip_conn *conn,
+             void *appstate)
+{
+  register struct tcpip_uipstate *s;
+
+  s = (struct tcpip_uipstate *)conn->appstate;
+  s->id = ek_current->id;
+  s->state = appstate;
+}
+/*---------------------------------------------------------------------------*/
+struct uip_udp_conn *
+udp_new(u16_t *ripaddr, u16_t port, void *appstate)
+{
+  struct uip_udp_conn *c;
+  struct tcpip_uipstate *s;
+  
+  c = uip_udp_new(ripaddr, port);
+  if(c == NULL) {
+    return NULL;
+  }
+
+  s = (struct tcpip_uipstate *)c->appstate;
+  s->id = EK_PROC_ID(EK_CURRENT());
+  s->state = appstate;
+
+  return c;
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  static unsigned char i;
+  register struct listenport *l;
+  ek_id_t id;
+  struct internal_state *state;
+  
+  switch(ev) {
+  case EK_EVENT_INIT:       
+    for(i = 0; i < UIP_LISTENPORTS; ++i) {
+      s.listenports[i].port = 0;
+    }
+    s.id = EK_PROC_ID(EK_CURRENT());
+    tcpip_event = s.event = ek_alloc_event();
+    timer_set(&periodic, CLOCK_SECOND/2);  
+    break;
+  case EK_EVENT_REPLACE:
+    memcpy(&s, data, sizeof(s));
+    arg_free(data);
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    state = (struct internal_state *)arg_alloc(sizeof(s));
+    /* Copy state */
+    memcpy(state, &s, sizeof(s)); 
+    ek_replace((struct ek_proc *)data, state);
+    break;
+    
+  case EK_EVENT_EXITED:
+    id = (ek_id_t)data;
+    l = s.listenports;
+    for(i = 0; i < UIP_LISTENPORTS; ++i) {
+      if(l->id == id) {
+	uip_unlisten(l->port);
+	l->port = 0;
+	l->id = EK_ID_NONE;
+      }
+      ++l;
+    }
+    /*    for(i = 0; i < UIP_CONNS; ++i) {
+      if(((struct tcpip_uipstate *)uip_conns[i].appstate)->id == id) {
+      ((struct tcpip_uipstate *)uip_conns[i].appstate)->id = EK_ID_NONE;
+	uip_conns[i].tcpstateflags = CLOSED;
+      }
+      }*/
+    {
+      register struct uip_conn *cptr;
+     
+      for(cptr = &uip_conns[0]; cptr < &uip_conns[UIP_CONNS]; ++cptr) {
+	if(((struct tcpip_uipstate *)cptr->appstate)->id == id) {
+	  ((struct tcpip_uipstate *)cptr->appstate)->id = EK_ID_NONE;
+	  cptr->tcpstateflags = CLOSED;
+	}
+      
+      }
+      
+    }
+#if UIP_UDP
+    {
+      register struct uip_udp_conn *cptr;
+      for(cptr = &uip_udp_conns[0];
+	  cptr < &uip_udp_conns[UIP_UDP_CONNS]; ++cptr) {
+	if(((struct tcpip_uipstate *)cptr->appstate)->id == id) {
+	  cptr->lport = 0;
+	}
+      }
+      
+    }
+    /*    for(i = 0; i < UIP_UDP_CONNS; ++i) {
+      if(((struct tcpip_uipstate *)uip_udp_conns[i].appstate)->id == id) {
+	uip_udp_conns[i].lport = 0;
+      }
+      }*/
+#endif /* UIP_UDP */
+    break;
+  case TCP_POLL:
+    if(data != NULL) {
+      uip_poll_conn(data);
+      if(uip_len > 0) {
+	tcpip_output();
+      }
+    }
+    break;
+  case UDP_POLL:
+    if(data != NULL) {
+      uip_udp_periodic_conn(data);
+      if(uip_len > 0) {
+	tcpip_output();
+      }
+    }
+    break;
+  };
+}
+/*---------------------------------------------------------------------------*/
+void
+tcpip_poll_udp(struct uip_udp_conn *conn)
+{
+  ek_post(s.id, UDP_POLL, conn);
+}
+/*---------------------------------------------------------------------------*/
+void
+tcpip_poll_tcp(struct uip_conn *conn)
+{
+  ek_post(s.id, TCP_POLL, conn);
+}
+/*---------------------------------------------------------------------------*/
+void
+tcpip_uipcall(void)     
+{
+  register struct tcpip_uipstate *ts;
+  static unsigned char i;
+  register struct listenport *l;
+
+  if(uip_conn != NULL) {
+    ts = (struct tcpip_uipstate *)uip_conn->appstate;
+  } else {
+    ts = (struct tcpip_uipstate *)uip_udp_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()) {
+    l = &s.listenports[0];
+    for(i = 0; i < UIP_LISTENPORTS; ++i) {
+      if(l->port == uip_conn->lport &&
+	 l->id != EK_ID_NONE) {
+	ts->id = l->id;
+	ts->state = NULL;
+	break;
+      }
+      ++l;
+    }
+  }
+
+  ek_post_synch(ts->id, s.event, ts->state);
+}
+/*---------------------------------------------------------------------------*/
+EK_POLLHANDLER(pollhandler)
+{
+  static unsigned char i;
+  
+  /* Check the clock so see if we should call the periodic uIP
+     processing. */
+  if(timer_expired(&periodic)) {
+    timer_restart(&periodic);
+    for(i = 0; i < UIP_CONNS; ++i) {
+      uip_periodic(i);
+      if(uip_len > 0) {
+	tcpip_output();
+	/*	uip_fw_output();*/
+      }
+    }
+    
+    for(i = 0; i < UIP_UDP_CONNS; i++) {
+      uip_udp_periodic(i);
+      if(uip_len > 0) {
+	tcpip_output();
+	/*	uip_fw_output();*/
+      }
+    }
+    uip_fw_periodic();
+  }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/uip/tcpip.h b/contiki/uip/tcpip.h
new file mode 100644
index 0000000..dd57cbc
--- /dev/null
+++ b/contiki/uip/tcpip.h
@@ -0,0 +1,282 @@
+/**
+ * \defgroup tcpip The Contiki/uIP interface
+ * @{
+ *
+ * TCP/IP support in Contiki is implemented using the uIP TCP/IP
+ * stack. For sending and receiving data, Contiki uses the functions
+ * provided by the uIP module, but Contiki adds a set of functions for
+ * connection management. The connection management functions make
+ * sure that the uIP TCP/IP connections are connected to the correct
+ * process.
+ *
+ * Contiki also includes an optional protosocket library that provides
+ * an API similar to the BSD socket API.
+ *
+ * \sa \ref uip "The uIP TCP/IP stack"
+ * \sa \ref psock "Protosockets library"
+ *
+ */
+
+/**
+ * \file
+ * Header for the Contiki/uIP interface.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ */
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: tcpip.h,v 1.6 2005/02/22 22:34:46 adamdunkels Exp $
+ */
+#ifndef __TCPIP_H__
+#define __TCPIP_H__
+
+#include "ek.h"
+
+
+
+
+struct uip_conn;
+
+struct tcpip_uipstate {
+  ek_id_t id;  
+  void *state;
+};
+
+#define UIP_APPCALL tcpip_uipcall
+#define UIP_UDP_APPCALL tcpip_uipcall
+#define UIP_APPSTATE_SIZE sizeof(struct tcpip_uipstate)
+
+#include "uip.h"
+
+EK_PROCESS_INIT(tcpip_init, arg);
+     
+void tcpip_uipcall(void);
+
+/**
+ * Mark a TCP connection with the current process.
+ *
+ * This function ties a TCP connection with the current process. Each
+ * TCP connection must be tied to a process in order for the process
+ * to be able to receive and send data. Additionally, this function
+ * can add a pointer with connection state to the connection.
+ *
+ * \param conn A pointer to the TCP connection.
+ *
+ * \param appstate An opaque pointer that will be passed to the
+ * process whenever an event occurs on the connection.
+ *
+ */
+void tcp_markconn(struct uip_conn *conn,
+		  void *appstate);
+
+/**
+ * Open a TCP port.
+ *
+ * This function opens a TCP port for listening. When a TCP connection
+ * request occurs for the port, the process will be sent a tcpip_event
+ * with the new connection request.
+ *
+ * \note Port numbers must always be given in network byte order. The
+ * functions HTONS() and htons() can be used to convert port numbers
+ * from host byte order to network byte order.
+ *
+ * Example
+ \code
+ static void init_ports(void) {
+   tcp_listen(HTONS(80));
+   tcp_listen(HTONS(81));
+ }
+ \endcode
+ *
+ * \param port The port number in network byte order. 
+ *
+ */
+void tcp_listen(u16_t port);
+
+/**
+ * Close a listening TCP port.
+ *
+ * This function closes a listening TCP port.
+ *
+ * \note Port numbers must always be given in network byte order. The
+ * functions HTONS() and htons() can be used to convert port numbers
+ * from host byte order to network byte order.
+ *
+ * Example
+ \code
+ static void close_ports(void) {
+   tcp_unlisten(HTONS(80));
+   tcp_unlisten(HTONS(81));
+ }
+ \endcode
+ *
+ * \param port The port number in network byte order. 
+ *
+ */
+void tcp_unlisten(u16_t port);
+
+/**
+ * Open a TCP connection to the specified IP address and port.
+ *
+ * This function opens a TCP connection to the specified port at the
+ * host specified with an IP address. Additionally, an opaque pointer
+ * can be attached to the connection. This pointer will be sent
+ * together with uIP events to the process.
+ *
+ * \note The port number must be provided in network byte order so a
+ * conversion with HTONS() usually is necessary.
+ *
+ * \note This function will only create the connection. The connection
+ * is not opened directly. uIP will try to open the connection the
+ * next time the uIP stack is scheduled by Contiki.
+ *
+ * Example:
+ \code
+ static struct uip_conn *conn;
+ 
+ EK_EVENTHANDLER(eventhandler, ev, data)
+ {
+   u16_t addr[2];
+   
+   if(ev == EK_EVENT_INIT) {
+     uip_ipaddr(addr, 192,168,1,1);
+     conn = tcp_connect(addr, HTONS(80), NULL);
+   }
+ }
+ \endcode
+ *
+ * \param ripaddr Pointer to the IP address of the remote host.
+ * \param port Port number in network byte order.
+ * \param appstate Pointer to application defined data.
+ *
+ * \return A pointer to the newly created connection, or NULL if
+ * memory could not be allocated for the connection.
+ *
+ */
+struct uip_conn *tcp_connect(u16_t *ripaddr, u16_t port,
+			     void *appstate);
+
+/**
+ * Create a new UDP connection.
+ *
+ * This function creates a new UDP connection with the specified
+ * remote endpoint.
+ *
+ * \note The port number must be provided in network byte order so a
+ * conversion with HTONS() usually is necessary.
+ *
+ * \sa udp_bind()
+ *
+ * \param ripaddr Pointer to the IP address of the remote host.
+ * \param port Port number in network byte order.
+ * \param appstate Pointer to application defined data.
+ *
+ * \return A pointer to the newly created connection, or NULL if
+ * memory could not be allocated for the connection.
+ */
+struct uip_udp_conn *udp_new(u16_t *ripaddr, u16_t port,
+			     void *appstate);
+
+/**
+ * Bind a UDP connection to a local port.
+ *
+ * This function binds a UDP conncetion to a specified local port.
+ *
+ * When a connction is created with udp_new(), it gets a local port number assigned automatically. If the application needs to bind the connection to a specified local port, this function should be used.
+ *
+ * \note The port number must be provided in network byte order so a
+ * conversion with HTONS() usually is necessary.
+ *
+ * Example
+ \code
+  EK_EVENTHANDLER(eventhandler, ev, data)
+  {
+    u16_t addr[2];
+  
+    if(ev == EK_EVENT_INIT) {
+      uip_ipaddr(addr, 255,255,255,255);
+      conn = udp_new(addr, HTONS(PORT), NULL);
+      if(conn != NULL) {
+        udp_bind(conn, HTONS(PORT));
+      }
+    }
+  }
+ \endcode
+ *
+ * \param conn A pointer to the UDP connection that is to be bound.
+ * \param port The port number in network byte order to which to bind
+ * the connection.
+ */
+#define udp_bind(conn, port) uip_udp_bind(conn, port)
+
+/**
+ * The uIP event.
+ *
+ * This event is posted to a process whenever a uIP event has occured.
+ */
+extern ek_event_t tcpip_event;
+
+
+
+void tcpip_set_forwarding(unsigned char f);
+void tcpip_input(void);
+void tcpip_output(void);
+
+
+/**
+ * Cause a specified TCP connection to be polled.
+ *
+ * This function causes uIP to poll the specified TCP connection. The
+ * function is used when the application has data that is to be sent
+ * immediately and do not wish to wait for the periodic uIP polling
+ * mechanism.
+ *
+ * \param conn A pointer to the TCP connection that should be polled.
+ *
+ */
+void tcpip_poll_tcp(struct uip_conn *conn);
+
+/**
+ * Cause a specified UDP connection to be polled.
+ *
+ * This function causes uIP to poll the specified UDP connection. The
+ * function is used when the application has data that is to be sent
+ * immediately and do not wish to wait for the periodic uIP polling
+ * mechanism.
+ *
+ * \param conn A pointer to the UDP connection that should be polled.
+ *
+ */
+void tcpip_poll_udp(struct uip_udp_conn *conn);
+
+#endif /* __TCPIP_H__ */
diff --git a/contiki/uip/uip-fw-service.c b/contiki/uip/uip-fw-service.c
new file mode 100644
index 0000000..4898b42
--- /dev/null
+++ b/contiki/uip/uip-fw-service.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-fw-service.c,v 1.4 2005/02/07 07:06:59 adamdunkels Exp $
+ */
+
+#include "packet-service.h"
+
+#include "uip-fw.h"
+
+static void output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen);
+
+static const struct packet_service_state state =
+  {
+    PACKET_SERVICE_VERSION,
+    output
+  };
+
+EK_EVENTHANDLER(eventhandler, ev, data);
+EK_POLLHANDLER(pollhandler);
+EK_PROCESS(proc, PACKET_SERVICE_NAME ": IP forwarding", EK_PRIO_NORMAL,
+	   eventhandler, NULL, (void *)&state);
+
+/*---------------------------------------------------------------------------*/
+EK_PROCESS_INIT(uip_fw_service_init, arg)
+{  
+  ek_service_start(PACKET_SERVICE_NAME, &proc);
+}
+/*---------------------------------------------------------------------------*/
+static void
+output(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen)
+{
+  uip_fw_output();
+}
+/*---------------------------------------------------------------------------*/
+EK_EVENTHANDLER(eventhandler, ev, data)
+{
+  switch(ev) {
+  case EK_EVENT_INIT:
+  case EK_EVENT_REPLACE:
+    break;
+  case EK_EVENT_REQUEST_REPLACE:
+    ek_replace((struct ek_proc *)data, NULL);
+    LOADER_UNLOAD();
+    break;
+  case EK_EVENT_REQUEST_EXIT:
+    ek_exit();
+    LOADER_UNLOAD();
+    break;
+  default:
+    break;
+  }
+
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/uip/uip-fw-service.h b/contiki/uip/uip-fw-service.h
new file mode 100644
index 0000000..92699fb
--- /dev/null
+++ b/contiki/uip/uip-fw-service.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-fw-service.h,v 1.2 2004/09/12 20:24:56 adamdunkels Exp $
+ */
+#ifndef __UIP_FW_SERVICE_H__
+#define __UIP_FW_SERVICE_H__
+
+#include "contiki.h"
+
+EK_PROCESS_INIT(uip_fw_service_init, arg);
+
+#endif /* __UIP_FW_SERVICE_H__ */
diff --git a/contiki/uip/uip-fw.c b/contiki/uip/uip-fw.c
new file mode 100644
index 0000000..3ba8baa
--- /dev/null
+++ b/contiki/uip/uip-fw.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-fw.c,v 1.9 2005/02/23 22:40:40 oliverschmidt Exp $
+ */
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uipfw uIP packet forwarding
+ * @{
+ *
+ */
+
+/**
+ * \file
+ * uIP packet forwarding.
+ * \author Adam Dunkels <adam@sics.se>
+ *
+ * This file implements a number of simple functions which do packet
+ * forwarding over multiple network interfaces with uIP.
+ *
+ */
+
+#include "uip.h"
+#include "uip_arch.h"
+#include "uip-fw.h"
+#include "uip-conf.h"
+
+#include <string.h> /* for memcpy() */
+
+/**
+ * \internal
+ * The list of registered network interfaces.
+ */
+static struct uip_fw_netif *netifs = NULL;
+
+/**
+ * \internal
+ * A pointer to the default network interface.
+ */
+static struct uip_fw_netif *defaultnetif = NULL;
+
+struct tcpip_hdr {
+  /* IP header. */
+  u8_t vhl,
+    tos;     
+  u16_t len,
+    ipid,        
+    ipoffset;
+  u8_t ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  
+  /* 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];
+};
+
+struct icmpip_hdr {
+  /* IP header. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+  u16_t id, seqno;
+  u8_t payload[1];
+};
+
+/**
+ * \internal
+ * ICMP ECHO type definition.
+ */
+#define ICMP_ECHO 8 
+
+/**
+ * \internal
+ * ICMP TIME-EXCEEDED type definition.
+ */
+#define ICMP_TE 11 
+
+/**
+ * \internal
+ * Pointer to the TCP/IP headers of the packet in the uip_buf buffer.
+ */
+#define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+/**
+ * \internal
+ * Pointer to the ICMP/IP headers of the packet in the uip_buf buffer.
+ */
+#define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+/**
+ * \internal
+ * Certain fields of an IP packet that are used for identifying
+ * duplicate packets.
+ */
+struct fwcache_entry {
+  u16_t timer;
+  
+  u16_t len, offset, ipid;
+  u16_t srcipaddr[2];
+  u16_t destipaddr[2];
+  u16_t payload[2];
+  u8_t proto;
+};
+
+/**
+ * \internal
+ * The number of packets to remember when looking for duplicates.
+ */
+#ifdef UIP_CONF_FWCACHE_SIZE
+#define FWCACHE_SIZE UIP_CONF_FWCACHE_SIZE
+#else
+#define FWCACHE_SIZE 2
+#endif
+
+
+/**
+ * \internal
+ * A cache of packet header fields which are used for
+ * identifying duplicate packets.
+ */
+static struct fwcache_entry fwcache[FWCACHE_SIZE];
+
+/**
+ * \internal
+ * The time that a packet cache is active.
+ */
+#define FW_TIME 20
+
+/*------------------------------------------------------------------------------*/
+/**
+ * Initialize the uIP packet forwarding module.
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_init(void)
+{
+  defaultnetif = netifs = NULL;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Check if an IP address is within the network defined by an IP
+ * address and a netmask.
+ *
+ * \param ipaddr The IP address to be checked.
+ * \param netipaddr The IP address of the network.
+ * \param netmask The netmask of the network.
+ *
+ * \return Non-zero if IP address is in network, zero otherwise.
+ */
+/*------------------------------------------------------------------------------*/
+static unsigned char
+ipaddr_maskcmp(u16_t *ipaddr, u16_t *netipaddr, u16_t *netmask)
+{
+  return (ipaddr[0] & netmask [0]) == (netipaddr[0] & netmask[0]) &&
+    (ipaddr[1] & netmask[1]) == (netipaddr[1] & netmask[1]);
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Send out an ICMP TIME-EXCEEDED message.
+ *
+ * This function replaces the packet in the uip_buf buffer with the
+ * ICMP packet.
+ */
+/*------------------------------------------------------------------------------*/
+static void
+time_exceeded(void)
+{
+  u16_t tmp16;
+
+  /* We don't send out ICMP errors for ICMP messages. */
+  if(ICMPBUF->proto == UIP_PROTO_ICMP) {
+    uip_len = 0;
+    return;
+  }
+  /* Copy fields from packet header into payload of this ICMP packet. */
+  memcpy(&(ICMPBUF->payload[0]), ICMPBUF, 28);
+
+  /* Set the ICMP type and code. */
+  ICMPBUF->type = ICMP_TE;
+  ICMPBUF->icode = 0;
+
+  /* Calculate the ICMP checksum. */
+  ICMPBUF->icmpchksum = 0;
+  ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36);
+
+  /* Set the IP destination address to be the source address of the
+     original packet. */
+  tmp16= BUF->destipaddr[0];
+  BUF->destipaddr[0] = BUF->srcipaddr[0];
+  BUF->srcipaddr[0] = tmp16;
+  tmp16 = BUF->destipaddr[1];
+  BUF->destipaddr[1] = BUF->srcipaddr[1];
+  BUF->srcipaddr[1] = tmp16;
+
+  /* Set our IP address as the source address. */
+  BUF->srcipaddr[0] = uip_hostaddr[0];
+  BUF->srcipaddr[1] = uip_hostaddr[1];
+
+  /* The size of the ICMP time exceeded packet is 36 + the size of the
+     IP header (20) = 56. */
+  uip_len = 56;
+  ICMPBUF->len[0] = 0;
+  ICMPBUF->len[1] = uip_len;
+
+  /* Fill in the other fields in the IP header. */
+  ICMPBUF->vhl = 0x45;
+  ICMPBUF->tos = 0;
+  ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0;
+  ICMPBUF->ttl  = UIP_TTL;
+  ICMPBUF->proto = UIP_PROTO_ICMP;
+  
+  /* Calculate IP checksum. */
+  ICMPBUF->ipchksum = 0;
+  ICMPBUF->ipchksum = ~(uip_ipchksum());
+
+
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Register a packet in the forwarding cache so that it won't be
+ * forwarded again.
+ */
+/*------------------------------------------------------------------------------*/
+static void
+fwcache_register(void)
+{
+  struct fwcache_entry *fw;
+  int i, oldest;
+
+  oldest = FW_TIME;
+  fw = NULL;
+  
+  /* Find the oldest entry in the cache. */
+  for(i = 0; i < FWCACHE_SIZE; ++i) {
+    if(fwcache[i].timer == 0) {
+      fw = &fwcache[i];
+      break;
+    } else if(fwcache[i].timer <= oldest) {
+      fw = &fwcache[i];
+      oldest = fwcache[i].timer;
+    }
+  }
+
+  fw->timer = FW_TIME;
+  fw->len = BUF->len;
+  fw->offset = BUF->ipoffset;
+  fw->ipid = BUF->ipid;
+  fw->srcipaddr[0] = BUF->srcipaddr[0];
+  fw->srcipaddr[1] = BUF->srcipaddr[1];
+  fw->destipaddr[0] = BUF->destipaddr[0];
+  fw->destipaddr[1] = BUF->destipaddr[1];
+  fw->payload[0] = BUF->srcport;
+  fw->payload[1] = BUF->destport;
+  fw->proto = BUF->proto;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * \internal
+ * Find a network interface for the IP packet in uip_buf.
+ */
+/*------------------------------------------------------------------------------*/
+static struct uip_fw_netif *
+find_netif(void)
+{
+  struct uip_fw_netif *netif;
+  
+  /* Walk through every network interface to check for a match. */
+  for(netif = netifs; netif != NULL; netif = netif->next) {
+    if(ipaddr_maskcmp(BUF->destipaddr, netif->ipaddr,
+		      netif->netmask)) {
+      /* If there was a match, we break the loop. */
+      return netif;
+    }
+  }
+  
+  /* If no matching netif was found, we use default netif. */
+  return defaultnetif;  
+}    
+/*------------------------------------------------------------------------------*/
+/**
+ * Output an IP packet on the correct network interface.
+ *
+ * The IP packet should be present in the uip_buf buffer and its
+ * length in the global uip_len variable.
+ *
+ * \retval UIP_FW_ZEROLEN Indicates that a zero-length packet
+ * transmission was attempted and that no packet was sent.
+ *
+ * \retval UIP_FW_NOROUTE No suitable network interface could be found
+ * for the outbound packet, and the packet was not sent.
+ *
+ * \return The return value from the actual network interface output
+ * function is passed unmodified as a return value.
+ */
+/*------------------------------------------------------------------------------*/
+u8_t
+uip_fw_output(void)
+{
+  struct uip_fw_netif *netif;
+
+  if(uip_len == 0) {
+    return UIP_FW_ZEROLEN;
+  }
+
+#if UIP_BROADCAST
+  /* Link local broadcasts go out on all interfaces. */
+  if(BUF->proto == UIP_PROTO_UDP &&
+     BUF->destipaddr[0] == 0xffff &&
+     BUF->destipaddr[1] == 0xffff) {
+    for(netif = netifs; netif != NULL; netif = netif->next) {
+      netif->output();
+    }
+    return UIP_FW_OK;
+  }
+#endif /* UIP_BROADCAST */  
+
+  
+  netif = find_netif();
+  /*  printf("uip_fw_output: netif %p ->output %p len %d\n", netif,
+	 netif->output,
+	 uip_len);*/
+
+  if(netif == NULL) {
+    return UIP_FW_NOROUTE;
+  }
+  /* If we now have found a suitable network interface, we call its
+     output function to send out the packet. */
+  fwcache_register();
+  return netif->output();
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Forward an IP packet in the uip_buf buffer.
+ *
+ * 
+ *
+ * \return UIP_FW_FORWARDED if the packet was forwarded, UIP_FW_LOCAL if
+ * the packet should be processed locally.
+ */
+/*------------------------------------------------------------------------------*/
+u8_t
+uip_fw_forward(void)
+{
+  struct uip_fw_netif *netif;
+  struct fwcache_entry *fw;
+
+  /* First check if the packet is destined for ourselves and return 0
+     to indicate that the packet should be processed locally. */
+  if(BUF->destipaddr[0] == uip_hostaddr[0] &&
+     BUF->destipaddr[1] == uip_hostaddr[1]) {
+    return UIP_FW_LOCAL;
+  }
+
+#if UIP_BROADCAST
+  if(BUF->proto == UIP_PROTO_UDP &&
+     BUF->destipaddr[0] == 0xffff &&
+     BUF->destipaddr[1] == 0xffff) {
+    return UIP_FW_LOCAL;
+  }
+#endif /* UIP_BROADCAST */  
+
+  /* If we use ping IP address configuration, and our IP address is
+     not yet configured, we should intercept all ICMP echo packets. */
+#if UIP_PINGADDRCONF
+  if((uip_hostaddr[0] | uip_hostaddr[1]) == 0 &&
+     BUF->proto == UIP_PROTO_ICMP &&
+     ICMPBUF->type == ICMP_ECHO) {
+    return UIP_FW_LOCAL;
+  }
+#endif /* UIP_PINGADDRCONF */
+
+  /* Check if the packet is in the forwarding cache already, and if so
+     we drop it. */
+
+  for(fw = fwcache; fw <= &fwcache[FWCACHE_SIZE]; ++fw) {
+    if(fw->timer != 0 &&
+       fw->len == BUF->len &&
+       fw->offset == BUF->ipoffset &&
+       fw->ipid == BUF->ipid &&      
+       fw->srcipaddr[0] == BUF->srcipaddr[0] &&
+       fw->srcipaddr[1] == BUF->srcipaddr[1] &&
+       fw->destipaddr[0] == BUF->destipaddr[0] &&
+       fw->destipaddr[1] == BUF->destipaddr[1] &&
+       fw->proto == BUF->proto &&
+       fw->payload[0] == BUF->srcport &&
+       fw->payload[1] == BUF->destport) {
+      /* Drop packet. */
+      return UIP_FW_FORWARDED;
+    }       
+  }
+
+  netif = find_netif();
+
+  /* Decrement the TTL (time-to-live) value in the IP header */
+  BUF->ttl = BUF->ttl - 1;
+  
+  /* Update the IP checksum. */
+  if(BUF->ipchksum >= HTONS(0xffff - 0x0100)) {
+    BUF->ipchksum = BUF->ipchksum + HTONS(0x0100) + 1;
+  } else {
+    BUF->ipchksum = BUF->ipchksum + HTONS(0x0100);
+  }
+  
+  /* If the TTL reaches zero we procude an ICMP time exceeded message
+     in the uip_buf buffer and forward that packet back to the sender
+     of the packet. */
+  if(BUF->ttl == 0) {    
+    time_exceeded();
+    netif = find_netif();
+  }
+  
+  /* If we now have found a suitable network interface, we call its
+     output function to send out the packet. */
+  if(netif != NULL && uip_len > 0) {
+    uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN];
+    fwcache_register();
+    netif->output();
+  }
+
+  /* Return non-zero to indicate that the packet was forwarded and that no
+     other processing should be made. */
+  return UIP_FW_FORWARDED;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Register a network interface with the forwarding module.
+ *
+ * \param netif A pointer to the network interface that is to be
+ * registered.  
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_register(struct uip_fw_netif *netif)
+{
+  netif->next = netifs;
+  netifs = netif;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Register a default network interface.
+ *
+ * All packets that don't go out on any of the other interfaces will
+ * be routed to the default interface.
+ *
+ * \param netif A pointer to the network interface that is to be
+ * registered.  
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_default(struct uip_fw_netif *netif)
+{
+  defaultnetif = netif;
+}
+/*------------------------------------------------------------------------------*/
+/**
+ * Perform periodic processing.
+ */
+/*------------------------------------------------------------------------------*/
+void
+uip_fw_periodic(void)
+{
+  struct fwcache_entry *fw;
+  for(fw = fwcache; fw <= &fwcache[FWCACHE_SIZE]; ++fw) {
+    if(fw->timer > 0) {
+      --fw->timer;
+    }    
+  }
+}
+/*------------------------------------------------------------------------------*/
diff --git a/contiki/uip/uip-fw.h b/contiki/uip/uip-fw.h
new file mode 100644
index 0000000..d7c0a98
--- /dev/null
+++ b/contiki/uip/uip-fw.h
@@ -0,0 +1,176 @@
+/**
+ * \addtogroup uipfw
+ * @{
+ */
+
+/**
+ * \file
+ * uIP packet forwarding header file.
+ * \author Adam Dunkels <adam@sics.se>
+ */
+
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-fw.h,v 1.7 2005/02/07 07:06:31 adamdunkels Exp $
+ */
+#ifndef __UIP_FW_H__
+#define __UIP_FW_H__
+
+#include "uip.h"
+
+/**
+ * Representation of a uIP network interface.
+ */
+struct uip_fw_netif {
+  struct uip_fw_netif *next;  /**< Pointer to the next interface when
+				 linked in a list. */
+  u16_t ipaddr[2];            /**< The IP address of this interface. */
+  u16_t netmask[2];           /**< The netmask of the interface. */
+  u8_t (* output)(void);
+                              /**< A pointer to the function that
+				 sends a packet. */
+};
+
+/**
+ * Intantiating macro for a uIP network interface.
+ *
+ * Example:
+ \code
+ struct uip_fw_netif slipnetif =
+   {UIP_FW_NETIF(192,168,76,1, 255,255,255,0, slip_output)};
+ \endcode
+ * \param ip1,ip2,ip3,ip4 The IP address of the network interface.
+ *
+ * \param nm1,nm2,nm3,nm4 The netmask of the network interface.
+ *
+ * \param outputfunc A pointer to the output function of the network interface.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_NETIF(ip1,ip2,ip3,ip4, nm1,nm2,nm3,nm4, outputfunc) \
+        NULL, \
+	{HTONS((ip1 << 8) | ip2), HTONS((ip3 << 8) | ip4)}, \
+	{HTONS((nm1 << 8) | nm2), HTONS((nm3 << 8) | nm4)}, \
+        outputfunc
+
+/**
+ * Set the IP address of a network interface.
+ *
+ * \param netif A pointer to the uip_fw_netif structure for the network interface.
+ *
+ * \param addr A pointer to an IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_fw_setipaddr(netif, addr) \
+        do { (netif)->ipaddr[0] = ((u16_t *)(addr))[0]; \
+             (netif)->ipaddr[1] = ((u16_t *)(addr))[1]; } while(0)
+/**
+ * Set the netmask of a network interface.
+ *
+ * \param netif A pointer to the uip_fw_netif structure for the network interface.
+ *
+ * \param addr A pointer to an IP address representing the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_fw_setnetmask(netif, addr) \
+        do { (netif)->netmask[0] = ((u16_t *)(addr))[0]; \
+             (netif)->netmask[1] = ((u16_t *)(addr))[1]; } while(0)
+
+void uip_fw_init(void);
+u8_t uip_fw_forward(void);
+u8_t uip_fw_output(void);
+void uip_fw_register(struct uip_fw_netif *netif);
+void uip_fw_default(struct uip_fw_netif *netif);
+void uip_fw_periodic(void);
+
+
+/**
+ * A non-error message that indicates that a packet should be
+ * processed locally.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_LOCAL     0
+
+/**
+ * A non-error message that indicates that something went OK.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_OK        0
+
+/**
+ * A non-error message that indicates that a packet was forwarded.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_FORWARDED 1
+
+/**
+ * A non-error message that indicates that a zero-length packet
+ * transmission was attempted, and that no packet was sent.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_ZEROLEN   2
+
+/**
+ * An error message that indicates that a packet that was too large
+ * for the outbound network interface was detected.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_TOOLARGE  3
+
+/**
+ * An error message that indicates that no suitable interface could be
+ * found for an outbound packet.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_NOROUTE   4
+
+/**
+ * An error message that indicates that a packet that should be
+ * forwarded or output was dropped.
+ *
+ * \hideinitializer
+ */
+#define UIP_FW_DROPPED   5
+
+
+#endif /* __UIP_FW_H__ */
+
+/** @} */
diff --git a/contiki/uip/uip-split.c b/contiki/uip/uip-split.c
new file mode 100644
index 0000000..927bf57
--- /dev/null
+++ b/contiki/uip/uip-split.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-split.c,v 1.3 2004/09/12 20:24:56 adamdunkels Exp $
+ */
+
+#include "uip-split.h"
+#include "uip.h"
+#include "uip-fw.h"
+#include "uip_arch.h"
+
+#include "tcpip.h"
+
+#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+/*-----------------------------------------------------------------------------*/
+void
+uip_split_output(void)
+{
+  u16_t tcplen, len1, len2;
+
+  /* We only try to split maximum sized TCP segments. */
+  if(BUF->proto == UIP_PROTO_TCP &&
+     uip_len == UIP_BUFSIZE - UIP_LLH_LEN) {
+
+    tcplen = uip_len - UIP_TCPIP_HLEN;
+    /* Split the segment in two. If the original packet length was
+       odd, we make the second packet one byte larger. */
+    len1 = len2 = tcplen / 2;
+    if(len1 + len2 < tcplen) {
+      ++len2;
+    }
+
+    /* Create the first packet. This is done by altering the length
+       field of the IP header and updating the checksums. */
+    uip_len = len1 + UIP_TCPIP_HLEN;
+    BUF->len[0] = (uip_len >> 8);
+    BUF->len[1] = (uip_len & 0xff);
+    
+    /* Recalculate the TCP checksum. */
+    BUF->tcpchksum = 0;
+    BUF->tcpchksum = ~(uip_tcpchksum());
+    
+    /* Recalculate the IP checksum. */
+    BUF->ipchksum = 0;
+    BUF->ipchksum = ~(uip_ipchksum());
+
+    /* Transmit the first packet. */
+    /*    uip_fw_output();*/
+    tcpip_output();
+
+    /* Now, create the second packet. To do this, it is not enough to
+       just alter the length field, but we must also update the TCP
+       sequence number and point the uip_appdata to a new place in
+       memory. This place is detemined by the length of the first
+       packet (len1). */
+    uip_len = len2 + UIP_TCPIP_HLEN;
+    BUF->len[0] = (uip_len >> 8);
+    BUF->len[1] = (uip_len & 0xff);
+
+    uip_appdata += len1;
+
+    uip_add32(BUF->seqno, len1);
+    BUF->seqno[0] = uip_acc32[0];
+    BUF->seqno[1] = uip_acc32[1];
+    BUF->seqno[2] = uip_acc32[2];
+    BUF->seqno[3] = uip_acc32[3];
+    
+    /* Recalculate the TCP checksum. */
+    BUF->tcpchksum = 0;
+    BUF->tcpchksum = ~(uip_tcpchksum());
+    
+    /* Recalculate the IP checksum. */
+    BUF->ipchksum = 0;
+    BUF->ipchksum = ~(uip_ipchksum());
+
+    /* Transmit the second packet. */
+    /*    uip_fw_output();*/
+    tcpip_output();
+  } else {
+    /*    uip_fw_output();*/
+    tcpip_output();
+  }
+     
+}
+/*-----------------------------------------------------------------------------*/
diff --git a/contiki/uip/uip-split.h b/contiki/uip/uip-split.h
new file mode 100644
index 0000000..9131a80
--- /dev/null
+++ b/contiki/uip/uip-split.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uip-split.h,v 1.2 2004/09/12 20:24:56 adamdunkels Exp $
+ */
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uipsplit uIP TCP throughput booster hack
+ * @{
+ *
+ * The basic uIP TCP implementation only allows each TCP connection to
+ * have a single TCP segment in flight at any given time. Because of
+ * the delayed ACK algorithm employed by most TCP receivers, uIP's
+ * limit on the amount of in-flight TCP segments seriously reduces the
+ * maximum achievable throughput for sending data from uIP.
+ *
+ * The uip-split module is a hack which tries to remedy this
+ * situation. By splitting maximum sized outgoing TCP segments into
+ * two, the delayed ACK algorithm is not invoked at TCP
+ * receivers. This improves the throughput when sending data from uIP
+ * by orders of magnitude.
+ *
+ * The uip-split module uses the uip-fw module (uIP IP packet
+ * forwarding) for sending packets. Therefore, the uip-fw module must
+ * be set up with the appropriate network interfaces for this module
+ * to work.
+ */
+
+
+/**
+ * \file
+ * Module for splitting outbound TCP segments in two to avoid the
+ * delayed ACK throughput degradation. 
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __UIP_SPLIT_H__
+#define __UIP_SPLIT_H__
+
+/**
+ * Handle outgoing packets.
+ *
+ * This function inspects an outgoing packet in the uip_buf buffer and
+ * sends it out using the uip_fw_output() function. If the packet is a
+ * full-sized TCP segment it will be split into two segments and
+ * transmitted separately. This function should be called instead of
+ * the actual device driver output function, or the uip_fw_output()
+ * function.
+ *
+ * The headers of the outgoing packet is assumed to be in the uip_buf
+ * buffer and the payload is assumed to be wherever uip_appdata
+ * points. The length of the outgoing packet is assumed to be in the
+ * uip_len variable.
+ *
+ */
+void uip_split_output(void);
+
+#endif /* __UIP_SPLIT_H__ */
+
+/** @} */
+/** @} */
diff --git a/contiki/uip/uip.c b/contiki/uip/uip.c
new file mode 100644
index 0000000..661e2b7
--- /dev/null
+++ b/contiki/uip/uip.c
@@ -0,0 +1,1589 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \file
+ * The uIP TCP/IP stack code.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2001-2003, 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. 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.24 2005/03/14 07:18:15 adamdunkels Exp $
+ *
+ */
+
+/*
+This is a small implementation of the IP, UDP and TCP protocols (as
+well as some basic ICMP stuff). The implementation couples the IP,
+UDP, TCP and the application layers very tightly. To keep the size of
+the compiled code down, this code frequently uses the goto
+statement. While it would be possible to break the uip_process()
+function into many smaller functions, this would increase the code
+size because of the overhead of parameter passing and the fact that
+the optimier would not be as efficient.
+
+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 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. The uip_appdata pointer points to the first
+available byte. 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
+const u16_t uip_hostaddr[2] =
+  {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1),
+   HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)};
+const u16_t uip_draddr[2] =
+  {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1),
+   HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)};
+const u16_t uip_netmask[2] =
+  {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1),
+   HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)};
+#else
+u16_t uip_hostaddr[2];       
+u16_t uip_draddr[2], uip_netmask[2];
+#endif /* UIP_FIXEDADDR */
+
+#if UIP_FIXEDETHADDR
+const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,
+					  UIP_ETHADDR1,
+					  UIP_ETHADDR2,
+					  UIP_ETHADDR3,
+					  UIP_ETHADDR4,
+					  UIP_ETHADDR5}};
+#else
+struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
+#endif
+
+#ifndef UIP_CONF_EXTERNAL_BUFFER
+u8_t uip_buf[UIP_BUFSIZE + 2];   /* The packet buffer that contains
+				    incoming packets. */
+#endif /* UIP_CONF_EXTERNAL_BUFFER */
+
+u8_t *uip_appdata;               /* The uip_appdata pointer points to
+				    application data. */
+u8_t *uip_sappdata;              /* The uip_appdata pointer points to
+				    the application data which is to
+				    be sent. */
+#if UIP_URGDATA > 0
+u8_t *uip_urgdata;               /* The uip_urgdata pointer points to
+   				    urgent data (out-of-band data), if
+   				    present. */
+u16_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+u16_t uip_len, uip_slen;
+                             /* The uip_len is either 8 or 16 bits,
+				depending on the maximum packet
+				size. */
+
+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
+static u16_t lastport;       /* Keeps track of the last port used for
+				a new connection. */
+#endif /* UIP_ACTIVE_OPEN */
+
+/* Temporary variables. */
+u8_t uip_acc32[4];
+static u8_t c, opt;
+static u16_t tmp16;
+
+/* 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 TCP_OPT_END     0   /* End of TCP options list */
+#define TCP_OPT_NOOP    1   /* "No-operation" TCP option */
+#define TCP_OPT_MSS     2   /* Maximum segment size TCP option */
+
+#define TCP_OPT_MSS_LEN 4   /* Length of TCP MSS option. */
+
+#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 */
+  
+
+  /* IPv4 initialization. */
+#if UIP_FIXEDADDR == 0
+  /*  uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
+#endif /* UIP_FIXEDADDR */
+
+}
+/*-----------------------------------------------------------------------------------*/
+#if UIP_ACTIVE_OPEN
+struct uip_conn *
+uip_connect(u16_t *ripaddr, u16_t rport)
+{
+  register struct uip_conn *conn, *cconn;
+  
+  /* Find an unused local port. */
+ again:
+  ++lastport;
+
+  if(lastport >= 32000) {
+    lastport = 4096;
+  }
+
+  /* Check if this port is already in use, and if so try to find
+     another one. */
+  for(c = 0; c < UIP_CONNS; ++c) {
+    conn = &uip_conns[c];
+    if(conn->tcpstateflags != CLOSED &&
+       conn->lport == htons(lastport)) {
+      goto again;
+    }
+  }
+
+  conn = 0;
+  for(c = 0; c < UIP_CONNS; ++c) {
+    cconn = &uip_conns[c]; 
+    if(cconn->tcpstateflags == CLOSED) {
+      conn = cconn;
+      break;
+    }
+    if(cconn->tcpstateflags == TIME_WAIT) {
+      if(conn == 0 ||
+	 cconn->timer > conn->timer) {
+	conn = cconn;
+      }
+    }
+  }
+
+  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->initialmss = conn->mss = UIP_TCP_MSS;
+  
+  conn->len = 1;   /* TCP length of the SYN is one. */
+  conn->nrtx = 0;
+  conn->timer = 1; /* Send the SYN next time around. */
+  conn->rto = UIP_RTO;
+  conn->sa = 0;
+  conn->sv = 16;   /* Initial value of the RTT variance. */
+  conn->lport = htons(lastport);
+  conn->rport = rport;
+  conn->ripaddr[0] = ripaddr[0];
+  conn->ripaddr[1] = ripaddr[1];
+  
+  return conn;
+}
+#endif /* UIP_ACTIVE_OPEN */
+/*-----------------------------------------------------------------------------------*/
+#if UIP_UDP
+struct uip_udp_conn *
+uip_udp_new(u16_t *ripaddr, u16_t rport)
+{
+  register 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 == htons(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 = rport;
+  conn->ripaddr[0] = ripaddr[0];
+  conn->ripaddr[1] = ripaddr[1];
+  
+  return conn;
+}
+#endif /* UIP_UDP */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_unlisten(u16_t port)
+{
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(uip_listenports[c] == port) {
+      uip_listenports[c] = 0;
+      return;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_listen(u16_t port)
+{
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(uip_listenports[c] == 0) {
+      uip_listenports[c] = port;
+      return;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/* XXX: IP fragment reassembly: not well-tested. */
+
+#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_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) {
+    memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
+    uip_reasstmr = UIP_REASS_MAXAGE;
+    uip_reassflags = 0;
+    /* Clear the bitmap. */
+    memset(uip_reassbitmap, 0, 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->srcipaddr[1] == FBUF->srcipaddr[1] &&
+     BUF->destipaddr[0] == FBUF->destipaddr[0] &&
+     BUF->destipaddr[1] == FBUF->destipaddr[1] &&
+     BUF->ipid[0] == FBUF->ipid[0] &&
+     BUF->ipid[1] == FBUF->ipid[1]) {
+
+    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. */
+    memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],
+	   (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
+	   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;
+      memcpy(BUF, FBUF, uip_reasslen);
+
+      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
+	 from now on. */
+      BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
+      BUF->len[0] = uip_reasslen >> 8;
+      BUF->len[1] = uip_reasslen & 0xff;
+      BUF->ipchksum = 0;
+      BUF->ipchksum = ~(uip_ipchksum());
+
+      return uip_reasslen;
+    }
+  }
+
+ nullreturn:
+  return 0;
+}
+#endif /* UIP_REASSEMBLY */
+/*-----------------------------------------------------------------------------------*/
+static void
+uip_add_rcv_nxt(u16_t n)
+{
+  uip_add32(uip_conn->rcv_nxt, n);
+  uip_conn->rcv_nxt[0] = uip_acc32[0];
+  uip_conn->rcv_nxt[1] = uip_acc32[1];
+  uip_conn->rcv_nxt[2] = uip_acc32[2];
+  uip_conn->rcv_nxt[3] = uip_acc32[3];
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_process(u8_t flag)
+{
+  register struct uip_conn *uip_connr = uip_conn;
+  
+  uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
+
+  /* Check if we were invoked because of a poll request for a
+     particular connection. */
+  if(flag == UIP_POLL_REQUEST) {
+    if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED &&
+       !uip_outstanding(uip_connr)) {
+	uip_flags = UIP_POLL;
+	UIP_APPCALL();
+	goto appsend;      
+    }
+    goto drop;
+    
+    /* Check if we were invoked because of the perodic timer fireing. */
+  } else if(flag == UIP_TIMER) {
+#if UIP_REASSEMBLY
+    if(uip_reasstmr != 0) {
+      --uip_reasstmr;
+    }
+#endif /* UIP_REASSEMBLY */
+    /* Increase the initial sequence number. */
+    if(++iss[3] == 0) {
+      if(++iss[2] == 0) {
+	if(++iss[1] == 0) {
+	  ++iss[0];
+	}
+      }
+    }    
+    uip_len = 0;
+    uip_slen = 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)) {
+	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_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_flags = UIP_POLL;
+	UIP_APPCALL();
+	goto appsend;
+      }
+    }
+    goto drop;
+  }
+#if UIP_UDP 
+  if(flag == UIP_UDP_TIMER) {
+    if(uip_udp_conn->lport != 0) {
+      uip_conn = NULL;
+      uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
+      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);
+
+
+  /* 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 is smaller the size reported in the IP header, we assume
+     that the packet has been corrupted in transit. If the size of
+     uip_len is larger than the size reported in the IP packet header,
+     the packet has been padded and we set uip_len to the correct
+     value.. */
+
+  if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
+    uip_len = (BUF->len[0] << 8) + BUF->len[1];
+  } else {
+    UIP_LOG("ip: packet shorter than reported in IP header.");
+    goto drop;
+  }
+
+  /* Check the fragment flag. */
+  if((BUF->ipoffset[0] & 0x3f) != 0 ||
+     BUF->ipoffset[1] != 0) { 
+#if UIP_REASSEMBLY
+    uip_len = uip_reass();
+    if(uip_len == 0) {
+      goto drop;
+    }
+#else
+    UIP_STAT(++uip_stat.ip.drop);
+    UIP_STAT(++uip_stat.ip.fragerr);
+    UIP_LOG("ip: fragment dropped.");    
+    goto drop;
+#endif /* UIP_REASSEMBLY */
+  }
+
+  if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
+    /* 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(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 */
+
+  } else {
+    /* If IP broadcast support is configured, we check for a broadcast
+       UDP packet, which may be destined to us. */
+#if UIP_BROADCAST
+    if(BUF->proto == UIP_PROTO_UDP &&
+       BUF->destipaddr[0] == 0xffff &&
+     BUF->destipaddr[1] == 0xffff &&
+       uip_ipchksum() == 0xffff) {
+      goto udp_input;
+    }
+#endif /* UIP_BROADCAST */
+    
+    /* Check if the packet is destined for our IP address. */  
+    if(BUF->destipaddr[0] != uip_hostaddr[0]) {
+      UIP_STAT(++uip_stat.ip.drop);
+      goto drop;
+    }
+    if(BUF->destipaddr[1] != uip_hostaddr[1]) {
+      UIP_STAT(++uip_stat.ip.drop);
+      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,
+				       proceed with TCP input
+				       processing. */
+    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;
+  }
+
+#if UIP_PINGADDRCONF  
+ icmp_input:
+#endif /* UIP_PINGADDRCONF */
+  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. */
+  tmp16 = BUF->destipaddr[0];
+  BUF->destipaddr[0] = BUF->srcipaddr[0];
+  BUF->srcipaddr[0] = tmp16;
+  tmp16 = BUF->destipaddr[1];
+  BUF->destipaddr[1] = BUF->srcipaddr[1];
+  BUF->srcipaddr[1] = tmp16;
+
+  UIP_STAT(++uip_stat.icmp.sent);
+  goto send;
+
+  /* End of IPv4 input header processing code. */
+  
+
+#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
+  uip_len = uip_len - UIP_IPTCPH_LEN;
+  uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
+  if(uip_udpchksum() != 0xffff) {
+    printf("checksum 0x%04x\n", uip_udpchksum());
+    UIP_STAT(++uip_stat.udp.drop);
+    UIP_STAT(++uip_stat.udp.chkerr);
+    UIP_LOG("udp: bad checksum.");    
+    goto drop;
+  }
+  uip_len = uip_len + (UIP_IPTCPH_LEN - UIP_IPUDPH_LEN);
+#else /* UIP_UDP_CHECKSUMS */
+  uip_len = uip_len - UIP_IPUDPH_LEN;
+#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 the local UDP port is non-zero, the connection is considered
+       to be used. If so, the local port number is checked against the
+       destination port number in the received packet. If the two port
+       numbers match, the remote port number is checked if the
+       connection is bound to a remote port. Finally, if the
+       connection is bound to a remote IP address, the source IP
+       address of the packet is checked. */
+    if(uip_udp_conn->lport != 0 && 
+       UDPBUF->destport == uip_udp_conn->lport &&
+       (uip_udp_conn->rport == 0 ||
+        UDPBUF->srcport == uip_udp_conn->rport) &&
+       ((uip_udp_conn->ripaddr[0] | uip_udp_conn->ripaddr[1]) == 0 ||
+	(uip_udp_conn->ripaddr[0] == 0xffff &&
+	 uip_udp_conn->ripaddr[1] == 0xffff) ||	
+	uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) {
+      goto udp_found; 
+    }
+  }
+  UIP_LOG("udp: no matching connection found");    
+  goto drop;
+  
+ udp_found:
+  uip_conn = NULL;
+  uip_flags = UIP_NEWDATA;
+  uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
+  uip_slen = 0;
+  UIP_UDP_APPCALL();
+ udp_send:
+  if(uip_slen == 0) {
+    goto drop;      
+  }
+  uip_len = uip_slen + UIP_IPUDPH_LEN;
+
+  BUF->len[0] = (uip_len >> 8);
+  BUF->len[1] = (uip_len & 0xff);
+  
+  BUF->proto = UIP_PROTO_UDP;
+
+  UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
+  UDPBUF->udpchksum = 0;
+
+  BUF->srcport  = uip_udp_conn->lport;
+  BUF->destport = uip_udp_conn->rport;
+
+  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];
+ 
+  uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
+
+#if UIP_UDP_CHECKSUMS 
+  /* Calculate UDP checksum. */
+  UDPBUF->udpchksum = ~(uip_udpchksum());
+  if(UDPBUF->udpchksum == 0) {
+    UDPBUF->udpchksum = 0xffff;
+  }
+#endif /* UIP_UDP_CHECKSUMS */
+  
+  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 - 1];
+      ++uip_connr) {
+    if(uip_connr->tcpstateflags != CLOSED &&
+       BUF->destport == uip_connr->lport &&
+       BUF->srcport == uip_connr->rport &&
+       BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
+       BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
+      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;
+  }
+  
+  tmp16 = BUF->destport;
+  /* Next, check listening connections. */  
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(tmp16 == 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 = UIP_IPTCPH_LEN;
+  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. */
+  tmp16 = BUF->srcport;
+  BUF->srcport = BUF->destport;
+  BUF->destport = tmp16;
+  
+  /* Swap IP addresses. */
+  tmp16 = BUF->destipaddr[0];
+  BUF->destipaddr[0] = BUF->srcipaddr[0];
+  BUF->srcipaddr[0] = tmp16;
+  tmp16 = BUF->destipaddr[1];
+  BUF->destipaddr[1] = BUF->srcipaddr[1];
+  BUF->srcipaddr[1] = tmp16;
+
+  
+  /* 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->rto = uip_connr->timer = UIP_RTO;
+  uip_connr->sa = 0;
+  uip_connr->sv = 4;  
+  uip_connr->nrtx = 0;
+  uip_connr->lport = BUF->destport;
+  uip_connr->rport = BUF->srcport;
+  uip_connr->ripaddr[0] = BUF->srcipaddr[0];
+  uip_connr->ripaddr[1] = BUF->srcipaddr[1];
+  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 == TCP_OPT_END) {
+	/* End of options. */	
+	break;
+      } else if(opt == TCP_OPT_NOOP) {
+	++c;
+	/* NOP option. */
+      } else if(opt == TCP_OPT_MSS &&
+		uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
+	/* An MSS option with the right option length. */	
+	tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+	  (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
+	uip_connr->initialmss = uip_connr->mss =
+	  tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+	
+	/* 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] = TCP_OPT_MSS;
+  BUF->optdata[1] = TCP_OPT_MSS_LEN;
+  BUF->optdata[2] = (UIP_TCP_MSS) / 256;
+  BUF->optdata[3] = (UIP_TCP_MSS) & 255;
+  uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
+  BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 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;
+  }      
+  /* 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 - UIP_IPH_LEN;
+
+  /* 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_connr->tcpstateflags & TS_MASK) == SYN_SENT) &&
+       ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
+    if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 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((BUF->flags & TCP_ACK) && 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_connr->rto - 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 retransmission timer. */
+      uip_connr->timer = uip_connr->rto;
+
+      /* Reset length of outstanding data. */
+      uip_connr->len = 0;
+    }
+    
+  }
+
+  /* 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;
+      uip_connr->len = 0;
+      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_CTL) == (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[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
+	  if(opt == TCP_OPT_END) {
+	    /* End of options. */	
+	    break;
+	  } else if(opt == TCP_OPT_NOOP) {
+	    ++c;
+	    /* NOP option. */
+	  } else if(opt == TCP_OPT_MSS &&
+		    uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
+	    /* An MSS option with the right option length. */
+	    tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+	      uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
+	    uip_connr->initialmss =
+	      uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+
+	    /* 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_connr->len = 0;
+      uip_len = 0;
+      uip_slen = 0;
+      UIP_APPCALL();
+      goto appsend;
+    }
+    /* Inform the application that the connection failed */
+    uip_flags = UIP_ABORT;
+    UIP_APPCALL();
+    /* The connection is closed after we send the RST */
+    uip_conn->tcpstateflags = CLOSED;
+    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 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
+      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) != 0) {
+#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;
+#else /* UIP_URGDATA > 0 */      
+      uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
+      uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
+#endif /* UIP_URGDATA > 0 */      
+    }
+
+    /* 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);
+    }
+
+    /* Check if the available buffer space advertised by the other end
+       is smaller than the initial MSS for this connection. If so, we
+       set the current MSS to the window size to ensure that the
+       application does not send more data than the other end can
+       handle.
+
+       If the remote host advertises a zero window, we set the MSS to
+       the initial MSS so that the application will send an entire MSS
+       of data. This data will not be acknowledged by the receiver,
+       and the application will retransmit it. This is called the
+       "persistent timer" and uses the retransmission mechanim.
+    */
+    tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
+    if(tmp16 > uip_connr->initialmss ||
+       tmp16 == 0) {
+      tmp16 = uip_connr->initialmss;
+    }
+    uip_connr->mss = tmp16;
+
+    /* 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 UIP_IPTCPH_LEN + UIP_LLH_LEN
+       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. */
+      if(uip_slen > 0) {
+
+	/* If the connection has acknowledged data, the contents of
+	   the ->len variable should be discarded. */ 
+	if((uip_flags & UIP_ACKDATA) != 0) {
+	  uip_connr->len = 0;
+	}
+
+	/* If the ->len variable is non-zero the connection has
+	   already data in transit and cannot send anymore right
+	   now. */
+	if(uip_connr->len == 0) {
+
+	  /* The application cannot send more than what is allowed by
+	     the mss (the minumum of the MSS and the available
+	     window). */
+	  if(uip_slen > uip_connr->mss) {
+	    uip_slen = uip_connr->mss;
+	  }
+
+	  /* Remember how much data we send out now so that we know
+	     when everything has been acknowledged. */
+	  uip_connr->len = uip_slen;
+	} else {
+
+	  /* If the application already had unacknowledged data, we
+	     make sure that the application does not send (i.e.,
+	     retransmit) out more than it previously sent out. */
+	  uip_slen = uip_connr->len;
+	}
+      }
+      uip_connr->nrtx = 0;
+    apprexmit:
+      uip_appdata = uip_sappdata;
+      
+      /* 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_connr->len > 0) {
+	/* 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 | TCP_PSH;
+	/* Send the packet. */
+	goto tcp_send_noopts;
+      }
+      /* If there is no data to send, just send out a pure ACK if
+	 there is newdata. */
+      if(uip_flags & UIP_NEWDATA) {
+	uip_len = UIP_TCPIP_HLEN;
+	BUF->flags = TCP_ACK;
+	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 = UIP_IPTCPH_LEN;
+ tcp_send_noopts:
+  BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 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;
+
+  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];
+ 
+
+  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 {
+    BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
+    BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); 
+  }
+
+ tcp_send_noconn:
+
+  BUF->len[0] = (uip_len >> 8);
+  BUF->len[1] = (uip_len & 0xff);
+
+  BUF->urgp[0] = BUF->urgp[1] = 0;
+  
+  /* Calculate TCP checksum. */
+  BUF->tcpchksum = 0;
+  BUF->tcpchksum = ~(uip_tcpchksum());
+  
+ ip_send_nolen:
+
+  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());
+
+  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;
+}
+/*-----------------------------------------------------------------------------------*/
+u16_t
+htons(u16_t val)
+{
+  return HTONS(val);
+}
+/*-----------------------------------------------------------------------------------*/
+/** @} */
diff --git a/contiki/uip/uip.h b/contiki/uip/uip.h
new file mode 100644
index 0000000..3a3d62e
--- /dev/null
+++ b/contiki/uip/uip.h
@@ -0,0 +1,1370 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \file
+ * Header file for the uIP TCP/IP stack.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * The uIP TCP/IP stack header file contains definitions for a number
+ * of C macros that are used by uIP programs as well as internal uIP
+ * structures, TCP/IP header structures and function declarations.
+ *
+ */
+
+
+/*
+ * Copyright (c) 2001-2003, 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. 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.20 2006/05/17 15:25:15 oliverschmidt Exp $
+ *
+ */
+
+#ifndef __UIP_H__
+#define __UIP_H__
+
+#include "uipopt.h"
+
+/*-----------------------------------------------------------------------------------*/
+/* First, the functions that should be called from the
+ * system. Initialization, the periodic timer and incoming packets are
+ * handled by the following three functions.
+ */
+
+/**
+ * \defgroup uipconffunc uIP configuration functions
+ * @{
+ *
+ * The uIP configuration functions are used for setting run-time
+ * parameters in uIP such as IP addresses. 
+ */
+
+/**
+ * Set the IP address of this host.
+ *
+ * The IP address is represented as a 4-byte array where the first
+ * octet of the IP address is put in the first member of the 4-byte
+ * array.
+ *
+ * \param addr A pointer to a 4-byte representation of the IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_sethostaddr(addr) do { uip_hostaddr[0] = ((u16_t *)(addr))[0]; \
+                              uip_hostaddr[1] = ((u16_t *)(addr))[1]; } while(0)
+
+/**
+ * Get the IP address of this host.
+ *
+ * The IP address is represented as a 4-byte array where the first
+ * octet of the IP address is put in the first member of the 4-byte
+ * array.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the currently configured IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_gethostaddr(addr) do { ((u16_t *)(addr))[0] = uip_hostaddr[0]; \
+                              ((u16_t *)(addr))[1] = uip_hostaddr[1]; } while(0)
+
+/**
+ * Set the default router's IP address.
+ *
+ * \param addr A pointer to a 4-byte array containing the IP address
+ * of the default router.
+ *
+ * \hideinitializer
+ */
+#define uip_setdraddr(addr) do { uip_draddr[0] = ((u16_t *)(addr))[0]; \
+                                 uip_draddr[1] = ((u16_t *)(addr))[1]; } while(0)
+
+/**
+ * Set the netmask.
+ *
+ * \param addr A pointer to a 4-byte array containing the IP address
+ * of the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_setnetmask(addr) do { uip_netmask[0] = ((u16_t *)(addr))[0]; \
+                                  uip_netmask[1] = ((u16_t *)(addr))[1]; } while(0)
+
+
+/**
+ * Get the default router's IP address.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the IP address of the default router.
+ *
+ * \hideinitializer
+ */
+#define uip_getdraddr(addr) do { ((u16_t *)(addr))[0] = uip_draddr[0]; \
+                                 ((u16_t *)(addr))[1] = uip_draddr[1]; } while(0)
+
+/**
+ * Get the netmask.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the value of the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_getnetmask(addr) do { ((u16_t *)(addr))[0] = uip_netmask[0]; \
+                                  ((u16_t *)(addr))[1] = uip_netmask[1]; } while(0)
+
+/** @} */
+
+/**
+ * \defgroup uipinit uIP initialization functions
+ * @{
+ *
+ * The uIP initialization functions are used for booting uIP.
+ */
+
+/**
+ * uIP initialization function.
+ *
+ * This function should be called at boot up to initilize the uIP
+ * TCP/IP stack.
+ */
+void uip_init(void);
+
+/** @} */
+
+/**
+ * \defgroup uipdevfunc uIP device driver functions
+ * @{
+ *
+ * These functions are used by a network device driver for interacting
+ * with uIP.
+ */
+
+/**
+ * Process an incoming packet.
+ *
+ * This function should be called when the device driver has received
+ * a packet from the network. The packet from the device driver must
+ * be present in the uip_buf buffer, and the length of the packet
+ * should be placed in the uip_len variable.
+ *
+ * When the function returns, there may be an outbound packet placed
+ * in the uip_buf packet buffer. If so, the uip_len variable is set to
+ * the length of the packet. If no packet is to be sent out, the
+ * uip_len variable is set to 0.
+ *
+ * The usual way of calling the function is presented by the source
+ * code below.
+ \code
+  uip_len = devicedriver_poll();
+  if(uip_len > 0) {
+    uip_input();
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uIP ARP code before calling
+ * this function:
+ \code
+  #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+  uip_len = ethernet_devicedrver_poll();
+  if(uip_len > 0) {
+    if(BUF->type == HTONS(UIP_ETHTYPE_IP)) {
+      uip_arp_ipin();
+      uip_input();
+      if(uip_len > 0) {
+        uip_arp_out();
+	ethernet_devicedriver_send();
+      }
+    } else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) {
+      uip_arp_arpin();
+      if(uip_len > 0) {
+	ethernet_devicedriver_send();
+      }
+    }
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define uip_input()        uip_process(UIP_DATA)
+
+/**
+ * Periodic processing for a connection identified by its number.
+ * 
+ * This function does the necessary periodic processing (timers,
+ * polling) for a uIP TCP conneciton, and should be called when the
+ * periodic uIP timer goes off. It should be called for every
+ * connection, regardless of whether they are open of closed.
+ *
+ * When the function returns, it may have an outbound packet waiting
+ * for service in the uIP packet buffer, and if so the uip_len
+ * variable is set to a value larger than zero. The device driver
+ * should be called to send out the packet.
+ *
+ * The ususal way of calling the function is through a for() loop like
+ * this:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uip_arp_out() function before
+ * calling the device driver:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode 
+ *
+ * \param conn The number of the connection which is to be periodically polled.
+ *
+ * \hideinitializer
+ */
+#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \
+                                uip_process(UIP_TIMER); } while (0)
+
+/**
+ * Perform periodic processing for a connection identified by a pointer
+ * to its structure.
+ *
+ * Same as uip_periodic() but takes a pointer to the actual uip_conn
+ * struct instead of an integer as its argument. This function can be
+ * used to force periodic processing of a specific connection.
+ *
+ * \param conn A pointer to the uip_conn struct for the connection to
+ * be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_periodic_conn(conn) do { uip_conn = conn; \
+                                     uip_process(UIP_TIMER); } while (0)
+
+/**
+ * Reuqest that a particular connection should be polled.
+ *
+ * Similar to uip_periodic_conn() but does not perform any timer
+ * processing. The application is polled for new data.
+ *
+ * \param conn A pointer to the uip_conn struct for the connection to
+ * be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_poll_conn(conn) do { uip_conn = conn; \
+                                 uip_process(UIP_POLL_REQUEST); } while (0)
+
+
+#if UIP_UDP
+/**
+ * Periodic processing for a UDP connection identified by its number.
+ *
+ * This function is essentially the same as uip_periodic(), but for
+ * UDP connections. It is called in a similar fashion as the
+ * uip_periodic() function:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }   
+ \endcode
+ *
+ * \note As for the uip_periodic() function, special care has to be
+ * taken when using uIP together with ARP and Ethernet:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }   
+ \endcode
+ *
+ * \param conn The number of the UDP connection to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \
+                                uip_process(UIP_UDP_TIMER); } while (0)
+
+/**
+ * Periodic processing for a UDP connection identified by a pointer to
+ * its structure.
+ *
+ * Same as uip_udp_periodic() but takes a pointer to the actual
+ * uip_conn struct instead of an integer as its argument. This
+ * function can be used to force periodic processing of a specific
+ * connection.
+ *
+ * \param conn A pointer to the uip_udp_conn struct for the connection
+ * to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \
+                                         uip_process(UIP_UDP_TIMER); } while (0)
+
+
+#endif /* UIP_UDP */
+
+/**
+ * The uIP packet buffer.
+ *
+ * The uip_buf array is used to hold incoming and outgoing
+ * packets. The device driver should place incoming data into this
+ * buffer. When sending data, the device driver should read the link
+ * level headers and the TCP/IP headers from this buffer. The size of
+ * the link level headers is configured by the UIP_LLH_LEN define.
+ *
+ * \note The application data need not be placed in this buffer, so
+ * the device driver must read it from the place pointed to by the
+ * uip_appdata pointer as illustrated by the following example:
+ \code
+ void
+ devicedriver_send(void)
+ {
+    hwsend(&uip_buf[0], UIP_LLH_LEN); 
+    if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
+      hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);    
+    } else {
+      hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
+      hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
+    }
+ }
+ \endcode
+ */
+extern u8_t uip_buf[UIP_BUFSIZE+2];
+
+/** @} */
+
+/*-----------------------------------------------------------------------------------*/
+/* 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.
+*/
+/**
+ * \defgroup uipappfunc uIP application functions
+ * @{
+ *
+ * Functions used by an application running of top of uIP.
+ */
+
+/**
+ * Start listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_listen(HTONS(80)); 
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_listen(u16_t port);
+
+/**
+ * Stop listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_unlisten(HTONS(80)); 
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_unlisten(u16_t port);
+
+/**
+ * Connect to a remote host using TCP.
+ *
+ * This function is used to start a new connection to the specified
+ * port on the specied host. It allocates a new connection identifier,
+ * sets the connection to the SYN_SENT state and sets the
+ * retransmission timer to 0. This will cause a TCP SYN segment to be
+ * sent out the next time this connection is periodically processed,
+ * which usually is done within 0.5 seconds after the call to
+ * uip_connect().
+ *
+ * \note This function is avaliable only if support for active open
+ * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
+ *
+ * \note Since this function requires the port number to be in network
+ * byte order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ u16_t ipaddr[2];
+
+ uip_ipaddr(ipaddr, 192,168,1,2);
+ uip_connect(ipaddr, HTONS(80)); 
+ \endcode
+ * 
+ * \param ripaddr A pointer to a 4-byte array representing the IP
+ * address of the remote hot.
+ *
+ * \param port A 16-bit port number in network byte order.
+ *
+ * \return A pointer to the uIP connection identifier for the new connection,
+ * or NULL if no connection could be allocated.   
+ *
+ */
+struct uip_conn *uip_connect(u16_t *ripaddr, u16_t port);
+
+
+
+/**
+ * \internal
+ *
+ * Check if a connection has outstanding (i.e., unacknowledged) data.
+ *
+ * \param conn A pointer to the uip_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_outstanding(conn) ((conn)->len)
+
+/**
+ * Send data on the current connection.
+ *
+ * This function is used to send out a single segment of TCP
+ * data. Only applications that have been invoked by uIP for event
+ * processing can send data. 
+ *
+ * The amount of data that actually is sent out after a call to this
+ * funcion is determined by the maximum amount of data TCP allows. uIP
+ * will automatically crop the data so that only the appropriate
+ * amount of data is sent. The function uip_mss() can be used to query
+ * uIP for the amount of data that actually will be sent.
+ * 
+ * \note This function does not guarantee that the sent data will
+ * arrive at the destination. If the data is lost in the network, the
+ * application will be invoked with the uip_rexmit() event being
+ * set. The application will then have to resend the data using this
+ * function.
+ * 
+ * \param data A pointer to the data which is to be sent.
+ *
+ * \param len The maximum amount of data bytes to be sent.
+ *
+ * \hideinitializer
+ */
+#define uip_send(data, len) do { uip_sappdata = (void *)(data); uip_slen = (len);} while(0)   
+
+/**
+ * The length of any incoming data that is currently avaliable (if avaliable)
+ * in the uip_appdata buffer.
+ *
+ * The test function uip_data() must first be used to check if there
+ * is any data available at all.
+ *
+ * \hideinitializer
+ */
+#define uip_datalen()       uip_len
+
+/**
+ * The length of any out-of-band data (urgent data) that has arrived
+ * on the connection.
+ *
+ * \note The configuration parameter UIP_URGDATA must be set for this
+ * function to be enabled.
+ *
+ * \hideinitializer
+ */
+#define uip_urgdatalen()    uip_urglen
+
+/**
+ * Close the current connection.
+ *
+ * This function will close the current connection in a nice way.
+ *
+ * \hideinitializer
+ */
+#define uip_close()         (uip_flags = UIP_CLOSE)
+
+/**
+ * Abort the current connection.
+ *
+ * This function will abort (reset) the current connection, and is
+ * usually used when an error has occured that prevents using the
+ * uip_close() function.
+ *
+ * \hideinitializer
+ */
+#define uip_abort()         (uip_flags = UIP_ABORT)
+
+/**
+ * Tell the sending host to stop sending data.
+ *
+ * This function will close our receiver's window so that we stop
+ * receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_stop()          (uip_conn->tcpstateflags |= UIP_STOPPED)
+
+/**
+ * Find out if the current connection has been previously stopped with
+ * uip_stop().
+ *
+ * \hideinitializer
+ */
+#define uip_stopped(conn)   ((conn)->tcpstateflags & UIP_STOPPED)
+
+/**
+ * Restart the current connection, if is has previously been stopped
+ * with uip_stop().
+ *
+ * This function will open the receiver's window again so that we
+ * start receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#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. */
+
+/**
+ * Is the current connection a UDP connection?
+ *
+ * This function checks whether the current connection is a UDP connection.
+ *
+ * \hideinitializer
+ *
+ */
+#define uip_udpconnection() (uip_conn == NULL)
+
+/**
+ * Is new incoming data available?
+ *
+ * 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.
+ *
+ * \hideinitializer
+ */
+#define uip_newdata()   (uip_flags & UIP_NEWDATA)
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * 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. 
+ *
+ * \hideinitializer
+ */
+#define uip_acked()   (uip_flags & UIP_ACKDATA)
+
+/**
+ * Has the connection just been 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()).
+ *
+ * \hideinitializer
+ */
+#define uip_connected() (uip_flags & UIP_CONNECTED)
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+#define uip_closed()    (uip_flags & UIP_CLOSE)
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+#define uip_aborted()    (uip_flags & UIP_ABORT)
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+#define uip_timedout()    (uip_flags & UIP_TIMEDOUT) 
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+#define uip_rexmit()     (uip_flags & UIP_REXMIT)
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * 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.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */ 
+#define uip_poll()       (uip_flags & UIP_POLL)
+
+/**
+ * Get the initial maxium segment size (MSS) of the current
+ * connection.
+ *
+ * \hideinitializer
+ */
+#define uip_initialmss()             (uip_conn->initialmss)
+
+/**
+ * Get the current maxium segment size that can be sent on the current
+ * connection.
+ *
+ * The current maxiumum segment size that can be sent on the
+ * connection is computed from the receiver's window and the MSS of
+ * the connection (which also is available by calling
+ * uip_initialmss()).
+ *
+ * \hideinitializer
+ */
+#define uip_mss()             (uip_conn->mss)
+
+/**
+ * Set up a new UDP connection.
+ *
+ * \param ripaddr A pointer to a 4-byte structure representing the IP
+ * address of the remote host.
+ *
+ * \param rport The remote port number in network byte order.
+ *
+ * \return The uip_udp_conn structure for the new connection or NULL
+ * if no connection could be allocated.
+ */
+struct uip_udp_conn *uip_udp_new(u16_t *ripaddr, u16_t rport);
+
+/**
+ * Removed a UDP connection.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_remove(conn) (conn)->lport = 0
+
+/**
+ * Bind a UDP connection to a local port.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the
+ * connection.
+ *
+ * \param port The local port number, in network byte order.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_bind(conn, port) (conn)->lport = port
+
+/**
+ * Send a UDP datagram of length len on the current connection.
+ *
+ * This function can only be called in response to a UDP event (poll
+ * or newdata). The data must be present in the uip_buf buffer, at the
+ * place pointed to by the uip_appdata pointer.
+ *
+ * \param len The length of the data in the uip_buf buffer.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_send(len) uip_slen = (len)
+
+/** @} */
+
+/* uIP convenience and converting functions. */
+
+/**
+ * \defgroup uipconvfunc uIP conversion functions
+ * @{
+ *
+ * These functions can be used for converting between different data
+ * formats used by uIP.
+ */
+ 
+/**
+ * Pack an IP address into a 4-byte array which is used by uIP to
+ * represent IP addresses.
+ *
+ * Example:
+ \code
+ u16_t ipaddr[2];
+
+ uip_ipaddr(&ipaddr, 192,168,1,2); 
+ \endcode
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the IP addres.
+ * \param addr0 The first octet of the IP address.
+ * \param addr1 The second octet of the IP address.
+ * \param addr2 The third octet of the IP address.
+ * \param addr3 The forth octet of the IP address. 
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \
+                     ((u16_t *)(addr))[0] = HTONS(((addr0) << 8) | (addr1)); \
+                     ((u16_t *)(addr))[1] = HTONS(((addr2) << 8) | (addr3)); \
+                  } while(0)
+
+/**
+ * Copy an IP address to another IP address.
+ *
+ * Copies an IP address from one place to another.
+ *
+ * Example:
+ \code
+ u16_t ipaddr1[2], ipaddr2[2];
+
+ uip_ipaddr(ipaddr1, 192,16,1,2);
+ uip_ipaddr_copy(ipaddr2, ipaddr1);
+ \endcode
+ *
+ * \param dest The destination for the copy.
+ * \param src The source from where to copy.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr_copy(dest, src) do { \
+                     ((u16_t *)dest)[0] = ((u16_t *)src)[0]; \
+                     ((u16_t *)dest)[1] = ((u16_t *)src)[1]; \
+                  } while(0)
+/**
+ * Compare two IP addresses
+ *
+ * Compares two IP addresses.
+ *
+ * Example:
+ \code
+ u16_t ipaddr1[2], ipaddr2[2];
+
+ uip_ipaddr(ipaddr1, 192,16,1,2);
+ if(uip_ipaddr_cmp(ipaddr2, ipaddr1)) {
+    printf("They are the same");
+ }
+ \endcode
+ *
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr_cmp(addr1, addr2) (((u16_t *)addr1)[0] == ((u16_t *)addr2)[0] && \
+				      ((u16_t *)addr1)[1] == ((u16_t *)addr2)[1])
+
+/**
+ * Compare two IP addresses with netmasks
+ *
+ * Compares two IP addresses with netmasks. The masks are used to mask
+ * out the bits that are to be compared.
+ *
+ * Example:
+ \code
+ u16_t ipaddr1[2], ipaddr2[2], mask[2];
+
+ uip_ipaddr(mask, 255,255,255,0);
+ uip_ipaddr(ipaddr1, 192,16,1,2);
+ uip_ipaddr(ipaddr2, 192,16,1,3); 
+ if(uip_ipaddr_maskcmp(ipaddr1, ipaddr2, mask)) {
+    printf("They are the same");
+ }
+ \endcode
+ * 
+ * \param addr1 The first IP address.
+ * \param addr2 The second IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr_maskcmp(addr1, addr2, mask) \
+                          (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \
+                            (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \
+                           ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \
+                            (((u16_t *)addr2)[1] & ((u16_t *)mask)[1])))
+
+
+/**
+ * Mask out the network part of an IP address.
+ *
+ * Masks out the network part of an IP address, given the address and
+ * the netmask.
+ *
+ * Example:
+ \code
+ u16_t ipaddr1[2], ipaddr2[2], netmask[2];
+
+ uip_ipaddr(ipaddr1, 192,16,1,2);
+ uip_ipaddr(netmask, 255,255,255,0);
+ uip_ipaddr_mask(ipaddr2, ipaddr1, netmask);
+ \endcode
+ *
+ * In the example above, the variable "ipaddr2" will contain the IP
+ * address 192.168.1.0.
+ *
+ * \param dest Where the result is to be placed.
+ * \param src The IP address.
+ * \param mask The netmask.
+ *
+ * \hideinitializer
+ */  
+#define uip_ipaddr_mask(dest, src, mask) do { \
+                     ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \
+                     ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \
+                  } while(0)
+
+/**
+ * Pick the first octet of an IP address.
+ *
+ * Picks out the first octet of an IP address.
+ *
+ * Example:
+ \code
+ u16_t ipaddr[2];
+ u8_t octet;
+
+ uip_ipaddr(ipaddr, 1,2,3,4);
+ octet = uip_ipaddr1(ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 1.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8)
+
+/**
+ * Pick the second octet of an IP address.
+ *
+ * Picks out the second octet of an IP address.
+ *
+ * Example:
+ \code
+ u16_t ipaddr[2];
+ u8_t octet;
+
+ uip_ipaddr(ipaddr, 1,2,3,4);
+ octet = uip_ipaddr2(ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 2.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff)
+
+/**
+ * Pick the third octet of an IP address.
+ *
+ * Picks out the third octet of an IP address.
+ *
+ * Example:
+ \code
+ u16_t ipaddr[2];
+ u8_t octet;
+
+ uip_ipaddr(ipaddr, 1,2,3,4);
+ octet = uip_ipaddr3(ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 3.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8)
+
+/**
+ * Pick the fourth octet of an IP address.
+ *
+ * Picks out the fourth octet of an IP address.
+ *
+ * Example:
+ \code
+ u16_t ipaddr[2];
+ u8_t octet;
+
+ uip_ipaddr(ipaddr, 1,2,3,4);
+ octet = uip_ipaddr4(ipaddr);
+ \endcode
+ *
+ * In the example above, the variable "octet" will contain the value 4.
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff)
+
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This macro is primarily used for converting constants from host
+ * byte order to network byte order. For converting variables to
+ * network byte order, use the htons() function instead.
+ *
+ * \hideinitializer
+ */
+#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 */
+
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This function is primarily used for converting variables from host
+ * byte order to network byte order. For converting constants to
+ * network byte order, use the HTONS() macro instead.
+ */
+u16_t htons(u16_t val);
+
+/** @} */
+
+/**
+ * Pointer to the application data in the packet buffer.
+ *
+ * This pointer points to the application data when the application is
+ * called. If the application wishes to send data, the application may
+ * use this space to write the data into before calling uip_send().
+ */
+extern u8_t *uip_appdata;
+extern u8_t *uip_sappdata; 
+
+#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 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.
+ */
+extern u16_t uip_len, uip_slen;
+
+#if UIP_URGDATA > 0 
+extern u8_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+
+/**
+ * Representation of a uIP TCP connection.
+ *
+ * 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 {
+  u16_t ripaddr[2];   /**< The IP address of the remote host. */
+  
+  u16_t lport;        /**< The local TCP port, in network byte order. */
+  u16_t rport;        /**< The local remote TCP port, in network byte
+			 order. */  
+  
+  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. */
+  u16_t len;          /**< Length of the data that was previously sent. */
+  u16_t mss;          /**< Current maximum segment size for the
+			 connection. */
+  u16_t initialmss;   /**< Initial maximum segment size for the
+			 connection. */  
+  u8_t sa;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t sv;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t rto;           /**< Retransmission time-out. */
+  u8_t tcpstateflags; /**< TCP state and flags. */
+  u8_t timer;         /**< The retransmission timer. */
+  u8_t nrtx;          /**< The number of retransmissions for the last
+			 segment sent. */
+
+  /** The application state. */
+  u8_t appstate[UIP_APPSTATE_SIZE];  
+};
+
+
+/* Pointer to the current connection. */
+extern struct uip_conn *uip_conn;
+/* The array containing all uIP connections. */
+extern struct uip_conn uip_conns[UIP_CONNS];
+/**
+ * \addtogroup uiparch
+ * @{
+ */
+
+/**
+ * 4-byte array used for the 32-bit sequence number calculations.
+ */
+extern u8_t uip_acc32[4];
+
+/** @} */
+
+
+#if UIP_UDP
+/**
+ * Representation of a uIP UDP connection.
+ */
+struct uip_udp_conn {
+  u16_t ripaddr[2];   /**< The IP address of the remote peer. */
+  u16_t lport;        /**< The local port number in network byte order. */
+  u16_t rport;        /**< The remote port number in network byte order. */
+  
+  /** The application state. */
+  u8_t appstate[UIP_APPSTATE_SIZE];    
+};
+
+extern struct uip_udp_conn *uip_udp_conn;
+extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+/**
+ * The structure holding the TCP/IP statistics that are gathered if
+ * UIP_STATISTICS is set to 1.
+ *
+ */
+struct uip_stats {
+  struct {
+    uip_stats_t drop;     /**< Number of dropped packets at the IP
+			     layer. */
+    uip_stats_t recv;     /**< Number of received packets at the IP
+			     layer. */
+    uip_stats_t sent;     /**< Number of sent packets at the IP
+			     layer. */
+    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, UDP nor TCP. */
+  } ip;                   /**< IP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped ICMP packets. */
+    uip_stats_t recv;     /**< Number of received ICMP packets. */
+    uip_stats_t sent;     /**< Number of sent ICMP packets. */
+    uip_stats_t typeerr;  /**< Number of ICMP packets with a wrong
+			     type. */
+  } icmp;                 /**< ICMP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped TCP segments. */
+    uip_stats_t recv;     /**< Number of recived TCP segments. */
+    uip_stats_t sent;     /**< Number of sent TCP segments. */
+    uip_stats_t chkerr;   /**< Number of TCP segments with a bad
+			     checksum. */
+    uip_stats_t ackerr;   /**< Number of TCP segments with a bad ACK
+			     number. */
+    uip_stats_t rst;      /**< Number of recevied TCP RST (reset) segments. */
+    uip_stats_t rexmit;   /**< Number of retransmitted TCP segments. */
+    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;                  /**< TCP statistics. */
+};
+
+/**
+ * The uIP TCP/IP statistics.
+ *
+ * This is the variable in which the uIP TCP/IP statistics are gathered.
+ */
+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 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. These values are never used directly, but only in
+   the macrose defined in this file. */
+ 
+#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. */
+#define UIP_POLL_REQUEST  3     /* Tells uIP that a connection should
+				   be polled. */
+#if UIP_UDP
+#define UIP_UDP_TIMER     4
+#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
+
+#define UIP_TCPIP_HLEN 40
+
+/**
+ * The buffer size available for user data in the \ref uip_buf buffer.
+ *
+ * This macro holds the available size for user data in the \ref
+ * uip_buf buffer. The macro is intended to be used for checking
+ * bounds of available user data.
+ *
+ * Example:
+ \code
+ snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i);
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
+
+/* The TCP and IP headers. */
+typedef struct {
+  /* IP header. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  
+  /* 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. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  /* 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. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  
+  /* 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
+
+/* Header sizes. */
+#define UIP_IPH_LEN    20    /* Size of IP header */
+#define UIP_UDPH_LEN    8    /* Size of UDP header */
+#define UIP_TCPH_LEN   20    /* Size of TCP header */
+#define UIP_IPUDPH_LEN 28    /* Size of IP + UDP header */
+#define UIP_IPTCPH_LEN 40    /* Size of IP + TCP header */
+
+
+
+#if UIP_FIXEDADDR
+extern const u16_t uip_hostaddr[2], uip_netmask[2], uip_draddr[2];
+#else /* UIP_FIXEDADDR */
+extern u16_t uip_hostaddr[2], uip_netmask[2], uip_draddr[2];
+#endif /* UIP_FIXEDADDR */
+
+
+
+/**
+ * Representation of a 48-bit Ethernet address.
+ */
+struct uip_eth_addr {
+  u8_t addr[6];
+};
+
+#endif /* __UIP_H__ */
+
+
+/** @} */
+
diff --git a/contiki/uip/uip_arch.h b/contiki/uip/uip_arch.h
new file mode 100644
index 0000000..4c13f6e
--- /dev/null
+++ b/contiki/uip/uip_arch.h
@@ -0,0 +1,138 @@
+/**
+ * \addtogroup uip
+ * {@
+ */
+
+/**
+ * \defgroup uiparch Architecture specific uIP functions
+ * @{
+ *
+ * The functions in the architecture specific module implement the IP
+ * check sum and 32-bit additions.
+ *
+ * The IP checksum calculation is the most computationally expensive
+ * operation in the TCP/IP stack and it therefore pays off to
+ * implement this in efficient assembler. The purpose of the uip-arch
+ * module is to let the checksum functions to be implemented in
+ * architecture specific assembler.
+ *
+ */
+
+/**
+ * \file
+ * Declarations of architecture specific functions.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * 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. 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_arch.h,v 1.3 2004/09/18 20:17:33 adamdunkels Exp $
+ *
+ */
+
+#ifndef __UIP_ARCH_H__
+#define __UIP_ARCH_H__
+
+#include "uip.h"
+
+/**
+ * Carry out a 32-bit addition.
+ *
+ * Because not all architectures for which uIP is intended has native
+ * 32-bit arithmetic, uIP uses an external C function for doing the
+ * required 32-bit additions in the TCP protocol processing. This
+ * function should add the two arguments and place the result in the
+ * global variable uip_acc32.
+ *
+ * \note The 32-bit integer pointed to by the op32 parameter and the
+ * result in the uip_acc32 variable are in network byte order (big
+ * endian).
+ *
+ * \param op32 A pointer to a 4-byte array representing a 32-bit
+ * integer in network byte order (big endian).
+ *
+ * \param op16 A 16-bit integer in host byte order.
+ */
+void uip_add32(u8_t *op32, u16_t op16);
+
+/**
+ * Calculate the Internet checksum over a buffer.
+ *
+ * The Internet checksum is the one's complement of the one's
+ * complement sum of all 16-bit words in the buffer.
+ *
+ * See RFC1071.
+ *
+ * \note This function is not called in the current version of uIP,
+ * but future versions might make use of it.
+ *
+ * \param buf A pointer to the buffer over which the checksum is to be
+ * computed.
+ *
+ * \param len The length of the buffer over which the checksum is to
+ * be computed.
+ *
+ * \return The Internet checksum of the buffer.
+ */
+u16_t uip_chksum(u16_t *buf, u16_t len);
+
+/**
+ * Calculate the IP header checksum of the packet header in uip_buf.
+ *
+ * The IP header checksum is the Internet checksum of the 20 bytes of
+ * the IP header.
+ *
+ * \return The IP header checksum of the IP header in the uip_buf
+ * buffer.
+ */
+u16_t uip_ipchksum(void);
+
+/**
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The TCP checksum is the Internet checksum of data contents of the
+ * TCP segment, and a pseudo-header as defined in RFC793.
+ *
+ * \note The uip_appdata pointer that points to the packet data may
+ * point anywhere in memory, so it is not possible to simply calculate
+ * the Internet checksum of the contents of the uip_buf buffer.
+ *
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_tcpchksum(void);
+
+u16_t uip_udpchksum(void);
+
+/** @} */
+/** @} */
+
+#endif /* __UIP_ARCH_H__ */
diff --git a/contiki/uip/uip_arp.c b/contiki/uip/uip_arp.c
new file mode 100644
index 0000000..40f6e23
--- /dev/null
+++ b/contiki/uip/uip_arp.c
@@ -0,0 +1,427 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uiparp uIP Address Resolution Protocol
+ * @{
+ * 
+ * The Address Resolution Protocol ARP is used for mapping between IP
+ * addresses and link level addresses such as the Ethernet MAC
+ * addresses. ARP uses broadcast queries to ask for the link level
+ * address of a known IP address and the host which is configured with
+ * the IP address for which the query was meant, will respond with its
+ * link level address.
+ *
+ * \note This ARP implementation only supports Ethernet.
+ */
+ 
+/**
+ * \file
+ * Implementation of the ARP Address Resolution Protocol.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2003, 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. 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.15 2005/02/23 22:40:40 oliverschmidt Exp $
+ *
+ */
+
+
+#include "uip_arp.h"
+
+#include <string.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
+
+struct arp_entry {
+  u16_t ipaddr[2];
+  struct uip_eth_addr ethaddr;
+  u8_t time;
+};
+
+static const struct uip_eth_addr broadcast_ethaddr =
+  {{0xff,0xff,0xff,0xff,0xff,0xff}};
+static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff};
+
+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])
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Initialize the ARP module.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_init(void)
+{
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    memset(arp_table[i].ipaddr, 0, 4);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Periodic ARP processing function.
+ *
+ * This function performs periodic timer processing in the ARP module
+ * and should be called at regular intervals. The recommended interval
+ * is 10 seconds between the calls.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_timer(void)
+{
+  struct arp_entry *tabptr;
+  
+  ++arptime;
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    tabptr = &arp_table[i];
+    if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
+       arptime - tabptr->time >= UIP_ARP_MAXAGE) {
+      memset(tabptr->ipaddr, 0, 4);
+    }
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
+{
+  register struct arp_entry *tabptr;
+  /* 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) {
+
+    tabptr = &arp_table[i];
+    /* Only check those entries that are actually in use. */
+    if(tabptr->ipaddr[0] != 0 &&
+       tabptr->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] == tabptr->ipaddr[0] &&
+	 ipaddr[1] == tabptr->ipaddr[1]) {
+	 
+	/* An old entry found, update this and return. */
+	memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
+	tabptr->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) {
+    tabptr = &arp_table[i];
+    if(tabptr->ipaddr[0] == 0 &&
+       tabptr->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) {
+      tabptr = &arp_table[i];
+      if(arptime - tabptr->time > tmpage) {
+	tmpage = arptime - tabptr->time;
+	c = i;
+      }
+    }
+    i = c;
+    tabptr = &arp_table[i];
+  }
+
+  /* Now, i is the ARP table entry which we will fill with the new
+     information. */
+  memcpy(tabptr->ipaddr, ipaddr, 4);
+  memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
+  tabptr->time = arptime;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * ARP processing for incoming IP packets
+ *
+ * This function should be called by the device driver when an IP
+ * packet has been received. The function will check if the address is
+ * in the ARP cache, and if so the ARP cache entry will be
+ * refreshed. If no ARP cache entry was found, a new one is created.
+ *
+ * This function expects an IP packet with a prepended Ethernet header
+ * in the uip_buf[] buffer, and the length of the packet in the global
+ * variable uip_len.
+ */
+/*-----------------------------------------------------------------------------------*/
+#if 0
+void
+uip_arp_ipin(void)
+{
+  uip_len -= sizeof(struct uip_eth_hdr);
+	
+  /* 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] & uip_netmask[0]) !=
+     (uip_hostaddr[0] & uip_netmask[0])) {
+    return;
+  }
+  if((IPBUF->srcipaddr[1] & uip_netmask[1]) !=
+     (uip_hostaddr[1] & uip_netmask[1])) {
+    return;
+  }
+  uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
+  
+  return;
+}
+#endif /* 0 */
+/*-----------------------------------------------------------------------------------*/
+/**
+ * ARP processing for incoming ARP packets.
+ *
+ * This function should be called by the device driver when an ARP
+ * packet has been received. The function will act differently
+ * depending on the ARP packet type: if it is a reply for a request
+ * that we previously sent out, the ARP cache will be filled in with
+ * the values from the ARP reply. If the incoming ARP packet is an ARP
+ * request for our IP address, an ARP reply packet is created and put
+ * into the uip_buf[] buffer.
+ *
+ * When the function returns, the value of the global variable uip_len
+ * indicates whether the device driver should send out a packet or
+ * not. If uip_len is zero, no packet should be sent. If uip_len is
+ * non-zero, it contains the length of the outbound packet that is
+ * present in the uip_buf[] buffer.
+ *
+ * This function expects an ARP packet with a prepended Ethernet
+ * header in the uip_buf[] buffer, and the length of the packet in the
+ * global variable uip_len.
+ */
+/*-----------------------------------------------------------------------------------*/
+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]) {*/
+    if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
+      /* First, we register the one who made the request in our ARP
+	 table, since it is likely that we will do more communication
+	 with this host in the future. */
+      uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
+      
+      /* The reply opcode is 2. */
+      BUF->opcode = HTONS(2);
+
+      memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
+      memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
+      memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
+      memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
+      
+      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]) {*/
+    if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
+      uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
+    }
+    break;
+  }
+
+  return;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Prepend Ethernet header to an outbound IP packet and see if we need
+ * to send out an ARP request.
+ *
+ * This function should be called before sending out an IP packet. The
+ * function checks the destination IP address of the IP packet to see
+ * what Ethernet MAC address that should be used as a destination MAC
+ * address on the Ethernet.
+ *
+ * If the destination IP address is in the local network (determined
+ * by logical ANDing of netmask and our IP address), the function
+ * checks the ARP cache to see if an entry for the destination IP
+ * address is found. If so, an Ethernet header is prepended and the
+ * function returns. If no ARP cache entry is found for the
+ * destination IP address, the packet in the uip_buf[] is replaced by
+ * an ARP request packet for the IP address. The IP packet is dropped
+ * and it is assumed that they higher level protocols (e.g., TCP)
+ * eventually will retransmit the dropped packet.
+ *
+ * If the destination IP address is not on the local network, the IP
+ * address of the default router is used instead.
+ *
+ * When the function returns, a packet is present in the uip_buf[]
+ * buffer, and the length of the packet is in the global variable
+ * uip_len.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_out(void)
+{
+  struct arp_entry *tabptr;
+  
+  /* 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. */
+
+  /* First check if destination is a local broadcast. */
+  if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) {
+    memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
+  } else {
+    /* Check if the destination address is on the local network. */
+    if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) {
+      /* 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. */
+      uip_ipaddr_copy(ipaddr, uip_draddr); 
+    } else {
+      /* Else, we use the destination IP address. */
+      uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); 
+    }
+      
+    for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+      tabptr = &arp_table[i];
+      if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) {
+	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. */
+
+      memset(BUF->ethhdr.dest.addr, 0xff, 6);
+      memset(BUF->dhwaddr.addr, 0x00, 6);
+      memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
+      memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
+    
+      uip_ipaddr_copy(BUF->dipaddr, ipaddr);
+      uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);
+      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[UIP_TCPIP_HLEN + UIP_LLH_LEN];
+    
+      uip_len = sizeof(struct arp_hdr);
+      return;
+    }
+
+    /* Build an ethernet header. */
+    memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
+  }
+  memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
+  
+  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..3c2e8c7
--- /dev/null
+++ b/contiki/uip/uip_arp.h
@@ -0,0 +1,146 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \addtogroup uiparp 
+ * @{
+ */
+ 
+/**
+ * \file
+ * Macros and definitions for the ARP module.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+  
+
+/*
+ * Copyright (c) 2001-2003, 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. 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.10 2004/09/17 20:59:23 adamdunkels Exp $
+ *
+ */
+
+#ifndef __UIP_ARP_H__
+#define __UIP_ARP_H__
+
+#include "uip.h"
+
+
+extern struct uip_eth_addr uip_ethaddr;
+
+/**
+ * The Ethernet header. 
+ */
+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);*/
+#define uip_arp_ipin()
+
+/* 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);
+
+/** @} */
+
+/**
+ * \addtogroup uipconffunc
+ * @{
+ */
+
+
+/**
+ * Specifiy the Ethernet MAC address.
+ *
+ * The ARP code needs to know the MAC address of the Ethernet card in
+ * order to be able to respond to ARP queries and to generate working
+ * Ethernet headers.
+ *
+ * \note This macro only specifies the Ethernet MAC address to the ARP
+ * code. It cannot be used to change the MAC address of the Ethernet
+ * card.
+ *
+ * \param eaddr A pointer to a struct uip_eth_addr containing the
+ * Ethernet MAC address of the Ethernet card.
+ *
+ * \hideinitializer
+ */
+#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \
+                              uip_ethaddr.addr[1] = eaddr.addr[1];\
+                              uip_ethaddr.addr[2] = eaddr.addr[2];\
+                              uip_ethaddr.addr[3] = eaddr.addr[3];\
+                              uip_ethaddr.addr[4] = eaddr.addr[4];\
+                              uip_ethaddr.addr[5] = eaddr.addr[5];} while(0)
+
+/** @} */
+
+
+#endif /* __UIP_ARP_H__ */
+
+
diff --git a/contiki/uip/uipbuf.c b/contiki/uip/uipbuf.c
new file mode 100644
index 0000000..f574b6e
--- /dev/null
+++ b/contiki/uip/uipbuf.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uipbuf.c,v 1.6 2004/09/12 20:24:56 adamdunkels Exp $
+ */
+
+#include "uipbuf.h"
+
+#include <string.h>
+
+/*---------------------------------------------------------------------------*/
+void
+uipbuf_setup(struct uipbuf_buffer *buf,
+	     u8_t *bufptr, u16_t bufsize)
+{
+  buf->buffer = buf->ptr = bufptr;
+  buf->bufsize = buf->left = bufsize;
+}
+/*---------------------------------------------------------------------------*/
+u8_t
+uipbuf_bufdata(struct uipbuf_buffer *buf, u16_t len,
+	       u8_t **dataptr, u16_t *datalen)
+{
+  if(*datalen < buf->left) {
+    memcpy(buf->ptr, *dataptr, *datalen);
+    buf->ptr += *datalen;
+    buf->left -= *datalen;
+    *dataptr += *datalen;
+    *datalen = 0;
+    return UIPBUF_NOT_FULL;
+  } else if(*datalen == buf->left) {
+    memcpy(buf->ptr, *dataptr, *datalen);
+    buf->ptr += *datalen;
+    buf->left = 0;
+    *dataptr += *datalen;
+    *datalen = 0;
+    return UIPBUF_FULL;
+  } else {
+    memcpy(buf->ptr, *dataptr, buf->left);
+    buf->ptr += buf->left;
+    *datalen -= buf->left;
+    *dataptr += buf->left;
+    buf->left = 0;
+    return UIPBUF_FULL;
+  }
+
+}
+/*---------------------------------------------------------------------------*/
+u8_t
+uipbuf_bufto(register struct uipbuf_buffer *buf, u8_t endmarker,
+	     register u8_t **dataptr, register u16_t *datalen)
+{
+  u8_t c;
+  /*
+  int len;
+
+  ptr = memchr(*dataptr, endmarker, *datalen);
+  if(ptr != NULL) {
+    len = ptr - *dataptr;
+  } else {
+    len = *datalen;
+  }
+  memcpy(buf->ptr, *dataptr, len);
+  *dataptr += len;
+  *datalen -= len;
+  buf->ptr += len;
+  */
+  while(buf->left > 0 && *datalen > 0) {
+    c = *buf->ptr = **dataptr;
+    ++*dataptr;
+    ++buf->ptr;
+    --*datalen;
+    --buf->left;
+    
+    if(c == endmarker) {
+      return UIPBUF_FOUND;
+    }
+  }
+
+  if(*datalen == 0) {
+    return UIPBUF_NOT_FOUND;
+  }
+
+  while(*datalen > 0) {
+    c = **dataptr;
+    --*datalen;
+    ++*dataptr;
+    
+    if(c == endmarker) {
+      return UIPBUF_FOUND | UIPBUF_FULL;
+    }
+  }
+  
+  return UIPBUF_FULL;
+}
+/*----------------------------------------------------------------------------*/
+u16_t
+uipbuf_len(struct uipbuf_buffer *buf)
+{
+  return buf->bufsize - buf->left;
+}
+/*----------------------------------------------------------------------------*/
diff --git a/contiki/uip/uipbuf.h b/contiki/uip/uipbuf.h
new file mode 100644
index 0000000..ff14a01
--- /dev/null
+++ b/contiki/uip/uipbuf.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 operating system.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: uipbuf.h,v 1.3 2004/09/12 20:24:56 adamdunkels Exp $
+ */
+/**
+ * \file
+ * uIP data buffering helper functions.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#ifndef __UIPBUF_H__
+#define __UIPBUF_H__
+
+#include "uip.h"
+
+/**
+ * \defgroup uipbuf uIP data buffering helper library.
+ *
+ * The event driven API that uIP uses can be tricky to use when
+ * dealing with incoming TCP data. The data can be split over any
+ * number of incoming segments and uIP does not provide any stream
+ * abstraction by itself. To remedy this, the uIP data buffering
+ * helper library provides a set of functions that make buffering data
+ * easier.
+ *
+ * The data buffering library provides a structure that holds a
+ * pointer to a buffer and the state of the buffer, as well as a set
+ * of functions for manipulating the buffer state. The functions are
+ * intended to facilitate buffering of both data that is of a known
+ * size and data that is terminated by a specified byte.
+ *
+ * @{
+ */
+
+/**
+ * Return value of the buffering functions that indicates that a
+ * buffer was not filled by incoming data.
+ *
+ * \hideinitializer
+ */
+#define UIPBUF_NOT_FULL 0
+#define UIPBUF_NOT_FOUND 0
+
+/**
+ * Return value of the buffering functions that indicates that a
+ * buffer was completely filled by incoming data.
+ *
+ * \hideinitializer
+ */
+#define UIPBUF_FULL 1
+
+/**
+ * Return value of the buffering functions that indicates that an
+ * end-marker byte was found.
+ *
+ * \hideinitializer
+ */
+#define UIPBUF_FOUND 2
+
+/**
+ * The structure that holds the state of a uIP buffer.
+ *
+ * This structure holds the state of a uIP buffer. The structure has
+ * no user-visible elements, but is used through the functions
+ * provided by the library.
+ *
+ * \hideinitializer
+ */
+struct uipbuf_buffer {
+  u8_t *ptr, *buffer;
+  unsigned short left, bufsize;
+};
+
+/**
+ * Set up a new uIP buffer structure.
+ *
+ * This function is used for setting up a uIP buffer structure with a
+ * specified size. The function should be called the first time a uIP
+ * buffer is used. The caller must provide the memory for holding the
+ * buffered bytes and the size of the buffer memory.
+ *
+ * \param buf A pointer to a uipbuf_buffer structure that is to be
+ * initialized.
+ *
+ * \param bufptr A pointer to the memory for holding the buffered
+ * data.
+ * 
+ * \param size The size of the buffer memory.
+ *
+ */
+void uipbuf_setup(struct uipbuf_buffer *buf,
+		  u8_t *bufptr, u16_t size);
+
+/**
+ * Buffer data until the buffer is full.
+ *
+ * This function puts data into the buffer, but no more than the
+ * buffer can hold.
+ *
+ * \param buf A pointer to the ::uipbuf_buffer structure that holds
+ * the state of the buffer.
+ *
+ * \param dataptr A pointer to the data that is to be buffered.
+ *
+ * \param datalen The length of the data that is to be buffered.
+ *
+ * \return If the buffer was not filled, the value UIPBUF_NOT_FULL
+ * is returned. If the buffer was filled, the number of bytes that
+ * could not be buffered is returned. If the buffer was exactly filled
+ * with the data, the value of 0 is returned.
+ *
+ */
+u8_t uipbuf_bufdata(struct uipbuf_buffer *buf, u16_t len,
+		    u8_t **dataptr, u16_t *datalen);
+
+/**
+ * Buffer data until a specific character is found or the buffer is full.
+ *
+ * This function puts data into the buffer until a specific marker
+ * byte is found. The marker byte is put into the buffer at the end of
+ * the data.
+ *
+ * \param buf A pointer to the ::uipbuf_buffer structure that holds
+ * the state of the buffer.
+ *
+ * \param dataptr A pointer to the data that is to be buffered.
+ *
+ * \param datalen The length of the data that is to be buffered.
+ *
+ * \param byte The end-marker byte that indicates the end of the data
+ * that is to be buffered.
+ * 
+ * \return This function returns the number of protruding bytes after
+ * the end-marker byte, if the marker was found. If the marker was not
+ * found and all of the data was buffered, the value of
+ * UIPBUF_NOT_FOUND is returned. If the marker was not found, but the
+ * data made the buffer fill up, the value of UIPBUF_FULL is returned.
+ *
+ */
+u8_t uipbuf_bufto(struct uipbuf_buffer *buf, u8_t endmarker,
+		  u8_t **dataptr, u16_t *datalen);
+
+u16_t uipbuf_len(struct uipbuf_buffer *buf);
+
+/** @} */
+
+#endif /* __UIPBUF_H__ */
diff --git a/contiki/uip/uiplib.c b/contiki/uip/uiplib.c
new file mode 100644
index 0000000..c239d23
--- /dev/null
+++ b/contiki/uip/uiplib.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2004, Adam Dunkels and the Swedish Institute of
+ * Computer Science.
+ * 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. 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 and the Contiki operating system.
+ *
+ * $Id: uiplib.c,v 1.3 2004/09/12 20:24:56 adamdunkels Exp $
+ *
+ */
+
+
+#include "uip.h"
+#include "uip_arp.h"
+
+#include "uiplib.h"
+
+#include "ek.h"
+
+/*-----------------------------------------------------------------------------------*/
+unsigned char
+uiplib_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/uiplib.h b/contiki/uip/uiplib.h
new file mode 100644
index 0000000..09af1fb
--- /dev/null
+++ b/contiki/uip/uiplib.h
@@ -0,0 +1,71 @@
+/**
+ * \file
+ * Various uIP library functions.
+ * \author
+ * Adam Dunkels <adam@sics.se>
+ *
+ */
+
+/*
+ * 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. 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: uiplib.h,v 1.2 2004/03/18 21:07:00 adamdunkels Exp $
+ *
+ */
+#ifndef __UIPLIB_H__
+#define __UIPLIB_H__
+
+/**
+ * \addtogroup uipconvfunc
+ * @{
+ */
+
+/**
+ * Convert a textual representation of an IP address to a numerical representation.
+ *
+ * This function takes a textual representation of an IP address in
+ * the form a.b.c.d and converts it into a 4-byte array that can be
+ * used by other uIP functions.
+ *
+ * \param addrstr A pointer to a string containing the IP address in
+ * textual form.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the numerical representation of the address.
+ *
+ * \retval 0 If the IP address could not be parsed.
+ * \retval Non-zero If the IP address was parsed. 
+ */
+unsigned char uiplib_ipaddrconv(char *addrstr, unsigned char *addr);
+
+/** @} */
+
+#endif /* __UIPLIB_H__ */
diff --git a/contiki/uip/uipopt.h b/contiki/uip/uipopt.h
new file mode 100644
index 0000000..9f88594
--- /dev/null
+++ b/contiki/uip/uipopt.h
@@ -0,0 +1,570 @@
+/**
+ * \defgroup uipopt Configuration options for uIP
+ * @{
+ *
+ * uIP is configured using the per-project configuration file
+ * "uipopt.h". This file contains all compile-time options for uIP and
+ * should be tweaked to match each specific project. The uIP
+ * distribution contains a documented example "uipopt.h" that can be
+ * copied and modified for each project.
+ *
+ * \note Contiki does not use the uipopt.h file to configure uIP, but
+ * uses a per-port uip-conf.h file that should be edited instead.
+ */
+
+/**
+ * \file
+ * Configuration options for uIP.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * 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.
+ */
+
+/*
+ * Copyright (c) 2001-2003, 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. 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.16 2005/02/24 22:25:12 oliverschmidt Exp $
+ *
+ */
+
+#ifndef __UIPOPT_H__
+#define __UIPOPT_H__
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN  3412
+#endif /* LITTLE_ENDIAN */
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN     1234
+#endif /* BIGE_ENDIAN */
+
+#include "uip-conf.h"
+
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipopttypedef uIP type definitions
+ * @{
+ */
+
+/**
+ * The 8-bit unsigned data type.
+ *
+ * This may have to be tweaked for your particular compiler. "unsigned
+ * char" works for most compilers.
+ */
+typedef unsigned char u8_t;
+
+/**
+ * The 16-bit unsigned data type.
+ *
+ * This may have to be tweaked for your particular compiler. "unsigned
+ * short" works for most compilers.
+ */
+typedef unsigned short u16_t;
+
+/**
+ * The statistics data type.
+ *
+ * This datatype determines how high the statistics counters are able
+ * to count.
+ */
+typedef unsigned short uip_stats_t;
+
+/** @} */
+
+#include "tcpip.h"
+
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \defgroup uipoptstaticconf Static configuration options
+ * @{
+ *
+ * These configuration options can be used for setting the IP address
+ * settings statically, but only if UIP_FIXEDADDR is set to 1. The
+ * configuration options for a specific node 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.
+*/
+
+/**
+ * Determines if uIP should use a fixed IP address or not.
+ *
+ * If uIP should use a fixed IP address, the settings are set in the
+ * uipopt.h file. If not, the macros uip_sethostaddr(),
+ * uip_setdraddr() and uip_setnetmask() should be used instead.
+ *
+ * \hideinitializer
+ */
+#define UIP_FIXEDADDR    0
+
+/**
+ * Ping IP address asignment.
+ *
+ * uIP uses a "ping" packets for setting its own IP address if this
+ * option is set. If so, uIP will start with an empty IP address and
+ * the destination IP address of the first incoming "ping" (ICMP echo)
+ * packet will be used for setting the hosts IP address.
+ *
+ * \note This works only if UIP_FIXEDADDR is 0.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_PINGADDRCONF
+#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF
+#else /* UIP_CONF_PINGADDRCONF */
+#define UIP_PINGADDRCONF 0
+#endif /* UIP_CONF_PINGADDRCONF */
+
+
+/**
+ * Specifies if the uIP ARP module should be compiled with a fixed
+ * Ethernet MAC address or not.
+ *
+ * If this configuration option is 0, the macro uip_setethaddr() can
+ * be used to specify the Ethernet address at run-time.
+ *
+ * \hideinitializer
+ */
+#define UIP_FIXEDETHADDR 0
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptip IP configuration options
+ * @{
+ *
+ */
+/**
+ * The IP TTL (time to live) of IP packets sent by uIP.
+ *
+ * This should normally not be changed.
+ */
+#define UIP_TTL         255
+
+/**
+ * Turn on support for IP packet reassembly.
+ *
+ * uIP supports reassembly of fragmented IP packets. This features
+ * requires an additonal amount of RAM to hold the reassembly buffer
+ * and the reassembly code size is approximately 700 bytes.  The
+ * reassembly buffer is of the same size as the uip_buf buffer
+ * (configured by UIP_BUFSIZE).
+ *
+ * \note IP packet reassembly is not heavily tested.
+ *
+ * \hideinitializer
+ */
+#define UIP_REASSEMBLY 0
+
+/**
+ * The maximum time an IP fragment should wait in the reassembly
+ * buffer before it is dropped.
+ *
+ */
+#define UIP_REASS_MAXAGE 40
+
+/** @} */
+
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptudp UDP configuration options
+ * @{
+ *
+ * \note The UDP support in uIP is still not entirely complete; there
+ * is no support for sending or receiving broadcast or multicast
+ * packets, but it works well enough to support a number of vital
+ * applications such as DNS queries, though
+ */
+
+/**
+ * Toggles wether UDP support should be compiled in or not.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_UDP
+#define UIP_UDP UIP_CONF_UDP
+#else /* UIP_CONF_UDP */
+#define UIP_UDP           1
+#endif /* UIP_CONF_UDP */
+
+/**
+ * Toggles if UDP checksums should be used or not.
+ *
+ * \note Support for UDP checksums is currently not included in uIP,
+ * so this option has no function.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_UDP_CHECKSUMS
+#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS
+#else
+#define UIP_UDP_CHECKSUMS 0
+#endif
+
+/**
+ * The maximum amount of concurrent UDP connections.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_UDP_CONNS
+#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS
+#else /* UIP_CONF_UDP_CONNS */
+#define UIP_UDP_CONNS    10
+#endif /* UIP_CONF_UDP_CONNS */
+
+/**
+ * The name of the function that should be called when UDP datagrams arrive.
+ *
+ * \hideinitializer
+ */
+
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipopttcp TCP configuration options
+ * @{
+ */
+
+/**
+ * Determines if support for opening connections from uIP should be
+ * compiled in.
+ *
+ * If the applications that are running on top of uIP for this project
+ * do not need to open outgoing TCP connections, this configration
+ * option can be turned off to reduce the code size of uIP.
+ *
+ * \hideinitializer
+ */
+#define UIP_ACTIVE_OPEN 1
+
+/**
+ * The maximum number of simultaneously open TCP connections.
+ *
+ * Since the TCP connections are statically allocated, turning this
+ * configuration knob down results in less RAM used. Each TCP
+ * connection requires approximatly 30 bytes of memory.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_MAX_CONNECTIONS
+#define UIP_CONNS       10
+#else /* UIP_CONF_MAX_CONNECTIONS */
+#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS
+#endif /* UIP_CONF_MAX_CONNECTIONS */
+
+
+/**
+ * The maximum number of simultaneously listening TCP ports.
+ *
+ * Each listening TCP port requires 2 bytes of memory.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_MAX_LISTENPORTS
+#define UIP_LISTENPORTS 20
+#else /* UIP_CONF_MAX_LISTENPORTS */
+#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS       
+#endif /* UIP_CONF_MAX_LISTENPORTS */
+
+/**
+ * The size of the advertised receiver's window.
+ *
+ * Should be set low (i.e., to the size of the uip_buf buffer) is the
+ * application is slow to process incoming data, or high (32768 bytes)
+ * if the application processes data quickly.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_RECEIVE_WINDOW
+#define UIP_RECEIVE_WINDOW   32768U
+#else
+#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW
+#endif
+
+/**
+ * Determines if support for TCP urgent data notification should be
+ * compiled in.
+ *
+ * Urgent data (out-of-band data) is a rarely used TCP feature that
+ * very seldom would be required.
+ *
+ * \hideinitializer
+ */
+#define UIP_URGDATA      0
+
+/**
+ * The initial retransmission timeout counted in timer pulses.
+ *
+ * This should not be changed.
+ */
+#define UIP_RTO         3
+
+/**
+ * The maximum number of times a segment should be retransmitted
+ * before the connection should be aborted.
+ *
+ * This should not be changed.
+ */
+#define UIP_MAXRTX      8
+
+/**
+ * The maximum number of times a SYN segment should be retransmitted
+ * before a connection request should be deemed to have been
+ * unsuccessful.
+ *
+ * This should not need to be changed.
+ */
+#define UIP_MAXSYNRTX      5
+
+/**
+ * The TCP maximum segment size.
+ *
+ * This is should not be to set to more than
+ * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN.
+ */
+#define UIP_TCP_MSS     (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
+
+/**
+ * How long a connection should stay in the TIME_WAIT state.
+ *
+ * This configiration option has no real implication, and it should be
+ * left untouched.
+ */ 
+#define UIP_TIME_WAIT_TIMEOUT 120
+
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptarp ARP configuration options
+ * @{
+ */
+
+/**
+ * The size of the ARP table.
+ *
+ * This option should be set to a larger value if this uIP node will
+ * have many connections from the local network.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_ARPTAB_SIZE
+#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE
+#else
+#define UIP_ARPTAB_SIZE 8
+#endif
+
+/**
+ * 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
+
+/** @} */
+
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \defgroup uipoptgeneral General configuration options
+ * @{
+ */
+
+/**
+ * The size of the uIP packet buffer.
+ *
+ * The uIP packet buffer should not be smaller than 60 bytes, and does
+ * not need to be larger than 1500 bytes. Lower size results in lower
+ * TCP throughput, larger size results in higher TCP throughput.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_BUFFER_SIZE
+#define UIP_BUFSIZE     400
+#else /* UIP_CONF_BUFFER_SIZE */
+#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE
+#endif /* UIP_CONF_BUFFER_SIZE */
+
+
+/**
+ * Determines if statistics support should be compiled in.
+ *
+ * The statistics is useful for debugging and to show the user.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_STATISTICS
+#define UIP_STATISTICS  0
+#else /* UIP_CONF_STATISTICS */
+#define UIP_STATISTICS UIP_CONF_STATISTICS
+#endif /* UIP_CONF_STATISTICS */
+
+/**
+ * Determines if logging of certain events should be compiled in.
+ *
+ * This is useful mostly for debugging. The function uip_log()
+ * must be implemented to suit the architecture of the project, if
+ * logging is turned on.
+ *
+ * \hideinitializer
+ */
+#ifndef UIP_CONF_LOGGING
+#define UIP_LOGGING     0
+#else /* UIP_CONF_LOGGING */
+#define UIP_LOGGING     UIP_CONF_LOGGING
+#endif /* UIP_CONF_LOGGING */
+
+/**
+ * Broadcast support.
+ *
+ * This flag configures IP broadcast support. This is useful only
+ * together with UDP.
+ *
+ * \hideinitializer
+ *
+ */
+#ifndef UIP_CONF_BROADCAST
+#define UIP_BROADCAST 0
+#else /* UIP_CONF_BROADCAST */
+#define UIP_BROADCAST UIP_CONF_BROADCAST
+#endif /* UIP_CONF_BROADCAST */
+
+/**
+ * Print out a uIP log message.
+ *
+ * This function must be implemented by the module that uses uIP, and
+ * is called by uIP whenever a log message is generated.
+ */
+void uip_log(char *msg);
+
+/**
+ * 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.
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_LLH_LEN
+#define UIP_LLH_LEN UIP_CONF_LLH_LEN
+#else /* UIP_CONF_LLH_LEN */
+#define UIP_LLH_LEN     14
+#endif /* UIP_CONF_LLH_LEN */
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptcpu CPU architecture configuration
+ * @{
+ *
+ * The CPU architecture configuration is where the endianess of the
+ * CPU on which uIP is to be run is specified. Most CPUs today are
+ * little endian, and the most notable exception are the Motorolas
+ * which are big endian. The BYTE_ORDER macro should be changed to
+ * reflect the CPU architecture on which uIP is to be run.
+ */
+
+/**
+ * The byte order of the CPU architecture on which uIP is to be run.
+ *
+ * This option can be either BIG_ENDIAN (Motorola byte order) or
+ * LITTLE_ENDIAN (Intel byte order).
+ *
+ * \hideinitializer
+ */
+#ifdef UIP_CONF_BYTE_ORDER
+#define BYTE_ORDER     UIP_CONF_BYTE_ORDER
+#else /* UIP_CONF_BYTE_ORDER */
+#define BYTE_ORDER     LITTLE_ENDIAN
+#endif /* UIP_CONF_BYTE_ORDER */
+
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \defgroup uipoptapp Appication specific configurations
+ * @{
+ *
+ * An uIP application is implemented using a single application
+ * function that is called by uIP whenever a TCP/IP event occurs. The
+ * name of this function must be registered with uIP at compile time
+ * using the UIP_APPCALL definition.
+ *
+ * uIP applications can store the application state within the
+ * uip_conn structure by specifying the size of the application
+ * structure with the UIP_APPSTATE_SIZE macro.
+ *
+ * The file containing the definitions must be included in the
+ * uipopt.h file.
+ *
+ * The following example illustrates how this can look.
+ \code
+
+void httpd_appcall(void);
+#define UIP_APPCALL     httpd_appcall
+
+struct httpd_state {
+  u8_t state; 
+  u16_t count;
+  char *dataptr;
+  char *script;
+};
+#define UIP_APPSTATE_SIZE (sizeof(struct httpd_state))
+ \endcode
+ */
+
+/**
+ * \var #define UIP_APPCALL
+ *
+ * The name of the application function that uIP should call in
+ * response to TCP/IP events.
+ *
+ */
+
+/**
+ * \var #define UIP_APPSTATE_SIZE
+ *
+ * The size of the application state that is to be stored in the
+ * uip_conn structure.
+ */
+/** @} */
+
+
+#endif /* __UIPOPT_H__ */