From fd331c15043f249576b820522b3d78d2b0e33a58 Mon Sep 17 00:00:00 2001
From: Jean-Yves Lamoureux <jylam@lnxscene.org>
Date: Wed, 8 Mar 2006 20:03:24 +0000
Subject: [PATCH]  * Added very preliminary network driver

---
 caca/Makefile.am      |   1 +
 caca/caca.c           |   9 ++
 caca/caca_internals.h |   7 +-
 caca/driver_network.c | 222 ++++++++++++++++++++++++++++++++++++++++++
 configure.ac          |  13 +++
 5 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 caca/driver_network.c

diff --git a/caca/Makefile.am b/caca/Makefile.am
index 841a089..672c2e6 100644
--- a/caca/Makefile.am
+++ b/caca/Makefile.am
@@ -17,6 +17,7 @@ libcaca_la_SOURCES = \
 	driver_slang.c \
 	driver_win32.c \
 	driver_x11.c \
+	driver_network.c \
 	$(NULL)
 libcaca_la_CPPFLAGS = -I$(top_srcdir)/cucul
 libcaca_la_LDFLAGS = -no-undefined
diff --git a/caca/caca.c b/caca/caca.c
index 005faef..ff4226b 100644
--- a/caca/caca.c
+++ b/caca/caca.c
@@ -145,6 +145,11 @@ static int caca_init_driver(caca_t *kk)
         if(!strcasecmp(var, "ncurses"))
             ncurses_init_driver(kk);
         else
+#endif
+#if defined(USE_NETWORK)
+        if(!strcasecmp(var, "network"))
+            network_init_driver(kk);
+        else
 #endif
             return -1;
 
@@ -186,6 +191,10 @@ static int caca_init_driver(caca_t *kk)
     slang_init_driver(kk);
     return 0;
 #endif
+#if defined(USE_NETWORK)
+    network_init_driver(kk);
+    return 0;
+#endif
 
     return -1;
 }
diff --git a/caca/caca_internals.h b/caca/caca_internals.h
index 6e11ef8..2f35c3b 100644
--- a/caca/caca_internals.h
+++ b/caca/caca_internals.h
@@ -53,6 +53,9 @@ enum caca_driver
 #endif
 #if defined(USE_GL)
     CACA_DRIVER_GL = 6,
+#endif
+#if defined(USE_NETWORK)
+    CACA_DRIVER_NETWORK = 7,
 #endif
     CACA_DRIVER_NONE = 0
 };
@@ -76,7 +79,9 @@ void win32_init_driver(caca_t *);
 #if defined(USE_X11)
 void x11_init_driver(caca_t *);
 #endif
-
+#if defined(USE_NETWORK)
+void network_init_driver(caca_t *);
+#endif
 /* Timer structure */
 struct caca_timer
 {
diff --git a/caca/driver_network.c b/caca/driver_network.c
new file mode 100644
index 0000000..4807ee6
--- /dev/null
+++ b/caca/driver_network.c
@@ -0,0 +1,222 @@
+/*
+ *  libcaca       ASCII-Art library
+ *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
+ *                All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the Do What The Fuck You Want To
+ *  Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+/** \file driver_network.c
+ *  \version \$Id: driver_gl.c 330 2006-03-07 09:17:35Z sam $
+ *  \author Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *  \brief Network driver
+ *
+ *  This file contains the libcaca network input and output driver
+ */
+
+#include "config.h"
+
+#if defined(USE_NETWORK)
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#if defined(HAVE_UNISTD_H)
+#   include <unistd.h>
+#endif
+#include <stdarg.h>
+
+#include "caca.h"
+#include "caca_internals.h"
+#include "cucul.h"
+#include "cucul_internals.h"
+
+
+
+struct driver_private
+{ 
+    unsigned int width, height;
+    unsigned int port;
+    int sockfd, new_fd;
+    struct sockaddr_in my_addr;    // my address information
+    struct sockaddr_in remote_addr;
+    socklen_t sin_size;
+    int clilen;
+    char buffer[256];
+};
+
+
+
+#define BACKLOG 1337    /* Number of pending connections */
+
+
+
+/* Following vars are static */
+static char codes[] = {0xff, 0xfb, 0x01,  // WILL ECHO                                                              
+                       0xff, 0xfb, 0x03,  // WILL SUPPRESS GO AHEAD
+                       0xff, 253, 31,     // DO NAWS
+                       0xff, 254, 31,     // DON'T NAWS
+                       0xff, 31, 250, 0, 30, 0, 0xFF, // to be replaced 
+                       0xff, 240};
+
+
+static int network_init_graphics(caca_t *kk)
+{
+    int yes=1;
+    printf("Initing network stack.\n");
+
+    kk->drv.p = malloc(sizeof(struct driver_private));
+
+
+    kk->drv.p->width = 80;
+    kk->drv.p->height = 25;
+    kk->drv.p->port = 7575; // 75 75 decimal ASCII -> KK   // FIXME, sadly
+
+
+    cucul_set_size(kk->qq, kk->drv.p->width, kk->drv.p->height);
+
+
+    printf("socket\n");
+    if ((kk->drv.p->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+        perror("socket");
+        return -1;
+    }
+    printf("setsockopt\n");
+    if (setsockopt(kk->drv.p->sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
+        perror("setsockopt");
+        return -1;
+    }
+
+
+    kk->drv.p->my_addr.sin_family = AF_INET;
+    kk->drv.p-> my_addr.sin_port = htons(kk->drv.p->port); 
+    kk->drv.p->my_addr.sin_addr.s_addr = INADDR_ANY;
+    memset(&(kk->drv.p->my_addr.sin_zero), '\0', 8);
+
+    printf("bind\n");
+    if (bind(kk->drv.p->sockfd, (struct sockaddr *)&kk->drv.p->my_addr, sizeof(struct sockaddr))
+                                                                   == -1) {
+        perror("bind");
+        return -1;
+    }
+    printf("listen\n");
+    if (listen(kk->drv.p->sockfd, BACKLOG) == -1) {
+        perror("listen");
+        return -1;
+    }
+
+    printf("accept\n");
+    kk->drv.p->clilen = sizeof(kk->drv.p->remote_addr);
+    kk->drv.p->new_fd = accept(kk->drv.p->sockfd, (struct sockaddr *) &kk->drv.p->remote_addr, &kk->drv.p->clilen);
+    if (kk->drv.p->new_fd < 0) {
+        perror("ERROR on accept");
+        return -1;
+    }
+
+
+    printf("Got connexion from %d.%d.%d.%d\n", 
+           (unsigned int)((kk->drv.p->remote_addr.sin_addr.s_addr)&0x000000FF),
+           (unsigned int)((kk->drv.p->remote_addr.sin_addr.s_addr)&0x0000FF00)>>8,
+           (unsigned int)((kk->drv.p->remote_addr.sin_addr.s_addr)&0x00FF0000)>>16,
+           (unsigned int)((kk->drv.p->remote_addr.sin_addr.s_addr)&0xFF000000)>>24);
+    
+    codes[16] = (unsigned char) kk->drv.p->width&0xff;
+    codes[18] = (unsigned char) kk->drv.p->height&0xff;
+
+    /* Send basic telnet codes */
+    if (send(kk->drv.p->new_fd, codes,sizeof(codes) , 0) == -1) {
+        perror("send");
+        return -1;
+    }
+
+    printf("network ok.\n");
+
+    return 0;
+}
+
+static int network_end_graphics(caca_t *kk)
+{
+    printf("network end graphics\n");
+    return 0;
+}
+
+static int network_set_window_title(caca_t *kk, char const *title)
+{
+    printf("network_set_window_title(%s) not implemented yet.\n", title);
+    return 0;
+}
+
+static unsigned int network_get_window_width(caca_t *kk)
+{
+    return kk->drv.p->width * 6;
+}
+
+static unsigned int network_get_window_height(caca_t *kk)
+{
+    return kk->drv.p->height * 10;
+}
+
+static void network_display(caca_t *kk)
+{
+    /* Clear screen */
+    /*    if (send(kk->drv.p->new_fd, "\033?75l\033[2J\033[H", 12, 0) == -1) {
+        perror("send");
+        return;
+    }
+    */
+
+    char *to_send = cucul_get_ansi(kk->qq, 0);;
+    to_send = realloc(to_send, kk->qq->width * kk->qq->height * 15 * 3);
+    
+
+    if (send(kk->drv.p->new_fd, "\033[s", 4, 0) == -1) {
+        perror("send");
+        return;
+    }
+    if (send(kk->drv.p->new_fd, to_send, kk->qq->width * kk->qq->height * 15, 0) == -1) {
+        perror("send");
+        return;
+    }
+    if (send(kk->drv.p->new_fd, "\033?75l\033[2J\033[H", 12, 0) == -1) {
+        perror("send");
+        return;
+    }
+ 
+}
+static void network_handle_resize(caca_t *kk)
+{
+    printf("Resize\n");
+ 
+}
+
+static unsigned int network_get_event(caca_t *kk)
+{
+    return 0;
+}
+
+
+/*
+ * Driver initialisation
+ */
+
+void network_init_driver(caca_t *kk)
+{
+    kk->drv.driver = CACA_DRIVER_NETWORK;
+
+    kk->drv.init_graphics = network_init_graphics;
+    kk->drv.end_graphics = network_end_graphics;
+    kk->drv.set_window_title = network_set_window_title;
+    kk->drv.get_window_width = network_get_window_width;
+    kk->drv.get_window_height = network_get_window_height;
+    kk->drv.display = network_display;
+    kk->drv.handle_resize = network_handle_resize;
+    kk->drv.get_event = network_get_event;
+}
+
+#endif // USE_NETWORK
diff --git a/configure.ac b/configure.ac
index 17bede6..fe589b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,8 @@ AC_ARG_ENABLE(x11,
   [  --enable-x11            X11 support (autodetected)])
 AC_ARG_ENABLE(gl,
   [  --enable-gl             OpenGL support (autodetected)])
+AC_ARG_ENABLE(network,
+  [  --enable-network        Network support (autodetected)])
 
 dnl example programs features
 AC_ARG_ENABLE(imlib2,
@@ -137,6 +139,17 @@ if test "${enable_gl}" != "no"; then
   fi
 fi
 
+if test "${enable_network}" != "no"; then
+  ac_cv_my_have_network="no"
+  AC_CHECK_HEADERS(sys/socket.h,
+     [ac_cv_my_have_network="yes"
+      AC_DEFINE(USE_NETWORK, 1, Define to activate the network backend driver)
+      CACA_DRIVERS="${CACA_DRIVERS} network"])
+  if test "${ac_cv_my_have_network}" = "no" -a "${enable_network}" = "yes"; then
+    AC_MSG_ERROR([cannot find standard networking socket files])
+  fi
+fi
+
 if test "${enable_ncurses}" != "no"; then
   ac_cv_my_have_ncurses="no"
   AC_CHECK_HEADERS(curses.h ncurses.h,