$ git clone http://tcclient.ion.nu/tc_client.git
commit b727a94707f15923256728a95b926488841c40df
Author: Alicia <...>
Date:   Fri Jul 31 23:15:53 2015 +0200

    tc_client-gtk and camviewer: added support for captchas

diff --git a/ChangeLog b/ChangeLog
index 1a64135..110da90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ Send account username in AMF0 "connect" command at startup regardless of whether
 If an RTMP chunk already has a buffer allocated when a packet sets the length, free it and start over.
 Added support for captchas.
 irchack: added a check for whether tc_client is installed or should be run from the source directory (should have been added along with the 'install' target)
+tc_client-gtk and camviewer: added support for captchas
 0.34:
 Fixed memory alignment in rtmp/amf code (for CPU architectures that are picky about it)
 Print version info when called with -v/--version (contributed by Jade)
diff --git a/gtkgui.glade b/gtkgui.glade
index ae7f240..7956c40 100644
--- a/gtkgui.glade
+++ b/gtkgui.glade
@@ -88,6 +88,44 @@
       </object>
     </child>
   </object>
+  <object class="GtkWindow" id="captcha">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">tc_client (captcha)</property>
+    <child>
+      <object class="GtkBox" id="box10">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkLabel" id="captcha_link">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xpad">50</property>
+            <property name="ypad">50</property>
+            <property name="use_markup">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="captcha_done">
+            <property name="label" translatable="yes">Done</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
   <object class="GtkWindow" id="channelconfig">
     <property name="can_focus">False</property>
     <property name="title" translatable="yes">tc_client</property>
diff --git a/utilities/camviewer/camviewer.c b/utilities/camviewer/camviewer.c
index 6a72ea4..73fb318 100644
--- a/utilities/camviewer/camviewer.c
+++ b/utilities/camviewer/camviewer.c
@@ -155,6 +155,12 @@ void camera_remove(struct viddata* data, const char* nick)
   }
 }
 
+void captcha_done(GtkButton* button, GtkWidget* box)
+{
+  gtk_widget_destroy(box);
+  write(tc_client_in[1], "\n", 1);
+}
+
 char buf[1024];
 gboolean handledata(GIOChannel* channel, GIOCondition condition, gpointer datap)
 {
@@ -197,6 +203,21 @@ gboolean handledata(GIOChannel* channel, GIOCondition condition, gpointer datap)
     camera_remove(data, buf);
     return 1;
   }
+  if(!strncmp(buf, "Captcha: ", 9))
+  {
+    GtkWidget* box=gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+    GtkWidget* label=gtk_label_new(0);
+    char link[snprintf(0,0,"Captcha: <a href=\"%s\">%s</a>", &buf[9], &buf[9])+1];
+    sprintf(link, "Captcha: <a href=\"%s\">%s</a>", &buf[9], &buf[9]);
+    gtk_label_set_markup(GTK_LABEL(label), link);
+    gtk_box_pack_start(GTK_BOX(box), label, 0, 0, 0);
+    GtkWidget* button=gtk_button_new_with_label("Done");
+    g_signal_connect(button, "clicked", G_CALLBACK(captcha_done), box);
+    gtk_box_pack_start(GTK_BOX(box), button, 0, 0, 0);
+    gtk_box_pack_start(GTK_BOX(data->box), box, 0, 0, 0);
+    gtk_widget_show_all(box);
+    return 1;
+  }
   if(!strncmp(buf, "Starting media stream for ", 26))
   {
     char* nick=&buf[26];
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index b536ae4..b76d210 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -205,11 +205,21 @@ gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer data
   }
   if(!strncmp(buf, "Connection ID: ", 15)) // Our initial nickname is "guest-" plus our connection ID
   {
+    write(tc_client_in[1], "/color\n", 7); // Check which random color tc_client picked
     unsigned int length=strlen(&buf[15]);
     nickname=malloc(length+strlen("guest-")+1);
     sprintf(nickname, "guest-%s", &(buf[15]));
     return 1;
   }
+  if(!strncmp(buf, "Captcha: ", 9))
+  {
+    gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(gui, "main")));
+    gtk_widget_show_all(GTK_WIDGET(gtk_builder_get_object(gui, "captcha")));
+    char link[snprintf(0,0,"Captcha: <a href=\"%s\">%s</a>", &buf[9], &buf[9])+1];
+    sprintf(link, "Captcha: <a href=\"%s\">%s</a>", &buf[9], &buf[9]);
+    gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(gui, "captcha_link")), link);
+    return 1;
+  }
   // Start streams once we're properly connected
   if(!strncmp(buf, "Currently on cam: ", 18))
   {
@@ -851,12 +861,18 @@ void startsession(GtkButton* button, void* x)
   }
 #endif
   if(acc_user[0]){dprintf(tc_client_in[1], "%s\n", acc_pass);}
-  write(tc_client_in[1], "/color\n", 7);
   GIOChannel* tcchannel=g_io_channel_unix_new(tc_client[0]);
   g_io_channel_set_encoding(tcchannel, 0, 0);
   g_io_add_watch(tcchannel, G_IO_IN, handledata, data);
 }
 
+void captcha_done(GtkWidget* button, void* x)
+{
+  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(gui, "captcha")));
+  gtk_widget_show_all(GTK_WIDGET(gtk_builder_get_object(gui, "main")));
+  write(tc_client_in[1], "\n", 1);
+}
+
 int main(int argc, char** argv)
 {
   if(!strncmp(argv[0], "./", 2)){frombuild=1;}
@@ -998,6 +1014,8 @@ int main(int argc, char** argv)
   // Connect signal for tab changing (to un-highlight)
   item=GTK_WIDGET(gtk_builder_get_object(gui, "tabs"));
   g_signal_connect(item, "switch-page", G_CALLBACK(pm_select), 0);
+  // Connect signal for captcha
+  g_signal_connect(gtk_builder_get_object(gui, "captcha_done"), "clicked", G_CALLBACK(captcha_done), 0);
   // Populate saved channels
   GtkWidget* startbox=GTK_WIDGET(gtk_builder_get_object(gui, "startbox"));
   int channelcount=config_get_int("channelcount");