First version of the AVR port
diff --git a/contiki-avr/apps/webclient.c b/contiki-avr/apps/webclient.c
new file mode 100644
index 0000000..eac5400
--- /dev/null
+++ b/contiki-avr/apps/webclient.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2002, Adam Dunkels.
+ * All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution. 
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgement:
+ *        This product includes software developed by Adam Dunkels. 
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+ *
+ * This file is part of the "contiki" web browser.
+ *
+ * $Id: webclient.c,v 1.1 2003/07/04 10:54:51 adamdunkels Exp $
+ *
+ */
+
+#include "uip.h"
+#include "webclient.h"
+#include "resolv.h"
+#include "uip_main.h"
+
+#include <string.h>
+
+#define WEBCLIENT_TIMEOUT 100
+
+#define WEBCLIENT_STATE_STATUSLINE 0
+#define WEBCLIENT_STATE_HEADERS    1
+#define WEBCLIENT_STATE_DATA       2
+#define WEBCLIENT_STATE_CLOSE      3
+
+#define HTTPFLAG_NONE   0
+#define HTTPFLAG_OK     1
+#define HTTPFLAG_MOVED  2
+#define HTTPFLAG_ERROR  3
+
+
+#define ISO_nl       0x0a
+#define ISO_cr       0x0d
+#define ISO_space    0x20
+
+struct webclient_state {
+  u8_t timer;
+  u8_t state;
+  u8_t httpflag;
+
+  u16_t port;
+  char host[40];
+  char file[100];  
+  u16_t getrequestptr;
+  u16_t getrequestleft;
+  
+  char httpheaderline[200];
+  u16_t httpheaderlineptr;
+
+  char mimetype[32];
+};
+
+static struct webclient_state s;
+
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_mimetype(void)
+{
+  return s.mimetype;
+}
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_filename(void)
+{
+  return s.file;
+}
+/*-----------------------------------------------------------------------------------*/
+char *
+webclient_hostname(void)
+{
+  return s.host;
+}
+/*-----------------------------------------------------------------------------------*/
+unsigned short
+webclient_port(void)
+{
+  return s.port;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+webclient_init(void)
+{
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+init_connection(void)
+{
+  s.state = WEBCLIENT_STATE_STATUSLINE;
+
+  s.getrequestleft = sizeof(http_get) - 1 + 1 +
+    sizeof(http_10) - 1 +
+    sizeof(http_crnl) - 1 +
+    sizeof(http_host) - 1 +
+    sizeof(http_crnl) - 1 +
+    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; 
+  u16_t addr[2];
+  
+  /* First check if the host is an IP address. */
+  ipaddr = &addr[0];
+  if(uip_main_ipaddrconv(host, (unsigned char *)addr) == 0) {    
+    ipaddr = resolv_lookup(host);
+    
+    if(ipaddr == NULL) {
+      return 0;
+    }
+  }
+
+  /* XXX: here we check so that the server does not try to access any
+     hosts on the SICS networks. */
+  if(ipaddr[0] == HTONS((193 << 8) | 10) &&
+     ((htons(ipaddr[1]) >> 8) == 66 ||
+      (htons(ipaddr[1]) >> 8) == 67)) {
+    return 0;
+  } else {
+    conn = uip_connect(ipaddr, port);
+  }
+  
+  if(conn == NULL) {
+    return 0;
+  }
+  
+  dispatcher_markconn(conn, NULL);
+
+  s.port = port;
+  strncpy(s.file, file, sizeof(s.file));
+  strncpy(s.host, host, sizeof(s.host));
+  
+  init_connection();
+  return 1;
+}
+/*-----------------------------------------------------------------------------------*/
+static unsigned char *
+copy_string(unsigned char *dest, unsigned char *src, unsigned char len)
+{
+  return strcpy(dest, src) + len;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+senddata(void)
+{
+  u16_t len;
+  char *getrequest;
+  char *cptr;
+  
+  if(s.getrequestleft > 0) {
+    cptr = getrequest = (char *)uip_appdata;
+
+    cptr = copy_string(cptr, http_get, sizeof(http_get) - 1);
+    cptr = copy_string(cptr, s.file, strlen(s.file));
+    *cptr++ = ISO_space;
+    cptr = copy_string(cptr, http_10, sizeof(http_10) - 1);
+
+    cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
+    
+    cptr = copy_string(cptr, http_host, sizeof(http_host) - 1);
+    cptr = copy_string(cptr, s.host, strlen(s.host));
+    cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
+
+    cptr = copy_string(cptr, http_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 u16_t
+parse_headers(u16_t len)
+{
+  char *cptr;
+  
+  while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
+    s.httpheaderline[s.httpheaderlineptr] = *uip_appdata;
+    ++uip_appdata;
+    --len;
+    if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
+      /* We have an entire HTTP header line in s.httpheaderline, so
+	 we parse it. */
+      if(s.httpheaderline[0] == ISO_cr) {
+	/* This was the last header line (i.e., and empty "\r\n"), so
+	   we are done with the headers and proceed with the actual
+	   data. */
+	s.state = WEBCLIENT_STATE_DATA;
+	return len;
+      }
+
+      s.httpheaderline[s.httpheaderlineptr - 1] = 0;
+      /* Check for specific HTTP header fields. */
+      if(strncmp(s.httpheaderline, http_content_type,
+		 sizeof(http_content_type) - 1) == 0) {
+	/* Found Content-type field. */
+	cptr = strchr(s.httpheaderline, ';');
+	if(cptr != NULL) {
+	  *cptr = 0;
+	}
+	strncpy(s.mimetype, s.httpheaderline +
+		sizeof(http_content_type) - 1, sizeof(s.mimetype));
+      } else if(strncmp(s.httpheaderline, http_location,
+			    sizeof(http_location) - 1) == 0) {
+	strncpy(s.file, s.httpheaderline +
+		sizeof(http_location) - 1, sizeof(s.file));
+	s.file[s.httpheaderlineptr - 1] = 0;
+      }
+
+
+      /* We're done parsing, so we reset the pointer and start the
+	 next line. */
+      s.httpheaderlineptr = 0;      
+    } else {
+      ++s.httpheaderlineptr;
+    }
+  }
+  return len;
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+newdata(void)
+{
+  u16_t len;
+
+  len = uip_datalen();
+
+  if(s.state == WEBCLIENT_STATE_STATUSLINE) {
+    len = parse_statusline(len);
+  }
+  
+  if(s.state == WEBCLIENT_STATE_HEADERS && len > 0) {
+    len = parse_headers(len);
+  }
+
+  if(len > 0 && s.state == WEBCLIENT_STATE_DATA &&
+     s.httpflag != HTTPFLAG_MOVED) {
+    webclient_datahandler((char *)uip_appdata, len);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+DISPATCHER_UIPCALL(webclient_appcall, state)
+{
+  struct uip_conn *conn;
+  DISPATCHER_UIPCALL_ARG(state);
+
+  if(uip_connected()) {
+    s.timer = 0;
+    s.state = WEBCLIENT_STATE_STATUSLINE;
+    senddata();
+    webclient_connected();
+    dispatcher_markconn(uip_conn, &s);
+    return;
+  }
+
+  
+  if(state == NULL) {
+    uip_abort();
+    return;
+  }
+
+  if(s.state == WEBCLIENT_STATE_CLOSE) {
+    webclient_closed();
+    uip_abort();
+    return;
+  }    
+  
+  
+
+  if(uip_aborted()) {
+    webclient_aborted();
+  }
+  if(uip_timedout()) {
+    webclient_timedout();
+  }
+
+  
+  if(uip_acked()) {
+    s.timer = 0;
+    acked();
+  }
+  if(uip_newdata()) {
+    s.timer = 0;
+    newdata();
+  }
+  if(uip_rexmit() ||
+     uip_newdata() ||
+     uip_acked()) {
+    senddata();
+  } else if(uip_poll()) {
+    ++s.timer;
+    if(s.timer == WEBCLIENT_TIMEOUT) {
+      webclient_timedout();
+      uip_abort();
+      return;
+    }
+        /*    senddata();*/
+  }
+
+  if(uip_closed()) {
+    dispatcher_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();
+      }
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/