/*****************************************************************************
 * util.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 laater 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) 2003-2005, Erica Andrews
 * (Phrozensmoke ['at'] yahoo.com)
 * http://phpaint.sourceforge.net/pyvoicechat/
 * 
 * Copyright (C) 2000-2002 Chris Pinkham
 * cpinkham@corp.infi.net, cpinkham@bc2va.org
 * http://www4.infi.net/~cpinkham/gyach/
 * 
 * Released under the terms of the GPL.
 * *NO WARRANTY*
 *
 *****************************************************************************/

#include "config.h"

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <fcntl.h>
#include <poll.h>

#include <glib.h>
#if GLIB_CHECK_VERSION(2,6,0)
#       include <glib/gstdio.h>
#else
#       define g_freopen freopen
#       define g_fopen fopen
#       define g_rmdir rmdir
#       define g_remove remove
#       define g_unlink unlink
#       define g_lstat lstat
#       define g_stat stat
#       define g_mkdir mkdir
#       define g_rename rename
#       define g_open open
#endif


#include <unistd.h>

#ifdef USE_GDK_PIXBUF
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
#endif

#include "gyach.h"
#include "commands.h"
#include "gyach_int_text.h"
#include "interface.h"
#include "main.h"
#include "users.h"
#include "util.h"
#include "pmwindow.h"
#include "sounds.h"

SMILEY *smileys;
char mail_user[65] = "";
char *recv_sound = NULL;
char *send_sound = NULL;
int  profile_viewer = 1;
int support_scentral_smileys=1;

int show_yavatars=1;
int enable_audibles=1;
int activate_profnames=1;
int show_bimages=1;
int pm_window_style=1;
int pmb_toolbar1=1;
int pmb_toolbar2=1;
int auto_reject_invitations=0;
int pmb_audibles=1;
int pmb_smileys=1;
int pmb_send_erase=1;
char *flash_player_cmd=NULL;
char *bimage_file=NULL;
char *bimage_url=NULL;
int bimage_timestamp=0;
char *bimage_hash=NULL;
int bimage_friend_only=0;
int bimage_share=0;
int share_blist_avatar=1;
int bimage_size=1;

int chatwin_smileys=1;
int chatwin_send_erase=1;
int show_tabs_at_bottom=0;

/* Do buddy list avatars use 'png' or 'jpg' format from yahoo's servers */
/* as of this writing, Yahoo supports 3 filetypes: swf, png, jpg ... 
	now using jpg instead of png because of smaller size, sometimes 
	a difference of 40-45kb pngs to 10kb for jpg */			
/* can also use: 
	http://img.avatars.yahoo.com/users/%s.medium.png */ 

char *avatar_filetype="jpg";


/* added: PhrozenSmoke from fader.c */
extern char *get_formatted_color(char *some_color);
extern void check_proxy_config();

extern int enable_animations;

/* added PhrozenSmoke */

char *smiley_tags[90]={};
char *smiley_files[90]={};

int have_smiley_file(char *str) {
	int i=0;
	while (1)  {
		if (i>89) {return 0;}
		if (smiley_files[i]==NULL) {return 0;}
		if (strcasecmp(smiley_files[i],str)==0) {return 1;}
		i++;
				 }
	return 0;
}

void map_smileys() {
	SMILEY *sm_ptr;
	int i=0;
	sm_ptr = &smileys[0];
	while( sm_ptr->sm_text ) {
		if (i>89) {break;}		
		if (!  have_smiley_file(sm_ptr->sm_file)) {
			smiley_files[i]=sm_ptr->sm_file;
			smiley_tags[i]=sm_ptr->sm_text;
			i++;
																		  }
		sm_ptr++;
		
	}
	smiley_files[i]=NULL;
	smiley_tags[i]=NULL;
}

GtkWidget *load_smiley_icon(char *str) {
	int is_audible=0;
	GdkPixbufAnimation *anim = NULL;
	char filename[192]="";

	if (! strncmp(str,"base.us", 7)) { is_audible=1;}

	snprintf(filename,190,"%s/smileys/%s.gif", PACKAGE_DATA_DIR, str);
	if (is_audible) {
		/* its an audible */
		snprintf(filename,190,"%s/audibles/%s.gif", PACKAGE_DATA_DIR, str);
	}
	/* printf("file:  %s", filename);
	fflush(stdout);  */
	anim = gdk_pixbuf_animation_new_from_file(filename,NULL);
	if (anim)  {
		GtkWidget *myimage=NULL;
		if (gdk_pixbuf_animation_is_static_image(anim) || 
			(!enable_animations) || (is_audible) )   {
			GdkPixbuf *buf = NULL;
			buf=gdk_pixbuf_animation_get_static_image(anim);
			if (is_audible) {
				GdkPixbuf *spixbuf=NULL;
				int awidth=0;
				int aheight=0;	
				awidth = gdk_pixbuf_get_width( buf );
				aheight = gdk_pixbuf_get_height( buf );
				aheight = ( 1.0 *  aheight / awidth ) * 40;
				awidth = 40;
				spixbuf = gdk_pixbuf_scale_simple( buf, awidth, aheight,
								   GDK_INTERP_BILINEAR );
				if (spixbuf) {
					myimage=gtk_image_new_from_pixbuf(spixbuf);
					g_object_unref( spixbuf );
				}
				else {myimage=gtk_image_new_from_pixbuf(buf);}
			}
			else {
				myimage=gtk_image_new_from_pixbuf(buf);
			}
			gtk_widget_show_all(myimage);
			//g_object_unref( buf );  /* creates seg-faults, dont re-enable */
		}
		else {
			myimage=gtk_image_new_from_animation(anim);
			gtk_widget_show_all(myimage);
		}

		gdk_pixbuf_animation_unref(anim);
		return myimage;
	}
	return NULL;
}


void strip_html_tags( char *str ) {
	char *to, *from;

	// DBG( 21, "strip_html_tags()\n" );

	to = str;
	from = str;

	while( *from ) {
		if ( *from == '<' ) {
			from++;
	
			if ( (!strncasecmp(from,"tr",2)) || 
				(!strncasecmp(from,"table",5)) ) {
				/* add newline char */ 
				*to = '\n';
				to++;
			}

			while(( *from ) &&
				  ( *from != '>' ) &&
				  ( *from != '<' )) {
				from++;
			}
			if ( *from )
				from++;
		}
		else {
			*to = *from;
			to++;
			from++;
		}
	}
	*to = *from;

	to = str;
	from = str;
	while( *from ) {
		if ( *from == '\r' ) {
			from++;
			continue;
		}
		else if ( *from == '\t' ) { /* tabs */
			from++;
			*to = ' ';
			to++;
			continue;
		}
		else if ( *from == '&' ) {
 			if (( *(from+1) == '#' ) &&
					   ( *(from+2) == '1' ) &&
					   ( *(from+3) == '8' ) &&
					   ( *(from+4) == '3' ) &&
					   ( *(from+5) == ';' )) {
				from += 6;
				*to = '\n';
				to++;
				continue;
			}
			if ( *(from+1) == '#' ) {
				while( ( *from ) && (*from != ';') ) {
					from++;
				}
				from++;
				continue;
			}
			if (( *(from+1) == 'n' ) &&
					   ( *(from+2) == 'b' ) &&
					   ( *(from+3) == 's' ) &&
					   ( *(from+4) == 'p' ) &&
					   ( *(from+5) == ';' )) {
				from += 6;
				*to = ' ';
				to++;
				continue;
			}
		}
		*to = *from;
		to++;
		from++;
	}
	*to = *from;

	to = str;
	from = str;
	while( *from ) {
		if (( *from == '\n' ) &&
			( *(from+1) == '\n' )) {
		}
		else {
			*to = *from;
			to++;
		}
		from++;
	}
	*to = *from;

	/* now strip "\033[30m" style entries */
	to = str;
	from = str;
	while( *from ) {
		if ( *from == '\033' ) {
			while(( *from ) &&
				( *from != 'm' )) {
				from++;
			}
		}
		else {
			*to = *from;
			to++;
		}
		if ( *from )
			from++;
	}
	*to = *from;
}

/* common code very commonly used to set a tooltip */
void set_tooltip(GtkWidget *somewid, char *somechar) {
        GtkTooltips *TIP_GROUP;

	if (!somewid) {return;}
	TIP_GROUP = GTK_TOOLTIPS(g_object_get_data(G_OBJECT(somewid), "tooltip_group"));
	if ( TIP_GROUP == NULL ) {
		TIP_GROUP = gtk_tooltips_new();
		g_object_set_data(G_OBJECT(somewid), "tooltip_group", TIP_GROUP);
	}

	if (!somechar) {
		gtk_tooltips_disable(TIP_GROUP);
		return;
	}

	gtk_tooltips_set_tip(TIP_GROUP, somewid, somechar, somechar);
	gtk_tooltips_enable(TIP_GROUP);
}


/* unashamedly borrowed from gaim */
int gyachi_build_dir(const char *path, int mode)
{
	char *dir, **components, delim[] = { G_DIR_SEPARATOR, '\0' };
	char error_message[1024];
	int cur, len;

	g_return_val_if_fail(path != NULL, -1);

	dir = g_new0(char, strlen(path) + 1);
	components = g_strsplit(path, delim, -1);
	len = 0;
	for (cur = 0; components[cur] != NULL; cur++) {
		/* If you don't know what you're doing on both
		 * win32 and *NIX, stay the hell away from this code */
		if(cur > 1)
			dir[len++] = G_DIR_SEPARATOR;
		strcpy(dir + len, components[cur]);
		len += strlen(components[cur]);
		if(cur == 0)
			dir[len++] = G_DIR_SEPARATOR;

		if(g_file_test(dir, G_FILE_TEST_IS_DIR)) {
			continue;
#ifdef _WIN32
		/* allow us to create subdirs on UNC paths
		 * (\\machinename\path\to\blah)
		 * g_file_test() doesn't work on "\\machinename" */
		}
		else if (cur == 2 && dir[0] == '\\' && dir[1] == '\\'
				&& components[cur + 1] != NULL) {
			continue;
#endif
		}
		else if(g_file_test(dir, G_FILE_TEST_EXISTS)) {
			snprintf(error_message, sizeof(error_message), "gyachi_build_dir:bad path: %s\n", path);
			show_ok_dialog(error_message);
			g_strfreev(components);
			g_free(dir);
			return -1;
		}

		if (g_mkdir(dir, mode) < 0) {
			snprintf(error_message, sizeof(error_message), "gyachi_build_dir:mkdir: %s\n", strerror(errno));
			show_ok_dialog(error_message);
			g_strfreev(components);
			g_free(dir);
			return -1;
		}
	}

	g_strfreev(components);
	g_free(dir);
	return 0;
}

const char *gyach_timestamp() {
	static char stampbuf[64]="";
	time_t time_now;
	struct tm *tm_now;

	time_now = time( NULL );
	tm_now = localtime( &time_now );
	/* Localize date/time */
	
	if (! strftime( stampbuf, 62, "%x %T", tm_now )) {
	    snprintf( stampbuf, 62, "%d/%d/%d %02d:%02d:%02d",
		      tm_now->tm_mon + 1, tm_now->tm_mday, tm_now->tm_year + 1900,
		      tm_now->tm_hour, tm_now->tm_min,tm_now->tm_sec );
	}
	return(stampbuf);
}

const char *yahoo_timestamp() {
	static char timebuf[64]="";
	
	snprintf( timebuf, 62, "<font size=\"10\">%s[%s]", YAHOO_COLOR_BLACK, gyach_timestamp() );
	return(timebuf);
}


int my_system( char *command ) {
	int pid;
	int status;

	if ( ! command ) {
		return( 1 );
	}

	pid = fork();
	if ( pid == -1 ) {
		return( -1 );
	}
	else if ( pid == 0 ) {
		char *argv[4];
		
		argv[0] = "sh";
		argv[1] = "-c";
		argv[2] = command;
		argv[3] = 0;

		if ( capture_fp ) {	
			fprintf(capture_fp,"\n[%s] EXTERNAL PROCESS LAUNCHED in 'my_system', Command-Line: sh -c %s\n",
				gyach_timestamp(), command);
			fflush( capture_fp );
		}

		execv( "/bin/sh", argv );
		exit( 127 );
	}
	else {
		while( 1 ) {
			if ( waitpid( pid, &status, 0 ) == -1 ) {
				return( -1 );
			}
			else {
				return( status );
			}
		}
	}
}

/* NOTE: this function frees *arg when done, so use strdup() before calling */
void *display_url( void *arg ) {
	char *url = (char *)arg;
	char cmd[768];

	if ( ! url ) { return( NULL ); }

	if ( strlen( url ) == 0 ) {
		free( url );
		return( NULL );
	}

	/* quick sanity check */
	if (( strchr( url, ';' )) ||
		( strchr( url, '`' ))) {
		free( url );
		return( NULL );
	}

	snprintf(cmd, sizeof(cmd)-1, browser_command, url);
	my_system(cmd);
	free(url);
	return(NULL);
}


void lower_str( char *str ) {
	char tmp[1280];
	char *dst = str;
	char *src = tmp;

	strncpy(tmp, str, 1278 );
	while (*src) {
		*(dst++) = tolower(*(src++));
 	}
}


GtkWidget *find_parent_window(GtkWidget *thing)
{
	GtkWidget *parent_window = thing;

	while (parent_window && !GTK_IS_WINDOW(parent_window)) {
		parent_window = gtk_widget_get_parent(parent_window);
	}

	return (parent_window);
}

/* this list is prioritized a little, since a few smileys are the same */
/* as others except for one extra char at the end, 
    files are format 89.gif, 33.gif, etc. */

SMILEY default_smileys[] = {
	{ ":(|)", "51" },
	{ "(:|", "37" },
	{ ":)>-", "67" },
	{ "\\:d/", "69" }, { "\\:D/", "69" },	
	{ ":))", "21" },	{ ":-))", "21" },
        { ":)]", "100" },
	{ ":)", "01" },	{ "(:", "01" },	{ "(-:", "01" },	{ ":-)", "01" },
	{ ":((", "20" },	{ ":-((", "20" },
	{ ":(", "02" },	{ ":-(", "02" },
	{ ";))", "71" },
	{ ";;)", "05" },	{ ";;-)", "05" },
	{ ";)", "03" },	{ ";-)", "03" },
	{ ":D", "04" },	{ ":-D", "04" },
	{ ":-/", "07" },	{ ":-\\", "07" },
	{ ":x", "08" },	{ ":-x", "08" },	{ ":X", "08" },	{ ":-X", "08" },
	{ ":\">", "09" },
	{ ">:p", "47" }, 	{ ">:P", "47" },
	{ ":p", "10" },	{ ":-p", "10" },	{ ":P", "10" },	{ ":-P", "10" },
	{ ":-*", "11" }, { "=*", "11" },	{ ":*", "11" },	
	{ "=((", "12" },
	{ ":o)", "34" },	{ ":O)", "34" },	{ ":0)", "34" },
	{ ":-o", "13" }, { ":O", "13" },	{ ":-O", "13" },  { ":0", "13" },	{ ":-0", "13" },  
	{ "X(", "14" },	{ "X-(", "14" },
	{ ":>", "15" },	{ ":->", "15" },
	 { "b-)", "16" }, { "B-)", "16" },
	{ "#:-s", "18" }, 	{ "#:-S", "18" },
	{ ":-ss", "42" }, 	{ ":-SS", "42" },
	{ ":-s", "17" }, 	{ ":-S", "17" },
	{ ">:)", "19" },
	{ ":|", "22" },	{ ":-|", "22" },
	{ "/:)", "23" }, { "/:-)", "23" },	
	{ "=))", "24" },
	{ "o:-)", "25" }, { "0:-)", "25" },	{ "O:-)", "25" }, { "o:)", "25" }, { "0:)", "25" }, { "8-)", "25" }, { "8)", "25" },
	{ ":-B", "26" }, { ":-b", "26" },
	{ "=;", "27" },
	{ "i-)", "28" }, { "I-)", "28" },	{ "|-)", "28" }, 
	{ "8-|", "29" },
	{ "l-)", "30" },
	{ ":-&", "31" },
	{ ":-$", "32" },
	{ "[-(", "33" },
	{ "8-}", "35" },

	{ "<:-p", "36" },

	{ "=p~", "38" },
        { ":-??", "106" },
	{ ":-?", "39" },
	{ "#-o", "40" },
	{ "=D>", "41" },
	
	{ "@-)", "43" },
	{ ":^o", "44" }, { ":^0", "44" },  { ":^O", "44" },
	{ ":-w", "45" }, 	{ ":-W", "45" },
	{ ":-<", "46" },

	{ ":@)", "49" },
	{ "3:-O", "50" }, { "3:-0", "50" },	{ "3:-o", "50" },  
	{ "~:>", "52" },
	{ "@};-", "53" },
	{ "%%-", "54" },
	{ "**==", "55" },
	{ "(~~)", "56" },
	{ "~o)", "57" },
	{ "*-:)", "58" },
	{ "8-X", "59" }, { "8-x", "59" },
	{ "=:)", "60" },	{ "=:-)", "60" },
	{ ">-)", "61" },
	{ ":-l", "62" }, { ":-L", "62" },
	{ "<):)", "48" },
	{ "[-o<", "63" },
	{ "$-)", "64" },
	{ ":-\"", "65" },
	{ "b-(", "66" },	{ "B-(", "66" },
	{ "[-x", "68" }, { "[-X", "68" },  
	{ ">:D<", "06" }, 	{ ">:d<", "06" },
	{ ">:/", "70" },

	{ "o->", "72" },
	{ "o=>", "73" },
	{ "o-+", "74" },
	{ "(%)", "75" },

	{ ":-@", "76" },
	{ "^:)^", "77" },
	{ ":-j", "78" }, { ":-J", "78" },
	{ "(*)", "79" },
        { ":-c", "101" },
        { "~X(", "102" },
        { ":-h", "103" },
        { ":-t", "104" },
        { "8->", "105" },
        { "%-(", "107" },
        { ":o3", "108" },
	{ 0, 0 }
};



SMILEY read_smileys[256];

void smileys_load() {
	SMILEY *sm_ptr;
	char filename[192];
	FILE *fp;
	struct stat sbuf;
	char buf[201];
	char *sm_text;
	char *sm_file;
	char *end;
	int override_smile=1;

	snprintf( filename, 190, "%s/.yahoorc/gyach/emoticons", getenv( "HOME" ));

	if ( stat( filename, &sbuf )) {
		/* doesn't exist so write and use default */
		fp = fopen( filename, "w" );
		if ( fp ) {
			fprintf( fp,
				"# format of file is emoticon_text<tab>emoticon_file\n# Place this file at ~/.yahoorc/gyach/emoticons\n# You probably shouldnt change the order of these too much.\n# NOTE: This file is no longer being read by Gyach-E - built-in emoticon configurations are being  used.  This file remains for historic purposes only" );
			sm_ptr = default_smileys;
			while( sm_ptr->sm_file ) {
				fprintf( fp, "%s	%s\n", sm_ptr->sm_text, sm_ptr->sm_file );
				sm_ptr++;
			}
			fclose( fp );
		}
		smileys = default_smileys;
	}
	else {
		/* changed here: PhrozenSmoke - do not use emoticon config file anymore
		it will screw up support for Yahoo's new smileys...the builtin configuration 
		will suit most folks just fine */

		if (override_smile) {
			smileys = default_smileys;
			return;
		}


		/* exists, so open and read */
		smileys = read_smileys;
		sm_ptr = smileys;
		fp = fopen( filename, "r" );
		if ( fp ) {
			while( fgets( buf, 200, fp )) {
				/* chop the newline */
				buf[strlen(buf)-1] = '\0';
				sm_text = skip_whitespace( buf );
				
				if ( *sm_text == '#' ) {
					continue;
				}

				end = find_whitespace( sm_text );
				if ( ! *end ) {
					/* invalid line, no filename given */
					continue;
				}
				*end = '\0';

				sm_file = skip_whitespace( end + 1 );
				end = find_whitespace( sm_file );
				*end = '\0';

				sm_ptr->sm_text = strdup( sm_text );
				sm_ptr->sm_file = strdup( sm_file );
				sm_ptr++;
			}
			fclose( fp );
			sm_ptr->sm_text = NULL;
			sm_ptr->sm_file = NULL;
		}
	}
}

int check_smiley( char *str ) {
	SMILEY *sm_ptr;

	sm_ptr = &smileys[0];
	while( sm_ptr->sm_text ) {
		if (( !strncmp( str, sm_ptr->sm_text, strlen(sm_ptr->sm_text))) &&
			(( strchr( " \n", str[strlen(sm_ptr->sm_text)] )) ||
			 ( ! str[strlen(sm_ptr->sm_text)] ))) {
			return( 1 );
		}
		sm_ptr++;
	}

	return( 0 );
}


void convert_smileys( char *str ) {
	char tmp[4096];
	char sm_code[66];
	char *from;
	char *to;
	int found;
	SMILEY *sm_ptr;
	char last_char=' ';
	int open_html_tag=0;

	// printf("STUFF:  %s\n",str); fflush(stdout);

	/* return if too long */
	if ( strlen( str ) > 3250 )
		return;

	strncpy( tmp, str, 3250 );

	from = tmp;
	to = str;
	*to = '\0';

	while( *from ) {
		found = 0;

		/* support SmileyCentral retrievable smileys, on the web */
		/* Parse SmileyCentral.com smiley codes that look something like this:
				@[smiley: Hi Ya : [15/15_1_70]]
		   into a downloadable URL for an animated .gif file like this:
				http://smileys.smileycentral.com/cat/15/15_1_70.gif

		   We can see the SmileyCentral.com smileys (instead of the ugly code)
		   WITHOUT all the spyware that comes with the SmileyCentral.com
		   software for Windoze!  The animated .gifs (there are THOUSANDS) 
		   on that site, are being more commonly used in the chat rooms.
		*/
		
		if ( !strncasecmp( from, "@[smiley", 8)) {		
			if (strstr(from,"]"))  {
				char *smender=NULL;
				from +=7;
				while (*from)    {
					if (*from=='[') {
						from++;
						break;
					}
					from++;
				}
				smender=strstr(from,"]");
				if (*from  && smender)  {
					*smender='\0';

					if (support_scentral_smileys) {
						snprintf( sm_code, 42, " %s", 
									"\033|scnt://smileys.smileycentral.com/cat/" );
						/* snprintf( sm_code, 42, "\033|%s", "scnt://localhost/ism/" ); */
						strncat(sm_code,from,16);
						strcat(sm_code,".gif ");
						strcat( to, sm_code );
					}
					else { /* user doesn't want SmileyCentral emoticons */
						snprintf( sm_code, 30, " [%s] ", "SC-Smiley" );
						strcat( to, sm_code );
					} 
					to += strlen( sm_code );
					found=1;
					smender += 1;
					if (*smender==']') {smender += 1;}
					from=smender;
				}
			}
		}

		sm_ptr = &smileys[0];
		while(( sm_ptr->sm_text ) && ( ! found )) {
			/* if ( ! ( (strstr( str, "has entered") != NULL || strstr( str, "has left") != NULL) && (strstr( str, "the room") != NULL )  ) )  { */

			/* This is a bug fix below: PhrozenSmoke */ 
			if ( ! open_html_tag)  {
				if ( !strncasecmp( from, sm_ptr->sm_text, strlen(sm_ptr->sm_text))) {
					if (( !strncmp( ":0", sm_ptr->sm_text, 2)) && isdigit(last_char)) {
						found=0;
					}
					else {
						found = 1;
						snprintf( sm_code, 9, "\033|%s ", sm_ptr->sm_file );
						strcat( to, sm_code );
						to += strlen( sm_code );
						from += strlen( sm_ptr->sm_text );
					}
				} 
			} /* end if */
			sm_ptr++;
		}
		if ( ! found ) {
			*to = *from;
			last_char=from[0];
			if (last_char=='>') {open_html_tag=0;}
			if (last_char=='<') {open_html_tag=1;}
			to++;
			from++;
			*to = '\0';
		}
	}
}

char *get_last_color( char *str ) {
	char *ptr;

	ptr = str + strlen( str );
	while(( ptr > str ) &&
		( *ptr != '|' )) {
		ptr--;
	}

	if ( ptr == str ) {
		return( ptr );
	}

	if ( *ptr == '|' ) {
		*ptr = '\0';
		ptr++;
		return( ptr );
	}

	/* should never get here */
	return( YAHOO_COLOR_BLACK );
}




/*
 * attempt to highlight urls if they aren't already highlighted along with
 * turning html style tags into esc sequences.
 */
void convert_tags( char *str ) {
	char tmp[4096];
	char *from;
	char *to;
	char *ptr;
	char *ptr2;
	char *ptr3;
	int len = 0;
	char tmp2[512];
	char colors[2048] = YAHOO_COLOR_BLACK;
	char prev_color[25] = YAHOO_COLOR_BLACK;
	char *cptr;

	/* PhrozenSmoke test code, ignore this */

	 /*printf("\nTAG:  %s\n",str);
	     fflush(stdout);  */


	// DBG( 21, "convert_tags( '%s' )\n", str );

	/* return if too long */
	if ( strlen( str ) > 3200 )
		return;

	/* convert html tags to ESC sequences */
	if ( strchr( str, '<' )) {
		memset( tmp, 0, sizeof( tmp ));

		from = str;
		to = tmp;

		ptr = strchr( from, '<' );
		while( ptr ) {
			len = ptr - from;
			strncpy( to, from, len );
			to += len;
			*to = '\0';
			from += len;

			if ( !strncasecmp( from, "<black>", 7 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_BLACK );
					to += strlen( YAHOO_COLOR_BLACK );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_BLACK, 23 );
				}
				from += 7;
			}
			else if ( !strncasecmp( from, "<blue>", 6 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_BLUE );
					to += strlen( YAHOO_COLOR_BLUE );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_BLUE, 23 );
				}
				from += 6;
			}
			else if ( !strncasecmp( from, "<cyan>", 6 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_CYAN );
					to += strlen( YAHOO_COLOR_CYAN );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_CYAN, 23 );
				}
				from += 6;
			}
			else if ( !strncasecmp( from, "<gray>", 6 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_GRAY );
					to += strlen( YAHOO_COLOR_GRAY );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_GRAY, 23 );
				}
				from += 6;
			}
			else if ( !strncasecmp( from, "<green>", 7 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_GREEN );
					to += strlen( YAHOO_COLOR_GREEN );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_GREEN, 23 );
				}
				from += 7;
			}
			else if ( !strncasecmp( from, "<pink>", 6 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_PINK );
					to += strlen( YAHOO_COLOR_PINK );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_PINK , 23);
				}
				from += 6;
			}
			else if ( !strncasecmp( from, "<purple>", 8 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_PURPLE );
					to += strlen( YAHOO_COLOR_PURPLE );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_PURPLE, 23 );
				}
				from += 8;
			}
			else if ( !strncasecmp( from, "<orange>", 8 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_ORANGE );
					to += strlen( YAHOO_COLOR_ORANGE );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_ORANGE, 23 );
				}
				from += 8;
			}
			else if ( !strncasecmp( from, "<red>", 5 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_RED );
					to += strlen( YAHOO_COLOR_RED );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_RED, 23 );
				}
				from += 5;
			}
			else if ( !strncasecmp( from, "<yellow>", 8 )) {
				if ( show_html ) {
					strcat( to, YAHOO_COLOR_YELLOW );
					to += strlen( YAHOO_COLOR_YELLOW );
					strcat( colors, "|" );
					strcat( colors, prev_color );
					strncpy( prev_color, YAHOO_COLOR_YELLOW, 23);
				}
				from += 8;
			}
			else if (( !strncasecmp( from, "</black>", 8 )) ||
				( !strncasecmp( from, "</blue>", 7 )) ||
				( !strncasecmp( from, "</cyan>", 7 )) ||
				( !strncasecmp( from, "</gray>", 7 )) ||
				( !strncasecmp( from, "</green>", 8 )) ||
				( !strncasecmp( from, "</pink>", 7 )) ||
				( !strncasecmp( from, "</purple>", 9 )) ||
				( !strncasecmp( from, "</orange>", 9 )) ||
				( !strncasecmp( from, "</red>", 6 )) ||
				( !strncasecmp( from, "</yellow>", 9 ))) {
				if ( show_html ) {
					cptr = get_last_color( colors );
					strcat( to, cptr );
					to += strlen( cptr );
				}
				while( *from != '>' ) {
					from++;
				}
				from++;
			}
			else if ( !strncasecmp( from, "<i>", 3 )) {
				if ( show_html ) {
					strcat( to, YAHOO_STYLE_ITALICON );
					to += strlen( YAHOO_STYLE_ITALICON );
				}
				from += 3;
			}
			else if ( !strncasecmp( from, "</i>", 4 )) {
				if ( show_html ) {
					strcat( to, YAHOO_STYLE_ITALICOFF );
					to += strlen( YAHOO_STYLE_ITALICOFF );
				}
				from += 4;
			}
			else if ( !strncasecmp( from, "<b>", 3 )) {
				if ( show_html ) {
					strcat( to, YAHOO_STYLE_BOLDON );
					to += strlen( YAHOO_STYLE_BOLDON );
				}
				from += 3;
			}
			else if ( !strncasecmp( from, "</b>", 4 )) {
				if ( show_html ) {
					strcat( to, YAHOO_STYLE_BOLDOFF );
					to += strlen( YAHOO_STYLE_BOLDOFF );
				}
				from += 4;
			}
			else if ( !strncasecmp( from, "<font", 5 )) {
				/* EXPERIMENTAL - skip beginning font tags */
				/*
				  from += 5;
				  while(( *from ) && ( *from != '>' )) {
					from++;
				  }
				  from++;
				*/
				/* this basically insures that "<font" is in lowercase */
				from += 5;
				*(to++) = '<';
				*(to++) = 'f';
				*(to++) = 'o';
				*(to++) = 'n';
				*(to++) = 't';
			}
			else if ( !strncasecmp( from, "</font>", 7 )) {
				/* skip ending font tags */
				from += 7;
			}
			else if ( !strncasecmp( from, "<alt", 4 )) {

				if (show_blended_colors) {
					/* PhrozenSmoke: changed here, SAVE, dont skip this tag */
					ptr=from;
					while ((*ptr) && (*ptr != '>')) {
						*(to++)=*(ptr++); 
					}
					if (*ptr == '>') {*(to++)=*(ptr++); }

				}
				else {
					while ((*ptr) && (*ptr != '>')) {ptr++;}
					if (*ptr == '>') {ptr++; }
				}

				from=ptr;
			}
			else if ( !strncasecmp( from, "</alt>", 6 )) {
				if (show_blended_colors) {
					/* PhrozenSmoke: changed here, SAVE, dont skip this tag */
					ptr=from;
					while ((*ptr) && (*ptr != '>')) {
						*(to++)=*(ptr++); 
					}
					if (*ptr == '>') {*(to++)=*(ptr++); }
				}
				else {
					while ((*ptr) && (*ptr != '>')) {ptr++;}
					if (*ptr == '>') {ptr++; }
				}

				from=ptr;

				/* skip ending alt tags */
				/* from += 6; */  /* disabled: PhrozenSmoke */
			}
			else if ( !strncasecmp( from, "<url=", 5 )) {
				/* skip beginning url tags */
				ptr = from + 5;
				while(( *ptr ) && ( *ptr != '>' )) {
					*(to++) = *(ptr++);
				}
				from = ptr;
				if ( *ptr )
					from++;
				*(to++) = ' ';
				*(to++) = '(';
			}
			else if ( !strncasecmp( from, "</url>", 6 )) {
				/* skip ending url tags */
				*(to++) = ')';
				from += 6;
			}
			else if (( !strncasecmp( from, "<snd", 4 )) ||
					   ( !strncasecmp( from, "<sound", 6 ))) {
				/* skip beginning snd tags */
				if ( from[2] == 'n' ) {
					ptr = from + 4;
				}
				else {
					ptr = from + 6;
				}

				from=ptr;
				if (( *ptr ) &&
					( *ptr == '=' )) {
					ptr++;
				}
				while(( *ptr ) && ( *ptr != '>' )) {
					ptr++;
				}
				if (( *ptr ) &&
					( *from == '=' )) {
					/* remember this sound so we can play it */
					if ( recv_sound ) {
						free( recv_sound );
						recv_sound = NULL;
					}
					if ((ptr-from-1) < sizeof(tmp2)) {
						strncpy(tmp2, from+1, ptr-from-1);
						tmp2[ptr-from-1] = '\0';
						recv_sound = strdup( tmp2 );
					}
				}
				from = ptr;
				if ( *ptr )
					from++;
			}
			else if ( !strncasecmp( from, "</snd>", 6 )) {
				/* skip ending snd tags */
				from += 6;
			}
			else if ( !strncasecmp( from, "<fade", 5 )) {
				if (show_blended_colors) {
					/* PhrozenSmoke: changed here, SAVE, dont skip this tag */
					ptr=from;
					while ((*ptr) && (*ptr != '>')) {
						*(to++)=*(ptr++); 
					}
					if (*ptr == '>') {*(to++)=*(ptr++); }
				}
				else {
					while ((*ptr) && (*ptr != '>')) {ptr++;}
					if (*ptr == '>') {ptr++; }
				}

				from=ptr;

			}
			else if ( !strncasecmp( from, "</fade>", 7 )) {
				if (show_blended_colors) {
					/* PhrozenSmoke: changed here, SAVE, dont skip this tag */
					ptr=from;
					while ((*ptr) && (*ptr != '>')) {
						*(to++)=*(ptr++); 
					}
					if (*ptr == '>') {*(to++)=*(ptr++); }
				}
				else {
					while ((*ptr) && (*ptr != '>')) {ptr++;}
					if (*ptr == '>') {ptr++; }
				}

				from=ptr;

				/* skip ending fade tags */
				/* from += 7; */ /* disabled: PhrozenSmoke */
			}
			else {
				 *(to++) = *(from++); 
			}
			ptr = strchr( from, '<' );
		}

		strcat( to, from );
		to += strlen( from );
		*to = '\0';
		strcpy( str, tmp );

		/*
		  if ( ! strchr( str, '\n' ))
			strcat( str, "\n" );
		*/
	}

	/* return if no urls */
	if (( ! strstr( str, "http://" )) && ( ! strstr( str, "https://" )) && 
		( ! strstr( str, "ftp://" ))) {
		return;
	}

	/* return if already marked */
	if ( strstr( str, YAHOO_STYLE_URLON ))
		return;

	/* return if not showing html */
	if ( ! show_html )
		return;

	memset( tmp, 0, sizeof( tmp ));

	from = str;
	to = tmp;

	/* search for ftp:// and http:// */
	ptr2 = strstr( str, "http://" );
		if (!ptr2) {ptr2=strstr( str, "https://" );}
	ptr3 = strstr( str, "ftp://" );

	if ( ptr2 && ptr3 ) {
		ptr = ptr2 < ptr3 ? ptr2 : ptr3;
	}
	else if ( ptr2 ) {
		ptr = ptr2;
	}
	else if ( ptr3 ) {
		ptr = ptr3;
	}
	else {
		ptr = NULL;
	}

	while( ptr ) {
		len = ptr - from;
		strncpy( to, from, len );
		to += len;
		*to = '\0';

		from += len;

		strcat( to, YAHOO_STYLE_URLON );
		to += strlen( YAHOO_STYLE_URLON );

		while(( *from ) && ( ! isspace( *from ))) {
			*(to++) = *(from++);
		}
		*to = '\0';

		strcat( to, YAHOO_STYLE_URLOFF );
		to += strlen( YAHOO_STYLE_URLOFF );

		/* search for ftp:// and http:// */
		ptr2 = strstr( from, "http://" );
		if (!ptr2) {ptr2=strstr( from, "https://" );}
		ptr3 = strstr( from, "ftp://" );

		if ( ptr2 && ptr3 ) {
			ptr = ptr2 < ptr3 ? ptr2 : ptr3;
		}
		else if ( ptr2 ) {
			ptr = ptr2;
		}
		else if ( ptr3 ) {
			ptr = ptr3;
		}
		else {
			ptr = NULL;
		}
	}

	strcat( to, from );
	to += strlen( from );
	*to = '\0';
	strcpy( str, tmp );
}

/*
 * strip junk (like "<snd" directives out of text
 */
void strip_junk( char *str ) {
	// DBG( 21, "strip_junk( '%s' )\n", str );

	/* fixme */
}

/*
 * read a fd with non-blocking i/o.
 * BEFORE CALLING, the fd must already be set to be non-blocking
 * i.e.:
 *
 *	fcntl(sock, F_SETFL, (long)O_NONBLOCK);
 *
 * upon return, at most size bytes have been read into buf, using
 * non-blocking i/o, calling process_gtk_events() during the idle
 * time.
 */

int read_sock(int sock, char *buf, int size, int secs)
{
	struct pollfd our_fd;
	char *ptr;
	int nr;
	int tr;
	int done;
	int count;
	int rv;

	tr = 0;
	rv = 0;
	done = 0;
	ptr = buf;
	set_socket_timer(sock, secs);
	while ((!done) && (tr < size)) {
		our_fd.fd = sock;
		our_fd.events = POLLIN;
		count = poll(&our_fd, 1, 750);	/* 3/4 sec */

		if (count > 0) {
			if (our_fd.revents & POLLIN) {
				set_socket_timer(sock, -1);
				nr = read( sock, ptr, size-tr );
				while((nr > 0) && (tr < size)) {
					//printf("read %d bytes of %d/%d. Total read: %d\n", nr, size-tr, size, tr+nr);
					ptr += nr;
					tr += nr;
					rv = tr;
					nr = read(sock, ptr, size-tr );
				}
				if (nr == 0) {
					/* end-of-file */
					done=1;
					//printf("eof\n\n");
				}
				if (nr < 0) {
					if (errno != EAGAIN) {
						//int my_errno=errno;
						//printf("socket read error: readcount: %d, errno: %d, %s\n", nr, my_errno, strerror(my_errno));
						/* some other error happened.
						 * Likely the 12 sec timer went off, and closed the socket.
						 * this will end up cancelling the read with an errno(9) (Bad file descriptor) error.
						 * This, actually, shouldn't happen, at least not very often.
						 */
						rv = -1;
						done=1;
					}
				}
			}
			else {
				//int my_errno=errno;
				//printf("poll error: errno: %d, %s\n", my_errno, strerror(my_errno));
				/* some other error happened.
				 * Likely the 12 sec timer went off, and closed the socket.
				 * this will end up cancelling the read with an errno(9) (Bad file descriptor) error.
				 * This, actually, shouldn't happen, at least not very often.
				 */
				rv = -1;
				done = 1;
			}
		}
		if (count < 0) {
			//int my_errno=errno;
			//printf("poll error: errno: %d, %s\n", my_errno, strerror(my_errno));
			/* some other error happened.
			 * Likely the 12 sec timer went off, and closed the socket.
			 * this will end up cancelling the read with an errno(9) (Bad file descriptor) error.
			 * This, actually, shouldn't happen, at least not very often.
			 */
			rv = -1;
			done = 1;
		}
		process_gtk_events();			  
	}

	set_socket_timer(sock, -1);
	return(rv);
}

int write_sock(int sock, char *buf, int size, int secs)
{
	char *ptr;
	int nr;
	int tr;
	int done;
	int count;
	int rv;
	struct pollfd our_fd;

	tr = 0;
	rv = 0;
	done = 0;
	ptr = buf;
	set_socket_timer(sock, secs);
	while ((!done) && (tr < size)) {
		our_fd.fd = sock;
		our_fd.events = POLLOUT;
		count = poll(&our_fd, 1, 750);	/* 3/4 sec */
		if (count > 0) {
			if (our_fd.revents & POLLOUT) {
				nr = write( sock, ptr, size-tr );
				//printf("wrote %d bytes of %d/%d. Total written so far: %d\n", nr, size-tr, size, tr+nr);
				ptr += nr;
				tr += nr;
				rv = tr;
				if (nr < 0) {
					if (errno != EAGAIN) {
						//int my_errno=errno;
						//printf("socket write error: writecount: %d, errno: %d, %s\n", nr, my_errno, strerror(my_errno));
						/* some other error happened.
						 * Likely the 12 sec timer went off, and closed the socket.
						 * this will end up cancelling the write with an errno(9) (Bad file descriptor) error.
						 * This, actually, shouldn't happen, at least not very often.
						 */
						rv = -1;
						done=1;
					}
				}
			}
			else {
				//int my_errno=errno;
				//printf("poll error: errno: %d, %s\n", my_errno, strerror(my_errno));
				/* some other error happened.
				 * Likely the 12 sec timer went off, and closed the socket.
				 * this will end up cancelling the write with an errno(9) (Bad file descriptor) error.
				 * This, actually, shouldn't happen, at least not very often.
				 */
				rv = -1;
				done = 1;
			}
		}
		if (count < 0) {
			//int my_errno=errno;
			//printf("poll error: errno: %d, %s\n", my_errno, strerror(my_errno));
			/* some other error happened.
			 * Likely the 12 sec timer went off, and closed the socket.
			 * this will end up cancelling the write with an errno(9) (Bad file descriptor) error.
			 * This, actually, shouldn't happen, at least not very often.
			 */
			rv = -1;
			done = 1;
		}
		process_gtk_events();			  
	}

	set_socket_timer(sock, -1);
	return(rv);
}


/* fetch a URL into a predefined buffer */
int fetch_url( char *image_url, char *buf, int max_url_fetch_size, char *url_post_data, char *cookie ) {
	int sock = -1;
	struct sockaddr_in sa;
	struct hostent *hinfo;
	char url[4000];
	int captcha;
	char tmp[512];
	char *ptr;
	int tr = 0;
	char host[56] = "";

	if ( capture_fp ) {	
		fprintf(capture_fp,"\n[%s] FETCH URL: URL: %s, Cookie: %s\n",
			gyach_timestamp(), image_url, cookie?cookie:"None");
		fflush( capture_fp );
	}

	if ( strncmp( image_url, "http://", 7 )) {
		if ( strncmp( image_url, "scnt://", 7 )) {return( 0 ); }
	}

	buf[0] = '\0';

	strncpy( host, image_url + 7, 54 );
	host[54] = '\0';
	ptr = strchr( host, '/' );
	*ptr = '\0';

	check_proxy_config();

	if ( use_proxy ) {
		ptr = image_url;
		hinfo = gethostbyname( proxy_host );
	}
	else {
		ptr = strchr( image_url + 7, '/' );
		hinfo = gethostbyname( host );
	}

	if ( ! hinfo || ( hinfo->h_addrtype != AF_INET )) {
		if (use_proxy)  { /* added: PhrozenSmoke */
			snprintf(tmp, 150, "%s:\n%s", _("Could not connect to server"), proxy_host );
			show_ok_dialog(tmp);
		}
		else {
			snprintf(tmp, 150, "%s:\n%s", _("Could not connect to server"), host );
			show_ok_dialog(tmp);
		}
		return( 0 );
	}

	memset( &sa, 0, sizeof(sa));
	memmove((void*)&sa.sin_addr.s_addr, hinfo->h_addr, hinfo->h_length );

	sa.sin_family = AF_INET;

	if ( use_proxy ) {
		sa.sin_port = htons( proxy_port );
	}
	else {
		sa.sin_port = htons( 80 );
	}

	if (( sock = socket( AF_INET, SOCK_STREAM, 6 )) == -1 ) {
		if (use_proxy)  { /* added: PhrozenSmoke */
			snprintf(tmp,150,"%s:\n%s", _("Could not connect to server"), proxy_host );
			show_ok_dialog(tmp);
		}
		else {
			snprintf(tmp, 150,"%s:\n%s", _("Could not connect to server"), host );
			show_ok_dialog(tmp);
		}

		/* if ( DBG_LEVEL > 10 ) {
			printf( "error in socket()\n" );
		} */ 
		return( 0 );
	}
	else {
		set_socket_timer(sock, 8);
		if ( connect( sock, (struct sockaddr*)&sa, sizeof(sa)) == -1 ) {
			if (use_proxy)  { /* added: PhrozenSmoke */
				snprintf(tmp,150, "%s:\n%s", _("Could not connect to server"), proxy_host );
				show_ok_dialog(tmp);
			}
			else {
				snprintf(tmp,150, "%s:\n%s", _("Could not connect to server"), host );
				show_ok_dialog(tmp);
			}

			if ( DBG_LEVEL > 10 ) {
				printf( "error in connect()\n" );
			}

			close(sock);
			return( 0 );
		}
		set_socket_timer(sock, -1);
	}

	fcntl(sock, F_SETFL, (long)O_NONBLOCK);

	snprintf( url, 940,
		"%s %s HTTP/%s\r\n"
		"Accept: application/xml,application/xhtml+xml,text/html,text/plain,*/*\r\n"
		"Accept: text/plain\r\n"
		/* "User-Agent: Gyach/%s\r\n" */     /* changed: PhrozenSmoke */
		"User-Agent: %s\r\n"      /* changed: PhrozenSmoke */
		"Host: %s\r\n",
		url_post_data?"POST":"GET",
		ptr, 
		url_post_data?"1.1":"1.0",
		GYACH_USER_AGENT, host );     /* changed: PhrozenSmoke */

	if (strstr(image_url,"/share/get") || strstr(image_url,"/share/put") ) { /* photos imv */ 
		strncat(url, "x-flash-version: 7,0,19,0\r\n", 28);
		if (strstr(image_url,"/share/put")) {
			strncat(url, "Content-Type: application/x-www-form-urlencoded\r\n", 50);
		}
	}

	write_sock(sock, url, strlen(url), 8);

	if ( capture_fp ) {	
		fprintf(capture_fp,"\n[%s] FETCH URL: URL: %s, Sent Data Request: %s\n", gyach_timestamp(), image_url, url);
		fflush( capture_fp );
	}

	*url = 0;	  /* dont remove */
	captcha=0;
	if ( cookie ) {
		if (!strncmp(cookie, "Referer: ", 9)) {
			captcha=1;
		}
		else {
			strcat( url, "Cookie: " );
		}
		if (strstr(host, "ab.login.yahoo.com")) {
			/* reactivation URLs */ 
			snprintf(url, 1012, "%s",  "Cookie: B=9a4k50l00fmia&b=2; Q=q1=AACAAAAAAAAAbw--&q2=QJMimQ--; F=a=.Z6jMDgsvaBtGShSqwPBTq0Ky1SSv3GwNnlt3BTHmMAZ2FO0YmBtuOWyfWKR&b=B0ZL; LYC=l_v=0&l_lv=7&l_s=zwz03zv2v1rzu5wv11z4z5xu34xuty4w&l_lc=0_0_32_0_-1&l_um=0_1_1_0_0; U=mt=CkOmvJ2MhYs818jJ_hTEskZoqphBfV.t2yWA&ux=0XuyAB&un=4ruau026ct429; PROMO=sessionID=; C=mg=1");    

		}
		else {
			strncat( url, cookie, 3500 );
		}
		strcat( url, "\r\n" );
	}


	if (! url_post_data) { strcat( url, "\r\n" );	}

	//printf("URL STUFF: %s",url);  fflush(stdout);

	write_sock(sock, url, strlen(url), 8);

	if ( capture_fp ) {	
		fprintf(capture_fp,"\n[%s] FETCH-URL COOKIES: %s\n", gyach_timestamp(), url);
		fflush( capture_fp );
	}

	if (url_post_data) {
		if (captcha) {
			sprintf(url, "Content-Type: application/x-www-form-urlencoded\r\n");
			write_sock(sock, url, strlen(url), 10);
		}
		sprintf(url, "Content-Length: %d\r\n\r\n", strlen(url_post_data));
		write_sock(sock, url, strlen(url), 10);
		write_sock(sock, url_post_data, strlen(url_post_data), 10);
		if ( capture_fp ) {	
			fprintf(capture_fp,"\n[%s] FETCH-URL POST: %s\n%s\n", gyach_timestamp(), url, url_post_data);
			fflush( capture_fp );
		}
	}

	if (max_url_fetch_size<1) {
		close( sock );
		return 0;
	}

	tr = read_sock(sock, buf, max_url_fetch_size-1, 12);
	buf[tr > 0 ? tr : 0] = 0;

	close(sock);

	/* search for end of html header
	 * no header, then no results
	 */
	ptr = strstr( buf, "\r\n\r\n" );
	if ( (tr<1) || (ptr == 0) )  {
		*buf = 0;
		//if (tr < 1) printf("FETCH_URL ERROR: received transfer length < 1\n");
		//if (ptr == 0) printf("FETCH_URL: received string, no terminator!: %s\n", buf);
		return 0;
	}

	ptr += 4;

	//char c=*ptr;*ptr=0; printf("header:\n%s\n", buf); *ptr=c; printf("body:\n%s\n", ptr);

	tr -= (ptr - buf);
	memcpy( buf, ptr, tr+1 );

	if ( capture_fp ) {	
		fprintf(capture_fp,"\n[%s] FETCH URL-Retrieved Data: URL: %s, Got Data Size: %d, Got Data: %s\n",
			gyach_timestamp(), image_url, tr, buf);
		fflush( capture_fp );
	}

	return( tr );
}


void subst_escs( char *str ) {
	char tmp[1536];
	char *from = tmp;
	char *to = str;

	// DBG( 21, "subst_escs( '%s' )\n", str );

	if ( ! strchr( str, '\\' ))
		return;

	strncpy( tmp, str, 1534 );

	while( *from ) {
		if (( *from == '\\' ) &&
			( *(from+1) == '\\' ) &&
			( *(from+2) == 'n' )) {
			*(to++) = '\\';
			*(to++) = 'n';
			from += 3;
		}
		else if (( *from == '\\' ) &&
			( *(from+1) == 'n' )) {
			*(to++) = '\n';
			from += 2;
		}
		else if (( *from == '\\' ) &&
			( *(from+1) == 't' )) {
			*(to++) = '\t';
			from += 2;
		}
		else {
			*(to++) = *(from++);
		}
	}
	*to = '\0';
}

char *filter_text( char *txt ) {
	static char buffilt[513] = "";
	char data[513];
	char *ptr;
	char new_cmd[768];
	FILE *fp;

	// DBG( 11, "filter_text( '%s' )\n", txt );

	/* zero out buffilt every time */
	buffilt[0] = '\0';

	if (!filter_command ) {
		strncpy( buffilt, txt , 511);
		return( buffilt );
	}

	/* sanity check to make sure our echo doesn't hose up */
	ptr = txt;
	while( *ptr ) {
		if ( *ptr == '"' )
			*ptr = '\'';
		ptr++;
	}
	snprintf( new_cmd, 766, "echo \"%s\" | %s", txt, filter_command );

	fp = popen( new_cmd, "r" );

	if ( fp ) {
		while(( strlen( buffilt ) < 512 ) &&
			  ( fgets( data, 512-strlen(buffilt), fp ))) {
			if (( strlen( buffilt ) + strlen( data )) < 512 )
				strcat( buffilt, data );
		}
		pclose( fp );

		ptr = buffilt + strlen( buffilt );
		ptr--;
		while(( *ptr == '\n' ) || ( *ptr == '\r' )) {
			*ptr = '\0';
			ptr--;
		}

		if ( strlen( buffilt ) == 511 ) {
			strcpy( buffilt+507, "...." );
		}
	}
	else {
		strncpy( buffilt, txt, 511 );
	}

	return( buffilt );
}

char *replace_args( char *str, char *args ) {
	static char result[1025] = "";
	char zargs[1025];
	char tmp[1025];
	char search[4];
	char *arg;
	char *ptr;
	char *end;
	char *ptr2;
	int x;

	// DBG( 11, "replace_args( '%s', '%s' )\n", str, args );

	strncpy( result, str , 1024);
	strncpy( zargs, args, 1024 );

	if (( ! strchr( result, '$' )) &&
		( ! strstr( result, "%s" ))) {
		return( result );
	}

	arg = zargs;
	for( x = 0; x < 10; x++ ) {
		/* find next arg */
		arg = skip_whitespace( arg );
		end=strchr(arg,'\0');
		/* end = find_whitespace( arg );  */
		*end = '\0';

		snprintf( search, 3, "$%d", x );
		ptr2 = result;
		while(( ptr = strstr( ptr2, search )) != NULL ) {
			/* skip if escaped */
			if (( ptr != result ) &&
				( *(ptr-1) == '\\' )) {
				ptr2++;
				continue;
			}

			strncpy( tmp, ptr + 2, 1022 );

			/* append arg if we have room */
			if (( ptr - result + strlen( arg ) + 1 ) < sizeof( result )) 
				strcpy( ptr, arg );

			/* append rest of string after arg if we have room */
			strncat( ptr, tmp, sizeof( result ) - strlen( result ));
			ptr2 = ptr;
		}

		arg = end + 1;
	}

	ptr2 = result;
	while(( ptr = strstr( ptr2, "$*" )) != NULL ) {
		/* skip if escaped */
		if (( ptr != result ) &&
			( *(ptr-1) == '\\' )) {
			ptr2++;
			continue;
		}

		strncpy( tmp, ptr + 2, 1024 );

		/* append arg if we have room */
		if (( ptr - result + strlen( args ) + 1 ) < sizeof( result )) 
			strcpy( ptr, args );

		/* append rest of string after arg if we have room */
		strncat( ptr, tmp, sizeof( result ) - strlen( result ));
		ptr2 = ptr;
	}

	ptr2 = result;
	while(( ptr = strstr( ptr2, "%s" )) != NULL ) {
		/* skip if escaped */
		if (( ptr != result ) &&
			( *(ptr-1) == '\\' )) {
			ptr2++;
			continue;
		}

		strncpy( tmp, ptr + 2 , 1024);

		/* append arg if we have room */
		if (( ptr - result + strlen( args ) + 1 ) < sizeof( result )) 
			strcpy( ptr, args );

		/* append rest of string after arg if we have room */
		strncat( ptr, tmp, sizeof( result ) - strlen( result ));
		ptr2 = ptr;
	}

	return( result );
}



void *fetch_avatar_all( void *arg, int is_yavatar, int ava_size, int bimage, char *burl ) {
	int allocsize=7168;
	char *buf=NULL;   /* avatars are usually under 2-3kb */	
	char *avatar = (char *)arg;
	char filename[192];
	char dirbuf[192];
	char url[240];
	int length=0;
	FILE *fp;
	struct stat sbuf;
	
	if (bimage) { /* a buddy image */
		char av_clean[40]="";
		snprintf( url, 190, "%s", burl );  /* will be a full URL */ 
		snprintf(av_clean,35, "%s", avatar);
		clean_bimage_name(av_clean);
		snprintf( dirbuf, 190, "%s/bimages", GYACH_CFG_DIR );
		snprintf( filename, 190, "%s/bimages/bimage-%s.png", GYACH_CFG_DIR, av_clean);
		allocsize=48672;
	}
	else if (is_yavatar) {
		/* Yahoo's new avatars for buddy lists, etc */
		if (ava_size>3) {return( NULL );} 
		snprintf( dirbuf, 190, "%s/yavatars", GYACH_CFG_DIR );
		if (ava_size==3) {
			snprintf( url, 238, "http://img.avatars.yahoo.com/users/%s.full.swf?src=ymsgr&intl=us&os=win&ver=%s", avatar, 
				version_emulation );
			snprintf( filename, 254, "%s/yavatars/%s.full.swf", GYACH_CFG_DIR, avatar);
			allocsize=56864;
			}
		if (ava_size==2) {
			snprintf( url, 238, "http://img.avatars.yahoo.com/users/%s.large.%s?src=ymsgr&intl=us&os=win&ver=%s", avatar, 
				avatar_filetype, version_emulation );
			snprintf( filename, 190, "%s/yavatars/%s.large.%s", GYACH_CFG_DIR, avatar, 
				avatar_filetype );
			allocsize=48672;
			}
		if (ava_size==1) {
			snprintf( url, 238, "http://img.avatars.yahoo.com/users/%s.medium.%s?src=ymsgr&intl=us&os=win&ver=%s", avatar, avatar_filetype, version_emulation );
			snprintf( filename, 190, "%s/yavatars/%s.medium.%s", GYACH_CFG_DIR, avatar, 
				avatar_filetype );
			allocsize=14236;
			}
		if (ava_size==0) {
			snprintf( url, 238, "http://img.avatars.yahoo.com/users/%s.small.%s?src=ymsgr&intl=us&os=win&ver=%s", avatar, 
				avatar_filetype, version_emulation );
			snprintf( filename, 190, "%s/yavatars/%s.small.%s", GYACH_CFG_DIR, avatar, 
				avatar_filetype );
			allocsize=6144;
		}
	}
	else {
		/* Cheeta Chat avatars */
		char tmp_avatar[72] = "";
		strncpy( tmp_avatar, avatar, 70 );
		lower_str( tmp_avatar );		
		snprintf( filename, 190,  "%s/avatars/%s.jpg", GYACH_CFG_DIR, tmp_avatar );
		/* also avatars.cheetachat.com  - same IP address */
		snprintf( url, 190, "http://avserv.cheetachat.com/avatar/%s.jpg", avatar );
		snprintf( dirbuf, 190, "%s/avatars", GYACH_CFG_DIR );	
	}

	free( avatar );
	
	/* Make any needed directories */ 
	if ( stat( dirbuf, &sbuf )) {mkdir( dirbuf, 0700 );  }

	buf=malloc(allocsize);
	if (!buf) {return( NULL );}
	sprintf(buf, "%s", "");
	// printf("alloced size: %d\n", allocsize); fflush(stdout);
	length = fetch_url( url, buf, allocsize-1, NULL, NULL );

	// printf("url length: %d\n", length); fflush(stdout);

	if ( length ) {
		if ( strstr( buf, "document has moved" )) {
			char *start, *end;

			if (is_yavatar) {free(buf); return( NULL );}
			start = strstr( buf, "com/avatar/" );
			if (start) {
				start += 11;
				end = strchr( start, '.' );
				if (end) {
					*end = '\0';
					free(buf);
					return fetch_avatar((void *)strdup(start));
				}
			}
		}
		else if ( strstr( buf, "was not found" )) {
			free(buf);
			return( NULL );
		}
		else {
			fp = fopen( filename, "w" );
			if ( fp ) {
				fwrite( buf, length, 1, fp );
				fclose( fp );
			}
		}
	}

	free(buf);
	return( NULL );
}


void *fetch_avatar( gpointer arg ) {
	return fetch_avatar_all((void *)arg, 0, 0, 0, NULL);
}

void *fetch_yavatar( void *arg, int ava_size, char *burl ) {
	if ( (! show_yavatars) && (ava_size == 0) ) {return 0; }
	if ( (! show_bimages) && (ava_size == 4) ) {return( NULL );}

	if (ava_size != 4) {  /* avatar */
				// printf("dl-2\n"); fflush(stdout);
		return fetch_avatar_all(arg, 1, ava_size, 0, NULL);
	}
	return fetch_avatar_all(arg, 0, 0, 1, burl);  /* buddy image */
}


int download_yavatar(char *avatar, int ava_size, char *burl) {
	char filename[192];
	struct stat sbuf;

	if ( (! show_yavatars) && (ava_size == 0) ) {return 0; }
	if ( (! show_bimages) && (ava_size == 4) )  {return 0; }
	if (!avatar) {return 0;}

	if (ava_size==2) {
		snprintf( filename, 190, "%s/yavatars/%s.large.%s", GYACH_CFG_DIR, avatar, 
			avatar_filetype );	
	} 
	else if (ava_size==3) {  /* shockwave animation */
		snprintf( filename, 190, "%s/yavatars/%s.full.swf", GYACH_CFG_DIR, avatar );	
	} 
	else if (ava_size==4) {  /* buddy image */
		snprintf( filename, 190, "%s/bimages/bimage-%s.png", GYACH_CFG_DIR, avatar );	
	} 
	else if (ava_size==1) {
		/* around 3-5 kb */
		snprintf( filename, 190, "%s/yavatars/%s.medium.%s", GYACH_CFG_DIR, avatar, 
			avatar_filetype );	
	} 
	else  {
		snprintf( filename, 190, "%s/yavatars/%s.small.%s", GYACH_CFG_DIR, avatar, 
			avatar_filetype );	
	} 

	if ( stat( filename, &sbuf ) || (ava_size==4) ) {
		/* doesn't exist, so download for displaying */
				// printf("dl-1\n"); fflush(stdout);
		fetch_yavatar(strdup(avatar), ava_size, burl);	
	}
	else {return 1;}

	if ( stat( filename, &sbuf )) {
		/* couldnt be downloaded */
		return 0;	
	}
	else {return 1;}
	return 0;
}

int bimage_exists(char *ava_key) {
	char filename[192];
	struct stat sbuf;
	if (!ava_key) {return 0;}
	snprintf( filename, 190, "%s/bimages/bimage-%s.png", GYACH_CFG_DIR, ava_key );
	if (  stat( filename, &sbuf )) {return 0;}
return 1;
}

void clean_bimage_name(char *bkey) {
	int stopper=0;
	if (!bkey) {return;}
	while (stopper< (strlen(bkey)-1) ) {
		if (bkey[stopper]=='\0') {break;}
		if (! isdigit(bkey[stopper]) ) {bkey[stopper]='B';}
		stopper++;
	}
}

void delete_yavatars(char *ava_key) {
	char filename[192];
	struct stat sbuf;
	if (!ava_key) {return;}
	snprintf( filename, 190, "%s/yavatars/%s.small.%s", GYACH_CFG_DIR, ava_key, 
		avatar_filetype);
	if ( ! stat( filename, &sbuf )) {unlink(filename);}
	snprintf( filename, 190, "%s/yavatars/%s.medium.%s", GYACH_CFG_DIR, ava_key, 
		avatar_filetype);
	if ( ! stat( filename, &sbuf )) {unlink(filename);}
	snprintf( filename, 190, "%s/yavatars/%s.large.%s", GYACH_CFG_DIR, ava_key, 
		avatar_filetype);
	if ( ! stat( filename, &sbuf )) {unlink(filename);}
	snprintf( filename, 190, "%s/yavatars/%s.full.swf", GYACH_CFG_DIR, ava_key );
	if ( ! stat( filename, &sbuf )) {unlink(filename);}
}

void delete_all_yavatars() {
	char filename[192];
	snprintf( filename, 190, "rm -f %s/yavatars/*.small.%s", GYACH_CFG_DIR, 
		avatar_filetype);
	my_system(filename);
	snprintf( filename, 190, "rm -f %s/yavatars/*.medium.%s", GYACH_CFG_DIR,
		avatar_filetype);
	my_system(filename);
	snprintf( filename, 190, "rm -f %s/yavatars/*.large.%s", GYACH_CFG_DIR, 
		avatar_filetype);
	my_system(filename);
	snprintf( filename, 190, "rm -f %s/yavatars/*.full.swf", GYACH_CFG_DIR);
	my_system(filename);
}

void delete_all_bimages() {
	char filename[192];
	snprintf( filename, 190, "rm -f %s/bimages/bimage-*.png", GYACH_CFG_DIR );
	my_system(filename);
}

void display_emotes_pane() {
	if (user_list) {
		if (disable_emotes) {
			gtk_widget_hide_all(emotes_pane);
		}
		else {
			gtk_widget_show_all(emotes_pane);
		}
	}
}

void display_chatroom_pane() {
	if (user_list) {
		gtk_widget_show_all(chatroom_user_pane);
		gtk_widget_show_all(chatroom_input_pane);
		display_emotes_pane();
		gtk_widget_set_sensitive(add_to_favorites_menuitem, in_a_chat ? TRUE : FALSE);
		gtk_widget_set_sensitive(conf_invite1, TRUE);
		gtk_widget_set_sensitive(conf_invite2, TRUE);
		gtk_widget_set_sensitive(conf_invite3, TRUE);
		gtk_widget_set_sensitive(conf_invite4, TRUE);
		gtk_widget_set_sensitive(conf_leave1,  TRUE);
		gtk_widget_set_sensitive(conf_leave2,  TRUE);

		if (conf_invite6) gtk_widget_set_sensitive(conf_invite6, TRUE);
		if (conf_invite7) gtk_widget_set_sensitive(conf_invite7, TRUE);
	}
	else {
		gtk_widget_hide_all(chatroom_user_pane);
		gtk_widget_hide_all(chatroom_input_pane);
		gtk_widget_set_sensitive(add_to_favorites_menuitem, FALSE);
		gtk_widget_set_sensitive(conf_invite1, FALSE);
		gtk_widget_set_sensitive(conf_invite2, FALSE);
		gtk_widget_set_sensitive(conf_invite3, FALSE);
		gtk_widget_set_sensitive(conf_invite4, FALSE);
		if (already_left_room) {
			gtk_widget_set_sensitive(conf_leave1, FALSE);
			gtk_widget_set_sensitive(conf_leave2, FALSE);
		}
		if (conf_invite6) gtk_widget_set_sensitive(conf_invite6, FALSE);
		if (conf_invite7) gtk_widget_set_sensitive(conf_invite7, FALSE);
	}
	gtk_widget_show_all(ct_widget());
	process_gtk_events();
	ct_scroll_to_bottom();
}

void display_avatar( char *user, char *avatar ) {
	char filename[192];
	char ava_part[72];
	struct stat sbuf;
	GThread *av_thread;

	if ( ! strcmp( avatar, "random" )) {return;	}

	/* Changed, PhrozenSmoke: The orignal author was lowering 
	the whole filename, which could cause problems if 'GYACH_CFG_DIR' was not
	all lowercase, i.e. the avatar not being found and repeated 'fetching' of
	the avatar.  */

	strncpy(ava_part, avatar,70);
	lower_str( ava_part );
	snprintf( filename, 190, "%s/avatars/%s.jpg", GYACH_CFG_DIR, ava_part );	

	if ( stat( filename, &sbuf )) {
		/* doesn't exist, so download for displaying later */
		av_thread = g_thread_create(fetch_avatar, (gpointer)strdup(avatar), FALSE, NULL );
	}
	else {
		/* exists, so display */
		if ( ct_can_do_pixmaps()) {
			ct_append_pixmap( filename,NULL );
		} 
	}
}


void play_sound(char *sound ) {
	char cmd[384];

	snprintf(cmd, 380, "wavplay %s > /dev/null 2>&1", sound);

	play_audible_command(strdup(cmd));
	free(sound);
}


gint gstrcmp( gpointer a, gpointer b ) {
	if ( a && b ) {
		// DBG( 31, "gstrcmp( '%s', '%s' )\n", (char *)a, (char *)b );
	}
	else if ( a ) {
		// DBG( 31, "gstrcmp( '%s', NULL )\n", (char *)a );
	}
	else if ( b ) {
		// DBG( 31, "gstrcmp( NULL, '%s' )\n", (char *)b );
	}
	else {
		// DBG( 31, "gstrcmp( NULL, NULL )\n" );
	}
	fflush( stderr );

	if (( ! a ) &&
		( ! b )) {
		// DBG( 32, "RETURN gstrcmp() == 0\n" );
		return( 0 );
	}

	if ( ! a ) {
		// DBG( 32, "RETURN gstrcmp() == -1\n" );
		return( -1 );
	}

	if ( ! b ) {
		// DBG( 32, "RETURN gstrcmp() == 1\n" );
		return( 1 );
	}

	// DBG( 32, "RETURN gstrcmp() == %d\n", strcasecmp( (char *)a, (char *)b ));

	return( strcasecmp( (char *)a, (char *)b ));
}


GList *gyach_g_list_free( GList *list ) {
	GList *node;

	if ( ! list )
		return( NULL );

	node = g_list_first( list );
	while( node ) {
		free( node->data );
		node = g_list_next( node );
	}
	g_list_free( list );

	return( NULL );
}

GList *gyach_g_list_copy( GList *list ) {
	GList *result;
	GList *node;

	result = g_list_copy( list );
	node = g_list_first( result );
	while( node ) {
		node->data = strdup( node->data );
		node = g_list_next( node );
	}

	return( result );
}

GList *gyach_g_list_merge( GList *main, GList *sub ) {
	GList *this_item;
	GList *found_item;

	this_item = sub;
	while( this_item ) {
		found_item = g_list_find_custom( main, this_item->data,
			(GCompareFunc)gstrcmp );

		if ( ! found_item ) {
			main = g_list_append( main, strdup( this_item->data ));
		}

		this_item = g_list_next( this_item );
	}
	gyach_g_list_free( sub );
	return( main );
}


/* This was moved in from the no-longer-used support.c module */

GtkWidget *lookup_widget (GtkWidget  *widget, const gchar *widget_name)
{
  GtkWidget *parent, *found_widget;

  for (;;)
    {
      found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
						       widget_name);
      if (found_widget) {
	return(found_widget);
      }
      
      if (GTK_IS_MENU (widget))
        parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
      else
        parent = widget->parent;
      if (parent == NULL)
        break;
      widget = parent;
    }

  g_warning ("Widget not found: %s", widget_name);
  return(NULL);
}


