$ git clone http://tcclient.ion.nu/tc_client.git
commit 558b36edfa2066bdc6f418eab32bd8280bb15e7d
Author: Alicia <...>
Date:   Tue Apr 7 06:49:01 2015 +0200

    Version 0.8

diff --git a/ChangeLog b/ChangeLog
index 6eaf8e9..5079b35 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+0.8:
+irchack: convert tc_client's ANSI codes to IRC color codes.
+irchack: convert IRC color codes to '/color <number>' commands for tc_client.
+Made it possible to turn off/on colors being displayed with '/color off' and '/color on'
 0.7:
 Added command handling (/color <number>, /colors, /nick <newnick>, and adding the privacy field for /msg)
 0.6:
diff --git a/Makefile b/Makefile
index 75a8eb9..76be707 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.7
+VERSION=0.8
 CFLAGS=-g3 -Wall $(shell curl-config --cflags)
 LIBS=-g3 $(shell curl-config --libs)
 
diff --git a/client.c b/client.c
index 97dfe99..5fddd11 100644
--- a/client.c
+++ b/client.c
@@ -39,6 +39,8 @@ struct writebuf
   int len;
 };
 
+char showcolor=1;
+
 unsigned int flip(unsigned int bits, int bytecount)
 {
   unsigned int ret=0;
@@ -271,6 +273,7 @@ int main(int argc, char** argv)
     {
       pfd[0].revents=0;
       len=read(0, buf, 2047);
+      if(len<1){break;}
       while(len>0 && (buf[len-1]=='\n'||buf[len-1]=='\r')){--len;}
       if(!len){continue;} // Don't send empty lines
       buf[len]=0;
@@ -282,6 +285,8 @@ int main(int argc, char** argv)
         {
           if(buf[6]) // Color specified
           {
+            if(!strcmp((char*)&buf[7], "off")){showcolor=0; continue;}
+            if(!strcmp((char*)&buf[7], "on")){showcolor=1; continue;}
             currentcolor=atoi((char*)&buf[7]);
             printf("\x1b[%smChanged color\x1b[0m\n", termcolors[currentcolor%16]);
           }else{ // No color specified, state our current color
@@ -397,7 +402,7 @@ int main(int argc, char** argv)
       else if(amfin->itemcount>5 && amfin->items[0].type==AMF_STRING && amf_comparestrings_c(&amfin->items[0].string, "privmsg") && amfin->items[3].type==AMF_STRING && amfin->items[4].type==AMF_STRING && amfin->items[5].type==AMF_STRING)
       {
         wchar_t* msg=fromnumlist(amfin->items[3].string.string);
-        const char* color=resolvecolor(amfin->items[4].string.string);
+        const char* color=(showcolor?resolvecolor(amfin->items[4].string.string):"0");
         printf("%s \x1b[%sm%s: %ls\x1b[0m\n", timestamp(), color, amfin->items[5].string.string, msg);
         free(msg);
         fflush(stdout);
@@ -480,5 +485,6 @@ int main(int argc, char** argv)
     }
 //    ++outnum; (Debugging)
   }
+  close(sock);
   return 0;
 }
diff --git a/irchack.c b/irchack.c
index 7257bda..92ce025 100644
--- a/irchack.c
+++ b/irchack.c
@@ -21,6 +21,61 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/socket.h>
+#include <ctype.h>
+
+// ANSI colors and their IRC equivalents
+struct color{const char* ansi; const char* irc;};
+struct color colortable[]={
+  {"31",   "\x03""05"},
+  {"31;1", "\x03""04"},
+  {"33",   "\x03""07"},
+  {"33",   "\x03""07"},
+  {"33;1", "\x03""08"},
+  {"32;1", "\x03""09"},
+  {"32;1", "\x03""09"},
+  {"32",   "\x03""03"},
+  {"36",   "\x03""10"},
+  {"34;1", "\x03""12"},
+  {"34;1", "\x03""12"},
+  {"34",   "\x03""02"},
+  {"35",   "\x03""06"},
+  {"35;1", "\x03""13"},
+  {"35;1", "\x03""13"},
+  {"35;1", "\x03""13"}
+};
+
+const char* findcolor_irc(const char* ansi)
+{
+  int len;
+  for(len=0; ansi[len]&&ansi[len]!='m'; ++len);
+  int i;
+  for(i=0; i<16; ++i)
+  {
+    if(!strncmp(colortable[i].ansi, ansi, len) && !colortable[i].ansi[len])
+    {
+      return colortable[i].irc;
+    }
+  }
+  return 0;
+}
+
+int findcolor_ansi(char* irc, char** end)
+{
+  char color[4];
+  strncpy(color, irc, 3);
+  color[3]=0;
+  if(!isdigit(color[1])){*end=&irc[1]; return -1;}
+  if(!isdigit(color[2])){*end=&irc[2]; color[2]=color[1]; color[1]='0';}else{*end=&irc[3];}
+  int i;
+  for(i=0; i<16; ++i)
+  {
+    if(!strcmp(colortable[i].irc, color))
+    {
+      return i;
+    }
+  }
+  return -1;
+}
 
 int main(int argc, char** argv)
 {
@@ -146,13 +201,16 @@ printf("Got from tc_client: '%s'\n", buf);
         continue;
       }
       if(buf[0]!='['){continue;} // Beyond this we only care about timestamped lines
-      // Strip out ANSI escape codes (TODO: translate them to IRC color codes instead)
+      // Translate ANSI escape codes to IRC color code instead
       char* ansi;
+      const char* color="";
       while((ansi=strstr(buf, "\x1b[")))
       {
         int len;
         for(len=0; ansi[len]&&ansi[len]!='m'; ++len);
         if(ansi[len]=='m'){++len;}
+        const char* c=findcolor_irc(&ansi[2]);
+        if(c){color=c;}
         memmove(ansi, &ansi[len], strlen(&ansi[len])+1);
       }
 
@@ -171,9 +229,9 @@ printf("Got from tc_client: '%s'\n", buf);
           msg=strchr(&msg[5], ' ');
           if(!msg){continue;}
           msg=&msg[1];
-          dprintf(sock, ":%s!user@host PRIVMSG %s :%s\n", name, nick, msg);
+          dprintf(sock, ":%s!user@host PRIVMSG %s :%s%s\n", name, nick, color, msg);
         }else{ // Regular channel message
-          dprintf(sock, ":%s!user@host PRIVMSG #%s :%s\n", name, channel, msg);
+          dprintf(sock, ":%s!user@host PRIVMSG #%s :%s%s\n", name, channel, color, msg);
         }
       }else{ // action, parse the actions and send them as JOINs, NICKs and QUITs etc. instead
         msg[0]=0;
@@ -206,7 +264,6 @@ printf("Got from tc_client: '%s'\n", buf);
         ++len;
       }
       if(len<=0){continue;}
-      while(len>0 && (buf[len-1]=='\n'||buf[len-1]=='\r')){--len;}
       buf[len]=0;
 printf("Got from IRC client: '%s'\n", buf);
       if(!strncmp(buf, "PRIVMSG ", 8))
@@ -217,6 +274,14 @@ printf("Got from IRC client: '%s'\n", buf);
         msg[0]=0;
         msg=&msg[1];
         if(msg[0]==':'){msg=&msg[1];}
+        char* color;
+        while((color=strchr(msg, '\x03')))
+        {
+          char* end;
+          int c=findcolor_ansi(color, &end);
+          if(c!=-1){dprintf(tc_in[1], "/color %i\n", c);}
+          memmove(color, end, strlen(end)+1);
+        }
         if(target[0]=='#' && !strcmp(&target[1], channel))
         {
           dprintf(tc_in[1], "%s\n", msg);
@@ -234,9 +299,12 @@ printf("Got from IRC client: '%s'\n", buf);
       {
         dprintf(sock, ":irchack PONG %s\n", &buf[5]);
       }
+      else if(!strncmp(buf, "QUIT ", 5)){break;}
     }
   }
 
+  close(tc_in[1]);
+  close(tc_out[0]);
   shutdown(sock, SHUT_RDWR);
   return 0;
 }