$ git clone http://tcclient.ion.nu/tc_client.git
commit 4e22a4ddc82a90027df37dd322cf11e0cf8c266d
Author: Alicia <...>
Date: Wed May 24 20:32:21 2017 +0200
tc_client-gtk: added a webkitview for solving captchas without an external browser.
diff --git a/ChangeLog b/ChangeLog
index bff8be4..a7aee0c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -22,6 +22,7 @@ tc_client-gtk: use /quit to guarantee a clean exit.
tc_client-gtk: fixed segfault at exit by doing camera cleanup earlier.
tc_client-gtk: made the automatic brightness postprocessing adjustment gradual.
tc_client-gtk: use pulseaudio for incoming audio if it's available (preferred over libao) and display the volume indicator even if no audio playback library is available.
+tc_client-gtk: added a webkitview for solving captchas without an external browser.
irchack: don't rely on connection ID.
0.41.1:
Use tinychat.com instead of apl.tinychat.com (works around SSL/TLS issues on windows)
diff --git a/Makefile b/Makefile
index 91131be..006b83c 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,9 @@ ifdef SWSCALE_LIBS
UTILS+=camviewer tc_client-gtk
CFLAGS+=$(GTK_CFLAGS) $(AVCODEC_CFLAGS) $(AVUTIL_CFLAGS) $(SWSCALE_CFLAGS)
INSTALLDEPS+=tc_client-gtk gtkgui.glade
+ ifdef HAVE_WEBKITGTK
+ CFLAGS+=-DHAVE_WEBKITGTK=1 $(WEBKITGTK_CFLAGS)
+ endif
ifdef HAVE_PULSE
AUDIO_CFLAGS=-DHAVE_PULSEAUDIO=1 $(PULSE_CFLAGS)
HAVE_AUDIOLIB=1
@@ -139,7 +142,7 @@ cursedchat: $(CURSEDCHAT_OBJ)
$(CC) $(LDFLAGS) $^ $(LIBS) $(READLINE_LIBS) $(CURSES_LIBS) -o $@
tc_client-gtk: $(TC_CLIENT_GTK_OBJ) camplaceholder.gif modicon.png greenroomindicator.png
- $(CC) $(LDFLAGS) $(TC_CLIENT_GTK_OBJ) $(LIBS) $(GTK_LIBS) $(AVCODEC_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(AVRESAMPLE_LIBS) $(SWRESAMPLE_LIBS) $(AVFORMAT_LIBS) $(AO_LIBS) $(LIBV4L2_LIBS) $(LIBX11_LIBS) $(PULSE_LIBS) -o $@
+ $(CC) $(LDFLAGS) $(TC_CLIENT_GTK_OBJ) $(LIBS) $(GTK_LIBS) $(AVCODEC_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(AVRESAMPLE_LIBS) $(SWRESAMPLE_LIBS) $(AVFORMAT_LIBS) $(AO_LIBS) $(LIBV4L2_LIBS) $(LIBX11_LIBS) $(PULSE_LIBS) $(WEBKITGTK_LIBS) -o $@
camplaceholder.gif: utilities/gtk/gencamplaceholder.sh utilities/gtk/camplaceholder.xcf utilities/gtk/spinnerdot.xcf
utilities/gtk/gencamplaceholder.sh
diff --git a/configure b/configure
index 8ddf184..c3cf343 100755
--- a/configure
+++ b/configure
@@ -252,6 +252,9 @@ if testpkgconfig glib-2.0 GLIB; then
echo 'CFLAGS+=$(GLIB_CFLAGS) -DHAVE_GLIB=1' >> config.mk
fi
+testpkgconfig webkit2gtk-4.0 WEBKITGTK || \
+testpkgconfig webkit2gtk-3.0 WEBKITGTK
+
printf 'Checking if we have a working poll()... '
echo '#include <poll.h>' > polltest.c
echo '#include <sys/socket.h>' >> polltest.c
diff --git a/tinychat.c b/tinychat.c
index 6d477e2..ae49299 100644
--- a/tinychat.c
+++ b/tinychat.c
@@ -117,7 +117,7 @@ static void getcaptcha(const char* channel)
end[0]=0;
printf("Captcha: http://tinychat.com/%s + javascript:void(ShowRecaptcha('%s'));\n", channel, token);
fflush(stdout);
- fgetc(stdin);
+ if(fgetc(stdin)==EOF){exit(0);}
}
}
free(page);
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index 635b3c4..bf213aa 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -50,6 +50,9 @@
#endif
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
+#ifdef HAVE_WEBKITGTK
+#include <webkit2/webkit2.h>
+#endif
#include "../compat.h"
#include "../compat_av.h"
#ifndef NO_PRCTL
@@ -148,6 +151,41 @@ void printchat(const char* text, const char* color, unsigned int offset, const c
chatview_autoscroll(chatview);
}
+#ifdef HAVE_WEBKITGTK
+static void removefrom(GtkWidget* widget, void* parent)
+{
+ gtk_container_remove(parent, widget);
+}
+#endif
+
+void captcha_done(void* x, void* y)
+{
+ GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "captcha"));
+ gtk_widget_hide(window);
+ gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(gui, "main")));
+ write(tc_client_in[1], "\n", 1);
+ if(greenroompipe_in[1]>-1){write(greenroompipe_in[1], "\n", 1);}
+#ifdef HAVE_WEBKITGTK // Get rid of the webkit view when we're done with it
+ gtk_container_foreach(GTK_CONTAINER(window), removefrom, window);
+}
+
+void captchajs(WebKitWebView* webview, WebKitLoadEvent event, gpointer data)
+{
+ // Hide unrelated parts of the page (tinychat-specific)
+ webkit_web_view_run_javascript(webview, "document.getElementById('footer').style.display='none'; document.getElementById('tinychat').style.display='none';", 0, 0, 0);
+ if(event!=WEBKIT_LOAD_FINISHED){return;}
+ g_signal_handlers_disconnect_by_data(webview, data);
+ // Add a note about loading the captcha (which is pretty slow)
+ webkit_web_view_run_javascript(webview, "var loaddiv=document.createElement('div'); loaddiv.appendChild(document.createTextNode('Loading captcha...')); loaddiv.style.background='rgb(255,255,255)'; document.body.appendChild(loaddiv); CaptchaSolvedSuccessfully=window.close;", 0, 0, 0);
+ const char* js=data;
+ // Put the javascript into the body tag's onload event, which is still slightly later than WEBKIT_LOAD_FINISHED
+ char buf[strlen("document.body.onload=function(){};0")+strlen(js)];
+ sprintf(buf, "document.body.onload=function(){%s};", js);
+ webkit_web_view_run_javascript(webview, buf, 0, 0, 0);
+ free(data);
+#endif
+}
+
unsigned int cameventsource=0;
gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer x)
{
@@ -268,10 +306,38 @@ gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer x)
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")));
+ GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "captcha"));
+ gtk_widget_show_all(window);
+ #ifdef HAVE_WEBKITGTK
+ // Resize to fit the captcha and clear the window
+ gtk_window_resize(GTK_WINDOW(window), 450, 600);
+ gtk_container_foreach(GTK_CONTAINER(window), removefrom, window);
+ GtkWidget* box=gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add(GTK_CONTAINER(window), box);
+ // Set up webkit webview
+ GtkWidget* webview=webkit_web_view_new();
+ g_signal_connect(webview, "close", G_CALLBACK(captcha_done), 0);
+ gtk_box_pack_start(GTK_BOX(box), webview, 1, 1, 0);
+ // Add a "Done" button, for skipping the captcha or if the captcha doesn't close the window itself
+ GtkWidget* button=gtk_button_new_with_label("Done");
+ g_signal_connect(button, "clicked", G_CALLBACK(captcha_done), 0);
+ gtk_box_pack_start(GTK_BOX(box), button, 0, 0, 0);
+ gtk_widget_show_all(box);
+ // Load the captcha page, and run the javascript if any was specified
+ char* js=strstr(&buf[9], " + javascript:");
+ if(js){js[0]=0;}
+ webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), &buf[9]);
+ if(js)
+ {
+ js=&js[14];
+ // Wait for it to load
+ g_signal_connect(webview, "load-changed", G_CALLBACK(captchajs), strdup(js));
+ }
+ #else
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);
+ #endif
return 1;
}
// Start streams once we're properly connected
@@ -1005,14 +1071,6 @@ void startsession(GtkButton* button, void* x)
#endif
}
-void captcha_done(GtkWidget* button, void* x)
-{
- gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(gui, "captcha")));
- gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(gui, "main")));
- write(tc_client_in[1], "\n", 1);
- if(greenroompipe_in[1]>-1){write(greenroompipe_in[1], "\n", 1);}
-}
-
#ifndef _WIN32
void justwait(int x){waitpid(-1, 0, WNOHANG);}
#endif
diff --git a/utilities/gtk/main.h b/utilities/gtk/main.h
index 3624296..b60b426 100644
--- a/utilities/gtk/main.h
+++ b/utilities/gtk/main.h
@@ -1,6 +1,6 @@
/*
tc_client-gtk, a graphical user interface for tc_client
- Copyright (C) 2015-2016 alicia@ion.nu
+ Copyright (C) 2015-2017 alicia@ion.nu
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
@@ -28,4 +28,4 @@ void togglemic(GtkCheckMenuItem* item, void* x);
extern gboolean inputkeys(GtkWidget* widget, GdkEventKey* event, void* data);
extern void sendmessage(GtkEntry* entry, void* x);
extern void startsession(GtkButton* button, void* x);
-extern void captcha_done(GtkWidget* button, void* x);
+extern void captcha_done(void* x, void* y);