/***************************************************************************** * users.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) 2000-2002 Chris Pinkham * Released under the terms of the GPL. * *NO WARRANTY* * * cpinkham@corp.infi.net, cpinkham@bc2va.org * http://www4.infi.net/~cpinkham/gyach/ *****************************************************************************/ #include "config.h" #include #include #include #include #include #include #ifdef USE_GDK_PIXBUF #include #endif #include "gyach.h" #include "commands.h" #include "friends.h" #include "gyach_int.h" #include "ignore.h" #include "images.h" #include "interface.h" #include "main.h" #include "support.h" #include "users.h" #include "util.h" GList *user_list = NULL; GList *left_list = NULL; GList *full_list = NULL; GHashTable *last_comments = NULL; GtkWidget * chat_users; GtkWidget * chat_user_menu; char *user_selected = NULL; char *follow_user = NULL; int show_html = 1; int show_statuses = 1; int show_enters = 1; int show_blended_colors = 1; int show_colors = 1; int show_fonts = 0; int show_avatars = 0; char *send_avatar = NULL; int show_emoticons = 0; GtkWidget * pm_window; GtkWidget * pm_entry; GtkWidget * pm_user; GList *pm_list = NULL; int pm_in_sep_windows = 1; int pm_from_friends = 1; int pm_from_users = 1; int pm_from_all = 1; int auto_raise_pm = 1; int auto_reply_when_away = 0; int pm_brings_back = 0; GtkWidget * profile_window = NULL; char *prof_text = NULL; char *prof_pic = NULL; int find_user_row( char *user ) { char tmp_user[513]; char tmp_list[513]; char *listitem[1]; int i; int r; DBG( 21, "find_user_row( '%s' )\n", user ); if ( strlen( user ) > sizeof( tmp_user )) return( -1 ); my_strncpy( tmp_user, user, sizeof(tmp_user)); lower_str( tmp_user ); r = -1; for( i = 0 ; i < GTK_CLIST(chat_users)->rows && r == -1; i++ ) { gtk_clist_get_text( GTK_CLIST(chat_users), i, 1, listitem ); my_strncpy( tmp_list, listitem[0], sizeof(tmp_list)); lower_str( tmp_list ); if ( ! strcmp( tmp_list, tmp_user )) r = i; } DBG( 22, "RETURN find_user_row() == %d\n", r ); return( r ); } void user_add( char *user ) { char tmp_user[129]; if ( ! user ) { DBG( 11, "user_add( NULL )\n" ); return; } else { DBG( 11, "user_add( '%s' )\n", user ); } my_strncpy( tmp_user, user, sizeof(tmp_user)); lower_str( tmp_user ); if ( g_list_find_custom( user_list, tmp_user, (GCompareFunc)gstrcmp )) return; user_list = g_list_prepend( user_list, strdup( tmp_user )); build_tab_complete_list(); } void user_remove( char *user ) { GList *this_user; char tmp_user[129]; char *ptr; if ( ! user ) { DBG( 11, "user_remove( NULL )\n" ); return; } else { DBG( 11, "user_remove( '%s' )\n", user ); } my_strncpy( tmp_user, user, sizeof(tmp_user)); lower_str( tmp_user ); this_user = g_list_find_custom( user_list, tmp_user, (GCompareFunc)gstrcmp ); if ( this_user ) { ptr = this_user->data; user_list = g_list_remove( user_list, ptr ); left_list = g_list_append( left_list, ptr ); /* keep the list down to last 10 users in room */ if ( g_list_nth( left_list, 10 )) { /* take the head off */ this_user = g_list_first( left_list ); ptr = this_user->data; left_list = g_list_remove( left_list, ptr ); free( ptr ); } } build_tab_complete_list(); } void chatter_list_populate( char *list, int clear_first ) { char *user; char *end; int last = 0; int row; int users = 0; gchar *listitem[3]; GtkWidget *tmp_widget = NULL; GtkStyle *user_style = NULL; #ifdef SHOW_STATUS_PIXMAPS GdkPixmap *st_pixmap = NULL; GdkBitmap *st_mask = NULL; #else char status[5] = ""; #endif #ifdef CASE_INSENSITIVE_USER_LIST char *temp_ptr; #endif gtk_clist_freeze(GTK_CLIST(chat_users)); if ( clear_first ) { gtk_clist_clear(GTK_CLIST(chat_users)); user_list = gyach_g_list_free( user_list ); full_list = gyach_g_list_free( full_list ); left_list = gyach_g_list_free( left_list ); tab_user = NULL; } gtk_clist_set_column_width( GTK_CLIST(chat_users), 0, 20 ); gtk_clist_set_row_height( GTK_CLIST(chat_users), 0 ); tmp_widget = lookup_widget( chat_window, "users" ); user_style = gtk_widget_get_style( tmp_widget ); user = list; while( user ) { end = strchr( user, ',' ); if ( end ) { *end = '\0'; } else { last = 1; } listitem[0] = user; listitem[1] = user; listitem[2] = user; #ifdef CASE_INSENSITIVE_USER_LIST tmp_ptr = user; while( *tmp_ptr ) { *tmp_ptr = tolower( *tmp_ptr ); tmp_ptr++; } #endif #ifdef SHOW_STATUS_PIXMAPS if ( ignore_check( user )) { st_pixmap = gdk_pixmap_create_from_xpm_d( tmp_widget->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], (gchar **)pixmap_status_ignore ); } else { if ( mute_check( user )) { st_pixmap = gdk_pixmap_create_from_xpm_d( tmp_widget->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], (gchar **)pixmap_status_mute ); } else { st_pixmap = gdk_pixmap_create_from_xpm_d( tmp_widget->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], (gchar **)pixmap_status_here ); } } #else if ( ignore_check( user )) { strcpy( status, "IG" ); } else { if ( mute_check( user )) { strcpy( status, "MU" ); } else { strcpy( status, "" ); } } #endif /* fake their last comment so we don't ignore if they happen to */ /* post a url right after we come into the room and it ends up */ /* being the first post we see but not their real first post. */ set_last_comment( user, "I Entered Room" ); row = find_user_row( user ); if ( row < 0 ) { users++; user_add( user ); row = gtk_clist_insert(GTK_CLIST(chat_users), 0, listitem ); gtk_clist_set_text(GTK_CLIST(chat_users), row, 1, user ); gtk_clist_set_text(GTK_CLIST(chat_users), row, 2, "000:" ); #ifdef SHOW_STATUS_PIXMAPS gtk_clist_set_pixmap(GTK_CLIST(chat_users), row, 0, st_pixmap, st_mask ); gdk_pixmap_unref( st_pixmap ); gdk_bitmap_unref( st_mask ); #else gtk_clist_set_text(GTK_CLIST(chat_users), row, 0, status ); #endif } if ( last ) { user = NULL; } else { user = end + 1; } } gtk_clist_sort(GTK_CLIST(chat_users)); gtk_clist_thaw(GTK_CLIST(chat_users)); set_status_room_counts(); } void chatter_list_add( char *user ) { int row; int iggy; gchar *listitem[3]; GtkWidget *tmp_widget = NULL; GtkStyle *user_style = NULL; #ifdef SHOW_STATUS_PIXMAPS GdkPixmap *st_pixmap = NULL; GdkBitmap *st_mask = NULL; #else char status[5] = ""; #endif #ifdef CASE_INSENSITIVE_USER_LIST char *temp_ptr; #endif tmp_widget = lookup_widget( chat_window, "users" ); user_style = gtk_widget_get_style( tmp_widget ); row = find_user_row( user ); if ( row != -1 ) { /* user is already in our list */ return; } /* entering */ listitem[0] = user; listitem[1] = user; listitem[2] = user; #ifdef CASE_INSENSITIVE_USER_LIST ptr = user; while( *ptr ) { *ptr = tolower( *ptr ); ptr++; } #endif #ifdef SHOW_STATUS_PIXMAPS if (( iggy = ignore_check( user )) != 0 ) { st_pixmap = gdk_pixmap_create_from_xpm_d( tmp_widget->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], (gchar **)pixmap_status_ignore ); } else { if (( iggy = mute_check( user )) != 0 ) { st_pixmap = gdk_pixmap_create_from_xpm_d( tmp_widget->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], (gchar **)pixmap_status_mute ); } else { st_pixmap = gdk_pixmap_create_from_xpm_d( tmp_widget->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], (gchar **)pixmap_status_here ); } } #else if (( iggy = ignore_check( user )) != 0 ) { strcpy( status, "IG" ); } else { if (( iggy = mute_check( user )) != 0 ) { strcpy( status, "MU" ); } else { strcpy( status, "" ); } } #endif user_add( user ); gtk_clist_freeze(GTK_CLIST(chat_users)); row = gtk_clist_append(GTK_CLIST(chat_users), listitem ); gtk_clist_set_text(GTK_CLIST(chat_users), row, 1, user ); gtk_clist_set_text(GTK_CLIST(chat_users), row, 2, "000:" ); #ifdef SHOW_STATUS_PIXMAPS gtk_clist_set_pixmap(GTK_CLIST(chat_users), row, 0, st_pixmap, st_mask ); gdk_pixmap_unref( st_pixmap ); gdk_bitmap_unref( st_mask ); #else gtk_clist_set_text(GTK_CLIST(chat_users), row, 0, status ); #endif gtk_clist_sort(GTK_CLIST(chat_users)); gtk_clist_thaw(GTK_CLIST(chat_users)); set_status_room_counts(); } void chatter_list_remove( char *user ) { int row; char buf[256]; row = find_user_row( user ); if ( row >= 0 ) { user_remove( user ); gtk_clist_remove( GTK_CLIST(chat_users), row ); } if (( follow_user ) && ( ! strcmp( user, follow_user ))) { snprintf( buf, sizeof(buf), "/goto %s", follow_user ); try_command( buf ); } set_status_room_counts(); } void chatter_list_status( char *user, gchar **status_image, char *status ) { int row; #ifdef SHOW_STATUS_PIXMAPS GtkWidget *tmp_widget = NULL; GtkStyle *user_style = NULL; GdkPixmap *st_pixmap = NULL; GdkBitmap *st_mask = NULL; #endif row = find_user_row( user ); #ifdef SHOW_STATUS_PIXMAPS tmp_widget = lookup_widget( chat_window, "users" ); user_style = gtk_widget_get_style( tmp_widget ); st_pixmap = gdk_pixmap_create_from_xpm_d( tmp_widget->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], (gchar **)status_image ); gtk_clist_set_pixmap(GTK_CLIST(chat_users), row, 0, st_pixmap, st_mask ); gdk_pixmap_unref( st_pixmap ); gdk_bitmap_unref( st_mask ); #else gtk_clist_set_text(GTK_CLIST(chat_users), row, 0, status ); #endif } void display_profile() { #ifdef USE_GDK_PIXBUF GdkPixbuf *pixbuf; GdkPixbuf *spixbuf; int width; int height; #endif GdkPixmap *st_pixmap; GdkBitmap *st_mask; GtkStyle *user_style = NULL; static GtkStyle *profile_style = NULL; GtkWidget *tmp_widget; #ifdef USE_GTK2 char prof_font[25]; #endif DBG( 11, "display_profile()\n" ); if ( ! prof_text ) { prof_text = NULL; prof_pic = NULL; return; } if ( profile_window ) { gtk_widget_destroy( profile_window ); profile_window = NULL; } profile_window = create_profile_window(); #ifdef USE_GTK2 if ( ! profile_style ) { snprintf( prof_font, sizeof(prof_font), "Courier %d", font_size ); profile_style = gtk_style_new(); profile_style->font_desc = pango_font_description_from_string( prof_font ); if (!profile_style->font_desc) profile_style->font_desc = pango_font_description_from_string( "fixed" ); } #else if ( ! profile_style ) { profile_style = gtk_style_new(); profile_style->font = gdk_font_load( "-adobe-courier-medium-r-normal-*-*-140-*-*-m-*-iso8859-1"); if (!profile_style->font) profile_style->font = gdk_font_load( "fixed" ); } #endif tmp_widget = lookup_widget( profile_window, "profile_info" ); gtk_widget_set_style( tmp_widget, profile_style ); gtk_label_set_text( GTK_LABEL(tmp_widget), prof_text ); gtk_misc_set_alignment( GTK_MISC(tmp_widget), 0.0f, 0.0f ); prof_text = NULL; if ( prof_pic ) { gtk_widget_realize( profile_window ); tmp_widget = lookup_widget( profile_window, "user_picture" ); user_style = gtk_widget_get_style( profile_window ); if ( user_style ) { #ifdef USE_GDK_PIXBUF pixbuf = gdk_pixbuf_new_from_file( prof_pic ); width = gdk_pixbuf_get_width( pixbuf ); height = gdk_pixbuf_get_height( pixbuf ); if ( width < height ) { width = ( 1.0 * width / height ) * 200; height = 200; } else { height = ( 1.0 * height / width ) * 200; width = 200; } spixbuf = gdk_pixbuf_scale_simple( pixbuf, width, height, GDK_INTERP_BILINEAR ); gdk_pixbuf_render_pixmap_and_mask( spixbuf, &st_pixmap, &st_mask, 0 ); gdk_pixbuf_unref( spixbuf ); gdk_pixbuf_unref( pixbuf ); #else st_pixmap = gdk_pixmap_create_from_xpm( profile_window->window, &st_mask, &user_style->bg[GTK_STATE_NORMAL], prof_pic ); #endif gtk_pixmap_set( GTK_PIXMAP(tmp_widget), st_pixmap, st_mask ); if ( st_pixmap ) gdk_pixmap_unref( st_pixmap ); if ( st_mask ) gdk_bitmap_unref( st_mask ); } unlink( prof_pic ); prof_pic = NULL; } gtk_widget_show( profile_window ); } void find_field_line( char *str, char *search_str, char *result ) { char *ptr; char *end; char *cr; DBG( 21, "find_field_line( '%s', '%s', %p )\n", str, search_str, result ); ptr = strstr( str, search_str ); if ( ptr ) { ptr += strlen( search_str ); while(( *ptr != ' ' ) && ( ptr < ( str + strlen( str )))) ptr++; while(( *ptr == ' ' ) && ( ptr < ( str + strlen( str )))) ptr++; end = strchr( ptr, ' ' ); cr = strchr( ptr, '\n' ); if (( cr ) && ( cr < end )) { strncpy( result, ptr, cr - ptr ); result[cr - ptr] = '\0'; } else { strncpy( result, ptr, end - ptr ); result[end - ptr] = '\0'; } } } void find_field( char *str, char *search_str, char *result ) { char *ptr; char *end; char *colon; DBG( 21, "find_field( '%s', '%s', %p )\n", str, search_str, result ); ptr = strstr( str, search_str ); if ( ptr ) { ptr += strlen( search_str ); while(( *ptr != '\n' ) && ( ptr < ( str + strlen( str )))) ptr++; while(( *ptr == '\n' ) && ( ptr < ( str + strlen( str )))) ptr++; end = strchr( ptr, '\n' ); colon = strchr( ptr, ':' ); if (( colon ) && ( colon < end )) { strcpy( result, "" ); } else { strncpy( result, ptr, end - ptr ); result[end - ptr] = '\0'; } } } char *download_image( char *image_url ) { static char tmp_filename[1025]; int sock; struct sockaddr_in sa; struct hostent *hinfo; char url[1025]; char result[65535]; char tmp[65535]; char *ptr; int nr = 0, tr = 0; int ifp; char host[75] = ""; DBG( 11, "download_image( '%s' )\n", image_url ); if ( strncmp( image_url, "http://", 7 )) return ""; strcpy( tmp_filename, "/tmp/gyach.XXXXXX" ); strncpy( host, image_url + 7, 74 ); host[74] = '\0'; ptr = strchr( host, '/' ); *ptr = '\0'; ptr = strchr( image_url + 7, '/' ); hinfo = gethostbyname( host ); if ( ! hinfo || ( hinfo->h_addrtype != AF_INET )) { /* fixme, show an error box */ return ""; } memset( &sa, 0, sizeof(sa)); memmove((void*)&sa.sin_addr.s_addr, hinfo->h_addr, hinfo->h_length ); sa.sin_family = AF_INET; sa.sin_port = htons( 80 ); if (( sock = socket( AF_INET, SOCK_STREAM, 6 )) == -1 ) { /* fixme, error message */ if ( DBG_LEVEL > 10 ) { printf( "error in socket()\n" ); } return ""; } else { if ( connect( sock, (struct sockaddr*)&sa, sizeof(sa)) == -1 ) { /* fixme, error message */ if ( DBG_LEVEL > 10 ) { printf( "error in connect()\n" ); } close(sock); return ""; } } snprintf( url, 1024, "GET %s HTTP/1.0\r\n" "Accept: text/html\r\n" "Accept: text/plain\r\n" "User-Agent: Gyach/%s\r\n" "Host: %s\r\n" "\r\n" "\r\n", ptr, VERSION, host ); write( sock, url, strlen( url )); result[0] = '\0'; tr = 0; nr = read( sock, tmp, 512 ); while(( nr > 0 ) && ( tr < 65000 )) { tmp[nr] = '\0'; memcpy( result + tr, tmp, nr ); tr += nr; process_gtk_events(); nr = read( sock, tmp, 512 ); } close( sock ); ptr = strstr( result, "\r\n\r\n" ); ptr += 4; if ( strstr( result, "Not Found" )) return( "" ); /* old way when was using mktemp() instead of mkstemp() ifp = open( tmp_filename, O_CREAT | O_TRUNC| O_WRONLY, 0600 ); */ /* new way using mkstemp() */ if (( ifp = mkstemp( tmp_filename )) == -1 ) { fprintf( stderr, "mkstemp( '%s' ) == -1\n", tmp_filename ); fflush( stderr ); return( "" ); } write( ifp, ptr, tr - ( ptr - result )); close( ifp ); DBG( 12, "download_image() == '%s'\n", tmp_filename ); return tmp_filename; } GtkFunction view_profile( gpointer data ) { fetch_profile( (void *)g_strdup((char *)data) ); if (prof_text) display_profile(); return(0); } /* this function gets run as a separate thread so it does not hold up chat */ /* while downloading html and image and parsing/displaying */ /* NOTE: this function frees *arg when done, so use strdup() before calling */ void *fetch_profile( void *arg ) { char *user = (char *)arg; int sock; struct sockaddr_in sa; struct hostent *hinfo; char url[1025]; char result[32769]; char tmp[32769]; char buf[8192]; #ifndef USE_GDK_PIXBUF char cmd[512]; #endif char host[32] = "profiles.yahoo.com"; int nr = 0, tr = 0; char *ptr; char *ptr2; char pic_url[129] = ""; char last_updated[21] = ""; char email[129] = ""; char realname[51] = ""; char nickname[51] = ""; char location[51] = ""; char age[5] = ""; char married[21] = ""; char sex[11] = ""; char occupation[51] = ""; char online_now[11] = ""; char homepage[129] = ""; char coollink1[129] = ""; char coollink2[129] = ""; char coollink3[129] = ""; DBG( 11, "fetch_profile( '%s' )\n", user ); if ( ! profile_viewer ) { snprintf( homepage, 128, "http://profiles.yahoo.com/%s", user ); ptr = strdup( homepage ); display_url( (void *)ptr ); free( user ); return( NULL ); } if ( use_proxy ) { hinfo = gethostbyname( proxy_host ); } else { hinfo = gethostbyname( host ); } if ( ! hinfo || ( hinfo->h_addrtype != AF_INET )) { /* fixme, show an error box */ free( user ); return( NULL ); } 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 ) { /* fixme, error message */ if ( DBG_LEVEL > 10 ) { printf( "error in socket()\n" ); } free( user ); return( NULL ); } else { if ( connect( sock, (struct sockaddr*)&sa, sizeof(sa)) == -1 ) { /* fixme, error message */ if ( DBG_LEVEL > 10 ) { printf( "error in connect()\n" ); } close(sock); free( user ); return( NULL ); } } if ( use_proxy ) { snprintf( url, 1024, "GET http://%s/%s HTTP/1.0\r\n" "Accept: text/html\r\n" "Accept: text/plain\r\n" "User-Agent: Gyach/%s\r\n" "Host: %s\r\n" "\r\n" "\r\n", host, user, VERSION, host ); } else { snprintf( url, 1024, "GET /%s HTTP/1.0\r\n" "Accept: text/html\r\n" "Accept: text/plain\r\n" "User-Agent: Gyach/%s\r\n" "Host: %s\r\n" "\r\n" "\r\n", user, VERSION, host ); } write( sock, url, strlen( url )); result[0] = '\0'; tr = 0; nr = read( sock, tmp, 32768 ); while( nr > 0 ) { tmp[nr] = '\0'; my_strncat( result, tmp, sizeof(result)); tr += nr; nr = read( sock, tmp, 32768 - tr ); } /* find the url to their pic */ snprintf( tmp, sizeof(tmp), "alt=\"%s\"", user ); ptr = tmp; while( *ptr ) *(ptr++) = tolower( *ptr ); ptr = strstr( result, tmp ); if ( ptr ) { while((( *(ptr-4) != 's' ) || ( *(ptr-3) != 'r' ) || ( *(ptr-2) != 'c' ) || ( *(ptr-1) != '=' )) && ( ptr > (result+5))) { ptr--; } if ( *ptr == '"' ) ptr++; /* now we are at the beginning of the url, so strncpy some */ strncpy( pic_url, ptr, 128 ); ptr = strchr( pic_url, '"' ); ptr2 = strchr( pic_url, ' ' ); if (( ptr && ptr2 ) && ( ptr2 < ptr )) ptr = ptr2; if ( ptr ) *ptr = '\0'; else pic_url[128] = '\0'; } /* strip html to make the rest easier */ strip_html_tags( result ); /* attempt to find some strings */ find_field_line( result, "Last Updated:", last_updated ); find_field( result, "My Email", email ); find_field( result, "Real Name:", realname ); find_field( result, "Nickname:", nickname ); find_field( result, "Location:", location ); find_field( result, "Age:", age ); find_field( result, "Marital Status:", married ); find_field( result, "Gender:", sex ); find_field( result, "Occupation:", occupation ); find_field_line( result, "Home Page:", homepage ); if (!strcmp( homepage, "No")) strcpy( homepage, "No homepage specified" ); find_field_line( result, "Cool Link:", coollink1 ); if (!strcmp( coollink1, "No")) { strcpy( coollink1, "No cool links specified" ); } else { find_field_line( result, "Cool Link 1:", coollink1 ); find_field_line( result, "Cool Link 2:", coollink2 ); find_field_line( result, "Cool Link 3:", coollink3 ); } ptr = strstr( result, "I'm online now!" ); if ( ptr ) { strcpy( online_now, "Online now!" ); } else { strcpy( online_now, "OFFline" ); } if ( DBG_LEVEL >= 10 ) { printf( "profile info for %s:\n", user ); printf( "Picture : '%s'\n", pic_url ); printf( "Last Updated : '%s'\n", last_updated ); printf( "Email : '%s'\n", email ); printf( "Real Name : '%s'\n", realname ); printf( "Nickname : '%s'\n", nickname ); printf( "Location : '%s'\n", location ); printf( "Age : '%s'\n", age ); printf( "Married? : '%s'\n", married ); printf( "Sex : '%s'\n", sex ); printf( "Occupation : '%s'\n", occupation ); printf( "Online Now : '%s'\n", online_now ); printf( "Home Page : '%s'\n", homepage ); printf( "Cool Link #1 : '%s'\n", coollink1 ); printf( "Cool Link #2 : '%s'\n", coollink2 ); printf( "Cool Link #3 : '%s'\n", coollink3 ); } close(sock); snprintf( buf, sizeof(buf), "Yahoo! ID : %s\n" "Real Name : %s\n" "Nickname : %s\n" "Last Updated : %s\n" "Location : %s\n" "Age : %s\n" "Marital Status : %s\n" "Sex : %s\n" "Occupation : %s\n" "Email : %s\n" "HomePage : %s\n" "Cool Links : %s\n" " %s\n" " %s\n", user, realname, nickname, last_updated, location, age, married, sex, occupation, email, homepage, coollink1, coollink2, coollink3 ); if ( pic_url[0] ) { ptr = download_image( pic_url ); #ifdef USE_GDK_PIXBUF prof_pic = ptr; #else snprintf( cmd, sizeof(cmd), "convert -geometry 200x200 -colors 256 %s " "xpm:%s.xpm", ptr, ptr ); if ( ! my_system( cmd )) { snprintf( cmd, sizeof(cmd), "%s.xpm", ptr ); prof_pic = strdup( cmd ); } unlink( ptr ); #endif } prof_text = strdup( buf ); free( user ); return( NULL ); } int set_last_comment( char *user, char *comment ) { char tmp[2048]; char tmp_user[128]; char tmp_comment[2048]; char *ptr = NULL; int count = 0; int row = 0; if ( ! last_comments ) { last_comments = g_hash_table_new( g_str_hash, g_str_equal ); } if ( ! last_comments ) { return( 0 ); } my_strncpy( tmp_user, user, sizeof(tmp_user)); lower_str( tmp_user ); my_strncpy( tmp_comment, comment, sizeof(tmp_comment)); /* lower_str( tmp_comment ); */ strip_html_tags( tmp_comment ); if (( ptr = g_hash_table_lookup( last_comments, tmp_user )) != NULL ) { if ( ! strcmp( ptr + 4, tmp_comment )) { /* user said same thing again */ count = atoi( ptr ) + 1; } else { /* user said something new */ count = 1; } snprintf( tmp, sizeof(tmp), "%03d:%s", count, tmp_comment ); /* don't pass in a strduped key since insert uses existing key ptr */ g_hash_table_insert( last_comments, g_strdup(tmp_user), g_strdup(tmp)); g_free( ptr ); } else { /* user has no previous comment */ count = 1; snprintf( tmp, sizeof(tmp), "%03d:%s", count, tmp_comment ); /* pass in a strduped key since insert needs a key ptr itself */ g_hash_table_insert( last_comments, g_strdup(tmp_user), g_strdup(tmp)); } gtk_clist_freeze(GTK_CLIST(chat_users)); row = find_user_row( user ); gtk_clist_set_text(GTK_CLIST(chat_users), row, 2, tmp ); gtk_clist_thaw(GTK_CLIST(chat_users)); return( count ); } char *get_last_comment( char *user ) { char tmp_user[128]; char *ptr; my_strncpy( tmp_user, user, sizeof(tmp_user)); lower_str( tmp_user ); if ( ! last_comments ) { return( NULL ); } if (( ptr = g_hash_table_lookup( last_comments, tmp_user )) != NULL ) { return( ptr + 4 ); } return( NULL ); } static void print_last_comment(gpointer key, gpointer value, gpointer user_data) { char tmp[2048]; snprintf( tmp, sizeof(tmp), "%-25s: %3d : ", (char *)key, atoi((char *)value )); ct_append_fixed( tmp, strlen( tmp )); snprintf( tmp, sizeof(tmp), "%s\n", (char *)value + 4 ); append_to_textbox( chat_window, NULL, tmp ); } void show_last_comments() { char tmp[128]; strcpy( tmp, "-----------------------------------------------------------------\n" ); append_to_textbox( chat_window, NULL, tmp ); strcpy( tmp, "Last comment/action for each user (with number of times):\n" ); append_to_textbox( chat_window, NULL, tmp ); if ( last_comments ) { g_hash_table_foreach( last_comments, print_last_comment, NULL ); } else { strcpy( tmp, "No comments yet...\n" ); append_to_textbox( chat_window, NULL, tmp ); } strcpy( tmp, "-----------------------------------------------------------------\n" ); append_to_textbox( chat_window, NULL, tmp ); } GList *find_pm_session( char *user ) { GList *this_session = pm_list; PM_SESSION *pm_sess; DBG( 11, "find_pm_session( '%s' )\n", user ); while( this_session ) { pm_sess = (PM_SESSION *)this_session->data; if ( !strcasecmp( user, pm_sess->pm_user )) { return( this_session ); } this_session = g_list_next( this_session ); } return( NULL ); } GList *find_pm_session_from_widget( GtkWidget *widget, char *name ) { GList *this_session = pm_list; PM_SESSION *pm_sess; GtkWidget *tmp_widget; DBG( 11, "find_pm_session_from_widget( %p, '%s' )\n", widget, name ); while( this_session ) { pm_sess = (PM_SESSION *)this_session->data; if ( pm_sess->pm_window == widget ) { return( this_session ); } tmp_widget = lookup_widget( pm_sess->pm_window, name ); if ( tmp_widget == widget ) { return( this_session ); } this_session = g_list_next( this_session ); } return( NULL ); }