/*****************************************************************************
 * capchat.c
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 * Copyright (C) 2007, Greg Hosler
 * (ghosler ['at'] yahoo.com)
 * 
 * Released under the terms of the GPL.
 * *NO WARRANTY*
 *
 * ghosler ['at'] yahoo.com
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <expat.h>

#include "main.h"
#include "gyach.h"
#include "captcha.h"
#include "interface.h"
#include "packet_handler.h"
#include "util.h"

/* forward declarations */
void set_captcha_label(GtkWidget *captcha_ui, char *label_text);

/* static in this module */
char *last_captcha_response_post      = NULL;
char *last_captcha_response_image_url = NULL;
char *last_captcha_response_cookie    = NULL;
char *last_captcha_room               = NULL;

typedef struct _form {
	char *action;
	char *referer_cookie;
	GList *variables;
} FORM_STRUCT;

typedef struct _variable {
	char *name;
	char *value;
} FORM_VARIABLE;

FORM_STRUCT *create_form_struct() {
	FORM_STRUCT *form_struct;
	form_struct = malloc(sizeof(FORM_STRUCT));
	form_struct->action=NULL;
	form_struct->variables=NULL;
	form_struct->referer_cookie=NULL;
	return(form_struct);
}

/* free all the data in the form structure.
 * the action string,
 * all the variable strings in the variable list
 * and then the form structure itself.
 */
void free_form_struct(FORM_STRUCT *form_struct) {
	FORM_VARIABLE *variable;
	GList         *l_listp;

	if (form_struct->action)  {free(form_struct->action);  form_struct->action=NULL;}
	if (form_struct->referer_cookie) {free(form_struct->referer_cookie); form_struct->referer_cookie=NULL;}
	/* free the individual variables, and the list elements */
	while (form_struct->variables) {
		l_listp=g_list_first(form_struct->variables);
		variable=l_listp->data;
		if (variable->name)  {free(variable->name);  variable->name=NULL;}
		if (variable->value) {free(variable->value); variable->value=NULL;}
		form_struct->variables = g_list_delete_link(form_struct->variables, l_listp);
	}
	free(form_struct);
}

char *find_attribute(const XML_Char **attrs, char *name) {
	const char *tag,
	           *value;

	if (attrs) {
		while (*attrs) {
			tag   = *attrs++;
			value = *attrs++;
			if (!strcmp(tag, name)) {
				return((char *)value);
			}
		}
	}

	return NULL;
}

void add_variable(FORM_STRUCT *form_struct, char *name, char *value) {
	GList *l_listp;
	FORM_VARIABLE *variable;

	if (!name) return;
	if (!value) value="";

	for (l_listp=form_struct->variables; l_listp; l_listp=g_list_next(l_listp)) {
		variable = (FORM_VARIABLE *)(l_listp->data);
		if (!strcmp(name, variable->name)) {
			free(variable->value);
			variable->value = strdup(value);
			return;
		}
	}

	variable = malloc(sizeof(FORM_VARIABLE));
	variable->name  = strdup(name);
	variable->value = strdup(value);
	form_struct->variables = g_list_append(form_struct->variables, variable);
}

char *find_variable(FORM_STRUCT *form_struct, char *name) {
	GList *l_listp;
	FORM_VARIABLE *variable;

	for (l_listp=form_struct->variables; l_listp; l_listp=g_list_next(l_listp)) {
		variable = (FORM_VARIABLE *)(l_listp->data);
		if (!strcmp(name, variable->name)) {
			return(variable->value);
		}
	}
	return NULL;
}


gboolean on_captcha_window_killed(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
	FORM_STRUCT *form_struct;

	if (!GTK_IS_WINDOW(widget)) {
		/* window has been deleted / destroyed */
		return(TRUE);
	}

	form_struct = g_object_get_data(G_OBJECT(widget), "form_struct");
	if (form_struct) {
		free_form_struct(form_struct);
	}

	gtk_widget_destroy(widget);

	return(TRUE);
}

gboolean destroy_captcha_window(gpointer user_data) {
	GtkWidget *widget = user_data;
	on_captcha_window_killed(widget, NULL, NULL);
	return(FALSE);
}

/* The captcha url is valid for about 5 minutes.
 * After a captcha url expirtes, the return on a relavidation will be:
 *
 *     The document has moved <A HREF="http://captcha.chat.yahoo.com/go/captchat/close?exceeded=1">here</A>.<P>
 *     <!-- captchaes1.chat.dcn.yahoo.com uncompressed/chunked Fri Nov  2 22:01:35 PDT 2007 -->
 *
 * The immediate next captcha validation will succeed, but you won't enter the chat room.
 * I believe this to be a bug on the yahoo server, but it COULD be just how the protocol
 * has been defined. (The yahoo server will send a logout packet to the user that tried to
 * validate against an expired captcha string...)
 *
 * Note that a rejoin will succeed.
 *
 * Anyway, there are 2 ways to deal with this.
 *     1) expire the saved captcha strings before they expire, so that we don't send the
 *        failing revalidation
 *     2) when captcha succeeds, start a timer, and after, say 4 or 5 secs, if we haven't seen
 *        the room join package, then do an automatic rejoin.
 *
 * So what I do is option 3.
 * 
 * When I detect that the captcha string has been validated, I see if we're still connected
 * to a room. If yahoo detected the expired captcha, they will have sent us a logout packet,
 * and we'll have reset the room name to [NONE]. So, in on_captcha_ok_clicked(), if the
 * room name is "[NONE]", then we'll resend a join. Meanwhile, occassionally, when we do
 * join a room, occassionally yahoo misses sending us the room list.
 * 
 * So... For cases where the logout follows captchs validation, and for cases where the room
 * list is not even sent (or received...), then we'll check if we actually have the room list
 * at about teh 4 sec mark after captcha validation. If we're still missing the room list, then
 * we'll join the room again...
 */

gboolean check_captcha_response(gpointer user_data) {
	char *buffer;

	if (need_room_list && last_captcha_room) {
		if (capture_fp) {	
			fprintf(capture_fp,"\n[%s] Still waiting for room list. Attempting to rejoin room: %s\n",
				gyach_timestamp(),
				last_captcha_room);
		}

		buffer = malloc(strlen(last_captcha_room) + 7);
		strcpy(buffer, "/join ");
		strcat(buffer, last_captcha_room);
		chat_command(buffer, 0);
		free(buffer);
	}

	return(FALSE);
}

void on_captcha_ok_clicked(GtkWidget *button, gpointer user_data) {
	FORM_STRUCT *form_struct;
	GtkWidget  *entry = user_data;
	GtkWidget  *hbox;
	const char *text;  
	GtkWidget *captcha_ui;
	char  *image_url;
	int    hostname_len;
	GList *l_listp;
	FORM_VARIABLE *variable;
	char  *post;
	int    post_len;
	char  *ptr;
	char   buffer[1000];
	int    length;

	captcha_ui = g_object_get_data(G_OBJECT(button), "mywindow");
	if (captcha_ui) {
		hbox = g_object_get_data(G_OBJECT(captcha_ui), "hbox");
		if (entry) {
			gtk_widget_set_sensitive(entry, 0);
		}
		if (hbox) {
			gtk_widget_set_sensitive(hbox, 0);
		}
		form_struct = g_object_get_data(G_OBJECT(captcha_ui), "form_struct");
		if (form_struct) {
			text = gtk_entry_get_text(GTK_ENTRY(entry));
			add_variable(form_struct, "answer", (char *)text);
			/* referer_cookie reads "Referer: http://<url>..."
			 * We need to isolate the "http://<hostname>/
			 * The 3rd slash, will be the 1st slash after
			 * 'Referer: httl://' (9, plus 7 chars from the start)
			 */
			ptr = strstr(form_struct->referer_cookie+9+7, "/");
			hostname_len = ptr-(form_struct->referer_cookie+9);
			image_url=malloc(hostname_len + strlen(form_struct->action) + 3);
			strncpy(image_url, form_struct->referer_cookie+9, hostname_len);
			image_url[hostname_len] = 0;
			strcat(image_url, form_struct->action);

			post_len = 0;
			for (l_listp=form_struct->variables; l_listp; l_listp=g_list_next(l_listp)) {
				variable = (FORM_VARIABLE *)(l_listp->data);
				post_len += strlen(variable->name) + 1 + strlen(variable->value) + 1;
			}
			
			post = malloc(post_len+1);
			*post = 0;
			for (l_listp=form_struct->variables; l_listp; l_listp=g_list_next(l_listp)) {
				variable = (FORM_VARIABLE *)(l_listp->data);
				strcat(post, variable->name);
				strcat(post, "=");
				strcat(post, variable->value);
				strcat(post, "&");
			}
			post[strlen(post)-1]=0;
			set_captcha_label(captcha_ui, _("Sending Authorization code."));
			length = fetch_url(image_url, buffer, 900, post, form_struct->referer_cookie);
			if (capture_fp) {	
				fprintf(capture_fp,"\n[%s] CAPTCHA RESULT: '%s'\n", gyach_timestamp(), buffer);
			}
			
			/* success

The document has moved <A HREF="http://captcha.chat.yahoo.com/go/captchat/close?.intl=us">here</A>.<P>
<!-- captchaes1.chat.dcn.yahoo.com uncompressed/chunked Sun Sep 16 05:26:25 PDT 2007 -->

The document has moved <A HREF="http://captcha.chat.yahoo.com/go/captchat/?tryagain=1&amp;img=http://ab.login.yahoo.com/img/O4EmpOVZFemR4jRjTRN5s1UgsqN7m9aZ687Ytn783knnSAatElKtDJGwWadcFHlMFnXn6eptkFzivSzsoQTaFAs-.jpg&amp;.intl=us">here</A>.<P>
<!-- captchaes1.chat.dcn.yahoo.com uncompressed/chunked Sun Sep 16 05:28:31 

			*/

			if (strstr(buffer, "/captchat/close?.intl")) {
				set_captcha_label(captcha_ui, _("Authorization succeeded!"));

				g_timeout_add(3000, destroy_captcha_window, captcha_ui);

				/* on a successful verification, we'll keep the verification strings
				 * around for a bit, because if the user goes to switch rooms, or
				 * rejoin the room, these strings can be used for a really quick revalidation!
				 *
				 * If we have any old verification strings, then free them up first
				 * and then save the current ones for the next revalidation attempt!
				 */
				if (last_captcha_response_post) {
					free(last_captcha_response_post);
				}
				last_captcha_response_post = post;
				post = NULL;
				if (last_captcha_response_image_url) {
					free(last_captcha_response_image_url);
				}
				last_captcha_response_image_url = image_url;
				image_url = NULL;
				if (last_captcha_response_cookie) {
					free(last_captcha_response_cookie);
				}
				last_captcha_response_cookie = strdup(form_struct->referer_cookie);

				if (!strcmp(ymsg_sess->room, "[NONE]")) {
					/* we've been disconnected from the room.
					 * Likely by an expired captcha attempt, so
					 * let's immediately re-do a /join...
					 */
					check_captcha_response(NULL);
				}

				/* Give yahoo 4 secs to get us a room list.
				 * If yahoo fails to deliver us a room list, then
				 * automatically rejoin the room.
				 */
				g_timeout_add(4000, check_captcha_response, NULL);

			}
			else {
				set_captcha_label(captcha_ui, _("Authorization FAILED! Guess again!"));
				if (entry) {
					gtk_widget_set_sensitive(entry, 1);
				}
				if (hbox) {
					gtk_widget_set_sensitive(hbox, 1);
				}
				gtk_widget_grab_focus(entry);
				gtk_editable_set_position(GTK_EDITABLE(entry), -1);
			}

			if (post) {
				free(post);
			}
			if (image_url) {
				free(image_url);
			}
		}
		else {
			on_captcha_window_killed(captcha_ui, NULL, NULL);
		}
	}
}

void on_captcha_entry_activate(GtkEditable *editable, gpointer user_data) {
	/* when enter is pressed, pretend that the [OK] button was pressed */
	on_captcha_ok_clicked((GtkWidget *)user_data, editable);
}

void on_captcha_cancel_clicked(GtkWidget *button, gpointer user_data) {
	GtkWidget *tmp_widget;

	tmp_widget = g_object_get_data(G_OBJECT(button), "mywindow");
	if (tmp_widget) {
		on_captcha_window_killed(tmp_widget, NULL, NULL);
	}		
}


GtkWidget *build_captcha(GtkWidget *parent, char *label_text)  {
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *label;
	GtkWidget *entry;
	GtkWidget *hbox;	
	GtkWidget *ok_button;
	GtkWidget *cancel_button;

	if (capture_fp) {
		fprintf(capture_fp,"\n[%s] INFO-DIALOG MESSAGE: '%s'\n", gyach_timestamp(), _("Building Captcha"));
		fflush(capture_fp);
	}

	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_wmclass(GTK_WINDOW(window), "gyachEDialog", "GYachI"); 
	gtk_window_set_title(GTK_WINDOW(window), _("GYachE Improved: Message"));
	gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
	if (parent) {
		gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
		gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(parent));
		gtk_window_set_destroy_with_parent(GTK_WINDOW(window), TRUE);
		gtk_window_present(GTK_WINDOW(parent));
	}
	else {
		gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
	}

	vbox = gtk_vbox_new(FALSE, 2);
	gtk_container_add(GTK_CONTAINER(window), vbox); 
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);  

	label=gtk_label_new(label_text);
	gtk_label_set_line_wrap(GTK_LABEL(label),1);
	//	gtk_label_set_selectable(GTK_LABEL(label), 1);
  	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 4);

	entry=gtk_entry_new();
  	gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 4);

	hbox=gtk_hbox_new(TRUE, 2);

	ok_button=get_pixmapped_button(_("OK"), GTK_STOCK_YES);
	set_tooltip(ok_button, _("OK"));
	g_object_set_data(G_OBJECT(ok_button), "mywindow", window);
	cancel_button=get_pixmapped_button(_("Cancel"), GTK_STOCK_CANCEL);
	set_tooltip(cancel_button, _("Cancel"));
	g_object_set_data(G_OBJECT(cancel_button), "mywindow", window);

	gtk_box_pack_start(GTK_BOX(hbox), ok_button, FALSE, FALSE, 2);
	gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" "), TRUE, TRUE, 2);
	gtk_box_pack_start(GTK_BOX(hbox), cancel_button, FALSE, FALSE, 2);
  	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 4);

	g_object_set_data(G_OBJECT(window), "label", label);
	g_object_set_data(G_OBJECT(window), "entry", entry);
	g_object_set_data(G_OBJECT(window), "vbox",  vbox);
	g_object_set_data(G_OBJECT(window), "hbox",  hbox);

	g_signal_connect(G_OBJECT(ok_button), "clicked",
                      G_CALLBACK(on_captcha_ok_clicked), entry);

	g_signal_connect(G_OBJECT(cancel_button), "clicked",
                      G_CALLBACK(on_captcha_cancel_clicked), NULL);

	g_signal_connect(G_OBJECT(window), "delete_event",
                      G_CALLBACK(on_captcha_window_killed), NULL);

	g_signal_connect(G_OBJECT(entry), "activate",
			    G_CALLBACK(on_captcha_entry_activate),
			    ok_button);

	gtk_widget_show_all(window);
	gtk_widget_hide(entry);
	gtk_widget_hide(hbox);
	gtk_widget_grab_focus(entry);
	gtk_editable_set_position(GTK_EDITABLE(entry), -1);
	return window;
}

void set_captcha_label(GtkWidget *captcha_ui, char *label_text) {
	GtkWidget *label;

	if (!GTK_IS_WINDOW(captcha_ui)) {
		/* window has been deleted / destroyed */
		return;
	}

	label=g_object_get_data(G_OBJECT(captcha_ui), "label");
	if (label) {
		gtk_label_set_label(GTK_LABEL(label), label_text);
	}
}


void set_captcha_image(GtkWidget *captcha_ui, char *jpg_image, int jpg_image_size)  {
	GtkWidget *vbox;
	GdkPixbufLoader *my_loader;
	GdkPixbuf *jpg_pixbuf;
	GtkWidget *image;
	int       rv;

	if (!GTK_IS_WINDOW(captcha_ui)) {
		/* window has been deleted / destroyed */
		return;
	}

	vbox = g_object_get_data(G_OBJECT(captcha_ui), "vbox");

	if (capture_fp) {	
		fprintf(capture_fp,"\n[%s] INFO-DIALOG MESSAGE: '%s'\n", gyach_timestamp(), _("Setting Captcha image"));
		fflush(capture_fp);
	}

	/* 1st, try to convert the jpg image into a GtkImage.
	 * If we can't do that, then we fail...
	 */

	set_captcha_label(captcha_ui, _("Loading jpeg image."));
	process_gtk_events();

	my_loader = gdk_pixbuf_loader_new();
	rv = gdk_pixbuf_loader_write(my_loader, jpg_image, jpg_image_size, 0);
	if (!rv) {
		/* loading jpg image failed */
		set_captcha_label(captcha_ui, _("Loading captcha jpg image failed.\nTry rejoin-ing the chat room"));
		return;
	}
	rv = gdk_pixbuf_loader_close(my_loader, 0);
	if (!rv) {
		/* closing jpg image loader failed */
		set_captcha_label(captcha_ui, _("Closing captcha jpg loader failed.\nTry rejoin-ing the chat room"));
		return;
	}
	jpg_pixbuf = gdk_pixbuf_loader_get_pixbuf(my_loader);
	image  = gtk_image_new_from_pixbuf(jpg_pixbuf);

	gtk_box_pack_start(GTK_BOX(vbox), image, TRUE, TRUE, 4);
	gtk_box_reorder_child(GTK_BOX(vbox), image, 0);

	set_captcha_label(captcha_ui, _("Please enter the characters from the above image into the entry box below, and Click [OK]\n"));
	gtk_window_resize (GTK_WINDOW(captcha_ui), 420, 270);

	gtk_widget_show_all(captcha_ui);
	return;
}



/* To help prevent spam and bots from disrupting your Yahoo! chat experience, please click here to verify your account (this link will open a new web browser window). This step is required before you can begin chatting. http://captcha.chat.yahoo.com/go/captchat/?img=http://ab.login.yahoo.com/img/Wcg6kuVZFekcZLRoTnsjduO1XVPgP8U.HIqDXPw9DN4g6jgRsj3XX9NSkQ4bCKIGAilw57_j9m5HNPSGpQ--.jpg&.intl=us
 */

void callback_start_tag(void *user_data, const XML_Char *tag_name, const XML_Char **attrs) {
	FORM_STRUCT *form_struct = user_data;
	char *attr_name,
	     *attr_value;

	//printf("START_TAG: %s\n", tag_name);

	/* for "form" we need to save off the "action" variable */
	if (!strcmp(tag_name, "form")) {
		attr_value = find_attribute(attrs, "action");
		if (form_struct->action && attr_value) {
			/* this should never really happen... */
			free(form_struct->action);
		}
		form_struct->action = attr_value ? strdup(attr_value) : 0;
	}


	/* for "input" elements, we need to save off the variable name, and value */
	if (!strcmp(tag_name, "input")) {
		attr_name  = find_attribute(attrs, "name");
		attr_value = find_attribute(attrs, "value");
		add_variable(form_struct, attr_name, attr_value);
	}
}


void callback_end_tag(void *user_data, const XML_Char *name) {	
	//printf("END_TAG: %s\n", name);
}

void handle_captcha(char *ymsg_105) {
	GtkWidget *captcha_ui;
	char *captcha_url;
	int   allocsize=8000;       /* the captchat url ought to be about 5 kb */
	char *captcha_buf=NULL;
	int   length;
	char *ptr;
	char *form_ptr;
	char *form_end;
	char  char_save;
	char *captcha_form;
	XML_Parser p;
	int   rv;

	FORM_STRUCT *form_struct;

	char *jpg_image=NULL;     /* the buffer for the captchat jpg file */
	char *jpg_url_ptr;
	int   jpg_size;

	/*
	 * heh heh heh. It turns out that once we have a valid captcha
	 * string, then that captcha validation string is still valid for
	 * subsequent validations, for a small period of time. From some
	 * testing, it's valid for "about 5 minutes".
	 * So...
	 * The 1st thing we're going to do is resend the last valid captcha
	 * validation, and if that succeeds, then we're done. We can ignore
	 * the new captcha request! :)
	 *
	 * If the old captcha string fails to validate, then it's back to
	 * where we were before, and we just do the full captcha thing.
	 */

	if (last_captcha_response_post) {
		char  buffer[1000];
		int   length;

		buffer[0]= 0;
		length = fetch_url(last_captcha_response_image_url, buffer, 900, last_captcha_response_post, last_captcha_response_cookie);
		if (capture_fp) {	
			fprintf(capture_fp,"\n[%s] CAPTCHA RESULT: '%s'\n", gyach_timestamp(), buffer);
		}
			

		if (strstr(buffer, "/captchat/close?.intl")) {
			/* success! We're done! */
			if (capture_fp) {	
				fprintf(capture_fp,"\n[%s] CAPTCHA REVERIFICATION SUCCEEDED!!!\n", gyach_timestamp());
			}
			return;
		}
		/* remember the room name of the room we are about to enter... */
		if (last_captcha_room) {
			free(last_captcha_room);
		}
		last_captcha_room = strdup(ymsg_sess->room);
  	}

	/* locate start of the url.
	 * It will be at the end of the string, with a space before it.
	 */

	captcha_url = strrchr(ymsg_105, ' ');
	if (!captcha_url) {
		/* space before the http://... not found. Shouldn't happen... */
		return;
	}

	captcha_url++;

	captcha_ui = build_captcha(chat_window, _("Fetching captcha url"));

	captcha_buf=malloc(allocsize);
	if (!captcha_buf) {
		set_captcha_label(captcha_ui, _("Failed to allocate memory for url buffer.\nTry rejoin-ing the chat room"));
		return;
	}

	*captcha_buf = 0;
	length = fetch_url(captcha_url, captcha_buf, allocsize-1, NULL, ymsg_sess->cookie);
	//int fd = creat("/home/hosler/captcha/captcha_form.html", 0664);
	//write(fd, captcha_buf, length);
	//close(fd);


	/* isolate the embedded post form within the url */
	captcha_form=0;
	ptr = captcha_buf;
	while (ptr) {
		form_ptr = strstr(ptr, "<form");
		form_end=0;
		if (form_ptr) {
			form_end = strstr(form_ptr, "/form>");
		}
		if (form_end) {
			form_end += 6;
			char_save = *form_end;
			*form_end = 0;

			ptr = strstr(form_ptr, "post");
			if (ptr) {
				captcha_form = form_ptr;
				break;
			} 

			*form_end = char_save;
			ptr = form_end;
		}
		else ptr = 0;
	}

	jpg_url_ptr = NULL;
	if (captcha_form) {
		//printf("CAPTCHA FORM: %s\n", captcha_form);
		set_captcha_label(captcha_ui, _("Captcha url fetched. Parsing form."));
		process_gtk_events();

		form_struct = create_form_struct();
		form_struct->referer_cookie = malloc(9 + strlen(captcha_url) + 10 + strlen(ymsg_sess->cookie) + 5);
		strcpy(form_struct->referer_cookie, "Referer: ");
		strcat(form_struct->referer_cookie, captcha_url);
		strcat(form_struct->referer_cookie, "\r\nCookie: ");
		strcat(form_struct->referer_cookie, ymsg_sess->cookie);

   		p = XML_ParserCreate(NULL);      /* XML_ParserCreate( "iso-8859-1"); */
		XML_SetElementHandler(p, callback_start_tag, callback_end_tag);

		XML_SetUserData(p, form_struct);

		rv = XML_Parse(p, captcha_form, strlen(captcha_form), 1);

		XML_ParserFree(p);	

		jpg_url_ptr = find_variable(form_struct, "question");
	}
	else {
		set_captcha_label(captcha_ui, _("Failed to fetch the Captcha url.\nTry rejoin-ing the chat room"));
		free(captcha_buf);
		return;
	}

	jpg_image = NULL;
	if (jpg_url_ptr) {
		set_captcha_label(captcha_ui, _(" Captcha form parsed.\nFetching the jpg image."));
		jpg_image=malloc(5000);
		if (jpg_image) {
			*jpg_image = 0;
			jpg_size = fetch_url(jpg_url_ptr, jpg_image, 5000-1, NULL, ymsg_sess->cookie);
			set_captcha_image(captcha_ui, jpg_image, jpg_size);

			g_object_set_data(G_OBJECT(captcha_ui), "form_struct", form_struct);
			free(jpg_image);
		}
	}

	if (!jpg_url_ptr) {
		/* could not process the captcha url
		 * Tell user to do it manually
		 */
		set_captcha_label(captcha_ui, _("Could not fetch the captcha jpg image.\nTry rejoin-ing the chat room"));
	}

	if (captcha_buf) {
		free(captcha_buf);
	}
}
