/* * Copyright (C) 1998 Nathan Neulinger * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include "gtkyahoo.h" static void click_in_chat_textbox(GtkWidget * w, GdkEventButton * event, gpointer data); void send_from_chat_window(GtkWidget * widget, gpointer * data) { char *from; char *to; char *text; struct gtkyahoo_chat_window *cw = (struct gtkyahoo_chat_window *) data; /* Get the info on who to send from/to */ from = cw->chat_from; to = cw->chat_to; /* Copy the current text and clear the entry area */ text = strdup(gtk_entry_get_text(GTK_ENTRY(cw->entry))); gtk_entry_set_text(GTK_ENTRY(cw->entry), ""); /* Send the message */ have_user_activity(); yahoo_cmd_msg(context, from, to, text); /* Append it to the window */ append_chat_msg(cw, from, text); /* Grab focus for the text entry again */ gtk_widget_grab_focus(cw->entry); /* Free the copy of the text */ free(text); } /* Add notification message to any relevant windows */ void append_chat_window_notification(struct gtkyahoo_chat_window *cw, char *what) { if (cw) { char msg[1000]; snprintf(msg, 1000, "%s%s%s%s%s", YAHOO_COLOR_RED, YAHOO_STYLE_BOLDON, what, YAHOO_STYLE_BOLDOFF, YAHOO_COLOR_BLACK); append_chat_msg(cw, NULL, msg); } } /* Add notification message to any relevant windows */ void append_chat_notification(char *user, char *what) { int i; struct gtkyahoo_chat_window *cw = find_chat_window(current_user, user); i = 0; while (context->identities && context->identities[i]) { cw = find_chat_window(context->identities[i], user); if (cw) { append_chat_window_notification (cw, what); } i++; } } /* Append message to chat window */ void append_chat_msg(struct gtkyahoo_chat_window *cw, char *user, char *msg) { char *timestamp = make_timestamp(); if (show_timestamp) { append_to_textbox(cw->window, cw->textbox, timestamp); } if (user) { char *colored_user, *color_string; /* Color other users' names blue, just like mswin client */ if (strcasecmp(cw->chat_from, user)) color_string = YAHOO_COLOR_BLUE; else color_string = YAHOO_COLOR_BLACK; if ((colored_user = malloc(strlen(user) + strlen(color_string) + 3))) { sprintf(colored_user, "%s%s: ", color_string, user); append_to_textbox(cw->window, cw->textbox, colored_user); free(colored_user); } } if (cw->transcript) { if (user) { if (strcasecmp(cw->chat_to, user)) { /* timestamp = "[MM/DD/YYYY HH:MM:SS] " */ if (cw->singlelog) fprintf(cw->transcript, "[%s %s -> %s: %s\n", timestamp+12, cw->chat_from, cw->chat_to, msg); else fprintf(cw->transcript, "[%s %s: %s\n", timestamp+12, cw->chat_from, msg); } else { if (cw->singlelog) fprintf(cw->transcript, "[%s %s -> %s: %s\n", timestamp+12, cw->chat_to, cw->chat_from, msg); else fprintf(cw->transcript, "[%s %s: %s\n", timestamp+12, cw->chat_to, msg); } } else { fprintf(cw->transcript, "%s%s\n", timestamp, msg); } fflush(cw->transcript); } append_to_textbox(cw->window, cw->textbox, msg); append_to_textbox(cw->window, cw->textbox, "\n"); ensure_window_raised(cw->window->window); } void chat_window_gains_focus(GtkWidget * widget, GdkEvent * event, gpointer * data) { struct gtkyahoo_chat_window *tmpcw; tmpcw = (struct gtkyahoo_chat_window *) data; tmpcw->hasFocus = TRUE; /* DBG_Print("general", "Chat Window with user \"%s\" has gained focus\n", tmpcw->chat_to); */ } void chat_window_loses_focus(GtkWidget * widget, GdkEvent * event, gpointer * data) { struct gtkyahoo_chat_window *tmpcw; tmpcw = (struct gtkyahoo_chat_window *) data; tmpcw->hasFocus = FALSE; /* DBG_Print("general", "Chat Window with user \"%s\" has lost focus\n", tmpcw->chat_to); */ } /* another callback */ void delete_chat_window(GtkWidget * widget, GdkEvent * event, gpointer * data) { struct gtkyahoo_chat_window *tmpcw; char *timestamp = make_timestamp(); tmpcw = (struct gtkyahoo_chat_window *) data; /* Remove the entry from the hash */ if (cwhash) { g_hash_table_remove(cwhash, tmpcw->key); } /* Destroy/free all the window elements */ gtk_widget_destroy(GTK_WIDGET(tmpcw->window)); if (tmpcw->transcript) { if (tmpcw->singlelog) fprintf(tmpcw->transcript, "Chat ended on %s: %s <-> %s\n", timestamp, tmpcw->chat_from, tmpcw->chat_to); else fprintf(tmpcw->transcript, "Chat ended on %s\n", timestamp); fflush(tmpcw->transcript); fclose(tmpcw->transcript); } if (tmpcw->chat_to) { free(tmpcw->chat_to); } if (tmpcw->chat_from) { free(tmpcw->chat_from); } if (tmpcw->key) { free(tmpcw->key); } free(tmpcw); } /* Generate chat window key */ char *gtkyahoo_chat_window_key(char *chat_from, char *chat_to) { char *key; int len; int i; /* Generate the key */ len = strlen(chat_from) + strlen(chat_to) + 5; key = (char *) malloc(len); /* key in sorted order so that a,b will be same window as b,a */ if (strcasecmp(chat_from, chat_to) > 0) { snprintf(key, len, "%s,%s", chat_from, chat_to); } else { snprintf(key, len, "%s,%s", chat_to, chat_from); } /* key is in lowercase to ignore case */ for (i = 0; i <= strlen(key); i++) { key[i] = tolower(key[i]); } return key; } /* Get or create a chat window */ struct gtkyahoo_chat_window *get_chat_window(char *chat_from, char *chat_to) { struct gtkyahoo_chat_window *tmpcw; char *key; char *timestamp = make_timestamp(); /* Create the hash if necessary */ if (!cwhash) { cwhash = g_hash_table_new((GHashFunc) gtkyahoo_hash, (GCompareFunc) gtkyahoo_hash_compare); } /* Generate the key */ key = gtkyahoo_chat_window_key(chat_from, chat_to); /* Look up the entry */ tmpcw = (struct gtkyahoo_chat_window *) g_hash_table_lookup(cwhash, (gpointer) key); if (!tmpcw) { tmpcw = create_chat_window(chat_from, chat_to); g_hash_table_insert(cwhash, (gpointer) tmpcw->key, (gpointer) tmpcw); append_chat_msg(tmpcw, NULL, YAHOO_COLOR_RED YAHOO_STYLE_BOLDON "Chat Session Started" YAHOO_STYLE_BOLDOFF YAHOO_COLOR_BLACK); gdk_window_raise(tmpcw->window->window); if (tmpcw->transcript) { if (tmpcw->singlelog) fprintf(tmpcw->transcript, "Chat started on %s: %s <-> %s\n", timestamp, tmpcw->chat_from, tmpcw->chat_to); else fprintf(tmpcw->transcript, "Chat started on %s\n", timestamp); fflush(tmpcw->transcript); } } /* free the key */ free(key); /* Return the window */ return tmpcw; } /* Find a chat window, return null if not found */ struct gtkyahoo_chat_window *find_chat_window(char *chat_from, char *chat_to) { struct gtkyahoo_chat_window *tmpcw; char *key; /* Create the hash if necessary */ if (!cwhash) { return NULL; } /* Generate the key */ key = gtkyahoo_chat_window_key(chat_from, chat_to); /* Look up the entry */ tmpcw = (struct gtkyahoo_chat_window *) g_hash_table_lookup(cwhash, (gpointer) key); /* Free the temporary key */ free(key); /* Return the window */ return tmpcw; } /* Create a chat window */ struct gtkyahoo_chat_window *create_chat_window(char *chat_from, char *chat_to) { struct gtkyahoo_chat_window *cw; char *title; char buff[4096]; /* path to logfile */ char buff2[256]; /* name of logfile */ int len; /* Allocate local structure */ cw = (struct gtkyahoo_chat_window *) malloc(sizeof(*cw)); memset (cw, 0, sizeof (*cw)); /* Set parameters */ cw->key = gtkyahoo_chat_window_key(chat_from, chat_to); cw->chat_from = strdup(chat_from); cw->chat_to = strdup(chat_to); /* send the newchat event */ event_clearinfo(); event_info->chat_from = chat_from; event_info->chat_to = chat_to; event_info->msg = "New Chat"; event_execute(GTKYAHOO_EVENT_NEWCHAT); /* Generate window title */ len = strlen(chat_from) + strlen(chat_to) + 50; title = (char *) malloc(len); snprintf(title, len, "GTKYahoo Chat (%s <=> %s)", chat_from, chat_to); /* Create main window */ cw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(cw->window), title); gtk_container_border_width(GTK_CONTAINER(cw->window), 5); gtk_widget_realize(cw->window); /* Free the title */ free(title); /* Trap delete_event signal */ gtk_signal_connect(GTK_OBJECT(cw->window), "delete_event", GTK_SIGNAL_FUNC(delete_chat_window), (gpointer) cw); /* Trap focus_in_event signal */ gtk_signal_connect(GTK_OBJECT(cw->window), "focus_in_event", GTK_SIGNAL_FUNC(chat_window_gains_focus), (gpointer) cw); /* Trap focus_in_event signal */ gtk_signal_connect(GTK_OBJECT(cw->window), "focus_out_event", GTK_SIGNAL_FUNC(chat_window_loses_focus), (gpointer) cw); /* Create the boxes */ /* 1) whole window (menu_box,image,text_box) */ /* 2) menu bar box */ /* 3) text area box */ cw->box_window = gtk_vbox_new(FALSE, 0); cw->box_menus = gtk_hbox_new(FALSE, 0); cw->box_text = gtk_hbox_new(FALSE, 0); cw->box_entry = gtk_hbox_new(FALSE, 0); gtk_widget_show(cw->box_window); gtk_widget_show(cw->box_menus); gtk_widget_show(cw->box_text); gtk_widget_show(cw->box_entry); /* build the full window box */ gtk_container_add(GTK_CONTAINER(cw->window), cw->box_window); gtk_box_pack_start(GTK_BOX(cw->box_window), cw->box_menus, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(cw->box_window), cw->box_text, TRUE, TRUE, 5); gtk_box_pack_start(GTK_BOX(cw->box_window), cw->box_entry, FALSE, TRUE, 0); /* Create the text entry area */ /* Note, the 1000 should not be user configurable. This needs to be done more cleanly, but is primarily based on the maximum packet size accepted by the pager server. I'm not positive 1000 will work. */ cw->entry = gtk_entry_new_with_max_length(1000); gtk_box_pack_start(GTK_BOX(cw->box_entry), cw->entry, TRUE, TRUE, 3); gtk_widget_show(cw->entry); gtk_signal_connect(GTK_OBJECT(cw->entry), "activate", GTK_SIGNAL_FUNC(send_from_chat_window), (gpointer) cw); /* Grab focus (insertion point) */ gtk_widget_grab_focus(cw->entry); /* Create the send button */ cw->button = gtk_button_new(); gtk_box_pack_end(GTK_BOX(cw->box_entry), cw->button, FALSE, TRUE, 3); gtk_widget_show(cw->button); gtk_signal_connect(GTK_OBJECT(cw->button), "clicked", GTK_SIGNAL_FUNC(send_from_chat_window), (gpointer) cw); gtk_container_add(GTK_CONTAINER(cw->button), xpm_label_box(cw->window, pixmapdata_send, "Send")); /* create a text box */ cw->textbox = gtk_text_new(NULL, NULL); gtk_box_pack_start(GTK_BOX(cw->box_text), cw->textbox, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(cw->textbox), "button_press_event", GTK_SIGNAL_FUNC(click_in_chat_textbox), GTK_TEXT(cw->textbox)->vadj); /* turned off since looked a little weird */ if (chat_window_wrap) gtk_text_set_word_wrap(GTK_TEXT(cw->textbox), TRUE); if ((chat_window_sizew > -1) || (chat_window_sizeh > -1)) { int height = -1, width = -1; /* This assumes we are using the default font. If we ever adjust the font, subst. (GdkFont*)(GTK_TEXT(cw->textbox)->current_font) for cw->textbox->style->font */ /* Should use 'M' here, that's what TeX always used, but it's too huge, try something average sized like 0 */ if (chat_window_sizew > -1) width = chat_window_sizew * gdk_char_width(cw->textbox->style->font, '0'); if (chat_window_sizeh > -1) height = chat_window_sizeh * (cw->textbox->style->font->ascent + cw->textbox->style->font->descent); #if 0 printf("wc=%d hc=%d : w=%d h=%d\n", chat_window_sizew, chat_window_sizeh, width, height); #endif gtk_widget_set_usize(cw->textbox, width, height); } gtk_widget_show(cw->textbox); /* Make the text box scrollable */ cw->scroll = gtk_vscrollbar_new(GTK_TEXT(cw->textbox)->vadj); gtk_box_pack_start(GTK_BOX(cw->box_text), cw->scroll, FALSE, FALSE, 0); gtk_widget_show(cw->scroll); /* Now show the main window */ gtk_widget_show(cw->window); if( chat_log_fileformat ) { char *tmpbuff = NULL; tmpbuff = create_chat_logfilename(chat_log_fileformat, cw); shellsafecpy(buff2, tmpbuff, strlen(tmpbuff)); snprintf(buff, 4096, "%s/.gtkyahoo/%s", getenv("HOME"), buff2); if(tmpbuff == NULL) DBG_Print("rcfile", "Error creating chat log filename\n"); else { if ( (cw->transcript = fopen(buff, "a")) == NULL ) { perror(buff); } free(tmpbuff); } } return cw; } static void click_in_chat_textbox(GtkWidget * w, GdkEventButton * event, gpointer data) { switch (event->button) { case 4: case 5: { GtkAdjustment *adjust = GTK_ADJUSTMENT(data); const gfloat step = adjust->page_increment / 2.0; const gfloat value = adjust->value; gtk_adjustment_set_value (adjust, (event->button == 5) ? MIN (value+step, adjust->upper - adjust->page_size) : MAX (value-step, adjust->lower)); gtk_adjustment_value_changed(adjust); } break; } }