/* Silky - A GTK+ client for SILC. Copyright (C) 2003, 2004, 2005 Toni Willberg - GUI-related functions FIXME: move most of stuff from here to ui_ -files 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 http://silky.sourceforge.net/ */ #include #include #include #include #include #ifdef HAVE_CONFIG_H # include #endif #include "support.h" /* context_nick_event() */ #include "gui.h" #include "channel.h" #include "query.h" #include "buddylist.h" #include "servers.h" #include "preferences.h" /* prefs_get() */ #include "ui_preferences.h" /* populate_prefs_serverlist() */ #include "callbacks.h" /* on_window_hide() */ #include "log.h" #include "commands.h" #include "xmllayout.h" #include "xmlconfig.h" /* xml_save_config() */ #include "cmdhistory.h" #include "tips.h" #include "ui_console.h" #include "ui_channel.h" #include "common.h" extern GladeXML *xmlmain; extern silkyStruct *silky; extern gchar *previous_nick; /* my nickname just before sending NICK command */ extern SilkyChannel *channels; /* from channel.c */ extern SilkyChannel *channel_active; extern SilkyQuery *query_active; extern SilkyCmdHistoryItem *current_cmd_history_entry; /* from cmdhistory.c */ extern SilkyServer *servers; extern SilkyBuddy *buddies; /* called when About button is clicked on the menu */ void on_ui_about(GtkWidget *widget, gpointer user_data) { gtk_widget_show(glade_xml_get_widget (xmlmain, "dialog_about")); /* I18N This is a window title */ gtk_label_set_label( GTK_LABEL(glade_xml_get_widget (xmlmain, "about_silky_label")) , g_strdup_printf("Silky %s", SILKY_VERSION) ); } /* QUIT */ /* this function is *just* a callback, we call real quit function from here */ void on_ui_quit(GtkWidget *widget, gpointer user_data) { handle_command("QUIT"); } /* User has clicked [Send] or hit enter in the input box. Is this a command or a message? */ void on_ui_send_check(GtkWidget *widget, gpointer input) { GtkEntry *inmes; gchar *message; debug("on_ui_send_check()"); /* Get value of the input box */ inmes = GTK_ENTRY(glade_xml_get_widget (xmlmain, "inputbox")); message = g_strdup(gtk_entry_get_text(inmes)); if (!message || strlen(message) <= 0) { debug("empty message, skipping!"); return; } cmd_history_push(message); current_cmd_history_entry = NULL; if (message[0] == '/') { /* It's a command, parse it */ debug("command"); handle_command (message + 1); gtk_entry_set_text(GTK_ENTRY(inmes), ""); free(message); } else { /* It's a message, send on to on_ui_send() */ on_ui_send(widget,input); } } /* hide/show inputbox when on console/channel page */ void on_ui_tabs_switch_page(GtkNotebook *notebook, GtkNotebookPage *page, guint pagenr, gpointer user_data) { SilkyChannel *ch = NULL; SilkyQuery *q = NULL; gui_renumber_tabs(); debug ("on_ui_tabs_switch_page(%d)", pagenr); ch = channel_find_by_pagenr(gtk_notebook_get_current_page(notebook)); if(ch == NULL) { channel_active = NULL; debug("no channel on this tab, setting channel_active = NULL"); } q = query_find_by_pagenr(gtk_notebook_get_current_page(notebook)); if(q == NULL) { query_active = NULL; debug("no query on this tab, setting query_active = NULL"); } if( !q && !ch ) { debug("Not a channel or query page, returning."); return; } debug("got reply, page: %d", pagenr); gtk_widget_show (glade_xml_get_widget (xmlmain, "inputbox")); gtk_widget_show (glade_xml_get_widget (xmlmain, "button_send")); gtk_widget_grab_focus(glade_xml_get_widget (xmlmain, "inputbox")); /* if channel page FIXME; segfaults on null why? */ if(ch && ch->channel_entry) { debug("Active channel now: %s", ch->channel_entry->channel_name); channel_active = ch; gtk_label_set_markup( (gpointer)ch->label_text, g_strconcat(CHANNEL_NAME(ch), NULL)); gtk_image_set_from_stock( (gpointer)ch->label_image, GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_BUTTON ); } else if( q && q->client_entry ) { debug("Active query now: %s", q->client_entry->nickname); query_active = q; gtk_label_set_markup( (gpointer)q->label_text, g_strconcat(q->client_entry->nickname, NULL)); gtk_image_set_from_stock( (gpointer)q->label_image, GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_BUTTON ); } else { debug("Active page doesn't belong to a channel or query."); channel_active = NULL; query_active = NULL; } } /* Send NICK command to the server */ gboolean on_nick_change(GtkWidget *widget, gpointer user_data) { GtkEntry *input; const gchar *new_nick; const gchar *old_nick; debug("on_nick_change()"); if (!CONNECTED) { printconsole(_("Can not change nickname: You are not yet connected to server.")); return FALSE; } input = GTK_ENTRY(glade_xml_get_widget (xmlmain, "new_nickname")); new_nick = gtk_entry_get_text(input); old_nick = silky->conn->nickname; if (strlen(new_nick) <1 ) { printconsole(_("Can not change nickname: Empty nickname not allowed.")); return FALSE; } if (new_nick && old_nick && !strcmp(new_nick, old_nick) ) { printconsole(_("Can not change nickname: That is your current nickname already.")); return FALSE; } /* set global variable for later use */ previous_nick = strdup(old_nick); silc_client_command_call(silky->client, silky->conn, NULL, "NICK", new_nick, NULL); debug("\tCommand sent. New entry says the nick is '%s'", silky->conn->nickname); on_window_hide(glade_xml_get_widget (xmlmain, "dialog_nick_change"), NULL); return FALSE; } /* user asked to disconnect */ void on_disconnect_from_server(GtkWidget *widget, gpointer user_data) { debug("on_disconnect_from_server()"); if ( CONNECTED ) { debug("We are connected; sending QUIT command"); debug("setting state to STATE_DISCONNECTING"); silky->state = STATE_DISCONNECTING; silc_client_command_call(silky->client, silky->conn, NULL, "QUIT", strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget (xmlmain,"set_quitmessage")))), NULL); debug("sent"); } else { debug("We are not connected, can not disconnect now"); printconsole(_("You are not connected to server.")); } } /* when user wants to see info about the server he's connected to */ void on_serverinfo(GtkWidget *widget, gpointer user_data) { debug("on_serverinfo()"); if (CONNECTED) { debug("sending MOTD %s", silky->conn->local_entry->server); silc_client_command_call(silky->client, silky->conn, NULL, "MOTD", silky->conn->local_entry->server, NULL); debug("sending INFO %s", silky->conn->local_entry->server); silc_client_command_call(silky->client, silky->conn, NULL, "INFO", silky->conn->local_entry->server, NULL); debug("sending STATS %s", silky->conn->local_entry->server); silc_client_command_call(silky->client, silky->conn, NULL, "STATS", silky->conn->local_entry->server, NULL); } else { debug("not yet connected"); printconsole(_("You are not connected to server.")); } } /* Show Join to a channel -dialog */ void on_show_join_channel_window(GtkWidget *widget, gpointer user_data) { debug("on_show_join_channel_window()"); /* Show an error dialog if there's no connection */ if (!CONNECTED) { printconsole(_("You are not connected to server.")); return; } if (!widget) { debug("No such widget!?"); return; } gtk_widget_show (glade_xml_get_widget (xmlmain, "dialog_join_channel")); /* I18N This is a window title */ gtk_window_set_title(GTK_WINDOW(glade_xml_get_widget (xmlmain, "dialog_join_channel")), g_strdup_printf("Silky v%s : %s", SILKY_VERSION, _("Join a channel"))); gtk_editable_select_region(GTK_EDITABLE(glade_xml_get_widget(xmlmain, "join_channel_name")), 0, -1); } /* Show incoming invite dialog */ void on_show_received_invite_window(GtkWidget *widget, gpointer user_data) { debug("on_show_received_invite_window()"); if (!widget) { debug("No such widget!?"); return; } gtk_widget_show (glade_xml_get_widget (xmlmain, "dialog_received_invite")); /* I18N This is a window title */ gtk_window_set_title(GTK_WINDOW(glade_xml_get_widget (xmlmain, "dialog_received_invite")), g_strdup_printf("Silky v%s : %s", SILKY_VERSION, _("Join channel?"))); } /* Show the CHANGE NICK dialog */ void on_show_nick_change_window(GtkWidget *widget, gpointer user_data) { debug("on_show_nick_change_window()"); if ( !CONNECTED ) { printconsole(_("You are not connected to server.")); return; } gtk_widget_show (glade_xml_get_widget (xmlmain, "dialog_nick_change")); gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(xmlmain, "new_nickname")), silky->client->nickname); gtk_editable_select_region(GTK_EDITABLE(glade_xml_get_widget(xmlmain, "new_nickname")), 0, -1); /* I18N This is a window title */ gtk_window_set_title(GTK_WINDOW(glade_xml_get_widget (xmlmain, "dialog_nick_change")), g_strdup_printf("Silky v%s : %s", SILKY_VERSION, _("Change nickname"))); } /* Show the SERVER CONNECT dialog */ void on_show_server_connect_window(GtkWidget *widget, gpointer user_data) { SilkyServer *s; GtkWidget *combo; GList *serveritems = NULL; debug("on_show_server_connect_window()"); if ( CONNECTED || CONNECTING ) { errordialog(_("You are already connected.")); return; } combo = glade_xml_get_widget(xmlmain, "new_servername_combo"); /* populate the dialog's combo list with out servers */ for( s = servers; s; s = s->next ) { if(s->hostname && g_utf8_strlen(s->hostname, -1) ) { debug("server: '%s'", s->hostname); serveritems = g_list_append (serveritems, s->hostname); } } if (serveritems) { gtk_combo_set_popdown_strings (GTK_COMBO (combo), serveritems); } gtk_widget_show (glade_xml_get_widget (xmlmain, "dialog_connect_server")); /* I18N This is a window title */ gtk_window_set_title(GTK_WINDOW(glade_xml_get_widget (xmlmain, "dialog_connect_server")), g_strdup_printf("Silky v%s : %s", SILKY_VERSION, _("Connect to a server"))); } int on_window_hide(GtkWidget *widget, gpointer window) { debug("on_window_hide"); if (!widget) { debug("No such window on_window_hide()"); return FALSE; } gtk_widget_hide (widget); return TRUE; } /* SETTINGS */ void on_settings(GtkWidget *widget, gpointer user_data) { prefs_populate_gui(); gtk_widget_show (glade_xml_get_widget (xmlmain, "dialog_preferences")); /* I18N This is a window title */ gtk_window_set_title(GTK_WINDOW(glade_xml_get_widget (xmlmain, "dialog_preferences")), g_strdup_printf("Silky v%s : %s", SILKY_VERSION, _("Settings"))); } void silky_gui_show_main() { GtkTextBuffer *tiptext = gtk_text_view_get_buffer(GTK_TEXT_VIEW(glade_xml_get_widget(xmlmain, "tipstextview"))); gint ret = GTK_RESPONSE_OK; gchar *tip = NULL; debug ("Showing the main window"); /* generate and show the main app window */ gtk_window_set_title (GTK_WINDOW (glade_xml_get_widget (xmlmain, "window_main")), g_strdup_printf ("Silky v%s", SILKY_VERSION)); gtk_widget_show (glade_xml_get_widget (xmlmain, "window_main")); /* set colors to the console tab */ set_textview_colors(GTK_TEXT_VIEW(glade_xml_get_widget (xmlmain, "textviewwidget"))); /* Show the input box for commands */ gtk_widget_show (glade_xml_get_widget (xmlmain, "inputbox")); /* Don't forget the send button */ gtk_widget_show (glade_xml_get_widget (xmlmain, "button_send")); /* set focus to inputbox of the main window */ gtk_widget_grab_focus (glade_xml_get_widget (xmlmain, "inputbox")); debug ("setting state to STATE_DISCONNECTED"); silky->state = STATE_DISCONNECTED; /* show the tips window */ ret = GTK_RESPONSE_OK; if ( prefs_str_to_bool(prefs_get("show_tips")) ) { while (ret == GTK_RESPONSE_OK) { debug ("showing a tip"); tip = silky_get_random_tip(); gtk_text_buffer_set_text(tiptext, tip, strlen(tip)); g_free(tip); ret = gtk_dialog_run (GTK_DIALOG(glade_xml_get_widget (xmlmain, "dialog_tips"))); } gtk_widget_hide(glade_xml_get_widget (xmlmain, "dialog_tips")); } else { debug ("not showing tip of the day"); } } /* this will check the type bits for sanity */ gboolean is_valid_msg_type(type) { if(type <= 0) return FALSE; /* MSG_PUBLIC and MSG_PRIVATE are mutually exclusive */ if( (type & MSG_PUBLIC) && (type & MSG_PRIVATE) ) return FALSE; /* only one of MSG_MESSAGE, MSG_ACTION and MSG_MOTION can be set */ if( (type & MSG_MESSAGE) && ((type & MSG_ACTION) || (type & MSG_MOTION)) ) return FALSE; if( (type & MSG_ACTION) && ((type & MSG_MOTION) || (type & MSG_MESSAGE)) ) return FALSE; if( (type & MSG_MOTION) && ((type & MSG_MESSAGE) || (type & MSG_ACTION)) ) return FALSE; /* if it's signed, it *must* be one of MSG_MESSAGE or MSG_ACTION */ if( (type & MSG_SIGNED) && !((type & MSG_MESSAGE) || (type & MSG_ACTION)) ) return FALSE; /* FIXME: more sanity checks? */ return TRUE; } void silky_print(gint type, void *target, gchar *text, ...) { va_list varg; SilkyChannel *ch, *foundch = NULL; gint found; gchar str[4097]; if(!target) { debug("target == NULL"); return; } /* sanity checks first */ if(!is_valid_msg_type(type)) { debug("Invalid message type"); return; } if(type & MSG_PUBLIC) { /* we assume this message will go to a channel tab, because it's public */ found = 0; for(ch = channels; ch; ch = ch->next) { if( (SilcChannelEntry)target == ch->channel_entry ) { found++; foundch = ch; break; } } if(!found) { debug("Target for public message not found, returning."); return; } va_start(varg, text); g_vsnprintf(str, sizeof(str)-1, text, varg); va_end(varg); /* due to if(!found) check above, foundch will at this time will be non-NULL or we wouldn't be here */ silky_print_channel(type, foundch, str); return; } if(type & MSG_PRIVATE) { /* blah blah */ return; } } void silky_print_channel(gint type, SilkyChannel *channel, gchar *text) { gchar *str = g_strdup(text); /* motion (join, part, quit, ...) */ if(type & MSG_MOTION) str = g_strdup_printf(template_motion, str); /* signed */ if(type & MSG_SIGNED) str = g_strdup_printf(template_signed, "?", str); /* timestamp */ str = g_strdup_printf(template_timestamp, utf_timestamp(), str); /* append linefeed */ str = g_strdup_printf("%s\n", str); /* ask to print to the channel's textview widget */ silky_print_buffer( GTK_TEXT_VIEW(glade_xml_get_widget(channel->glade_xml, "textviewwidget")), str ); } /* print given text to given textview widget's buffer FIXME: THIS FUNCTION IS NOT YET IN USE */ void silky_print_buffer(GtkTextView *textview, gchar *text) { GtkTextBuffer *buffer; GtkTextIter iter; buffer = gtk_text_view_get_buffer(textview); gtk_text_buffer_insert (buffer, &iter, text, -1); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_create_mark(buffer, "end_mark", &iter, FALSE); gtk_text_view_scroll_to_mark(textview, gtk_text_buffer_get_mark(buffer, "end_mark"), 0.1, FALSE, 0,1); return; } /* this should update GUI when cmode changes;*/ void silky_gui_check_channel_cmodes(SilcChannelEntry channel_entry, gchar *cmode) { GtkWidget *wid_channel_topic = get_stored_channel_widget(channel_entry->channel_name, "channeltopic"); GtkWidget *wid_channel_topicbutton = get_stored_channel_widget(channel_entry->channel_name, "button_change_topic"); debug("checking '%s'", channel_entry->channel_name); /* enable/disable the topicbox, if appropriate */ if( !I_AM_OP(channel_entry) ) { if(channel_entry->mode & SILC_CHANNEL_MODE_TOPIC) { gtk_widget_set_sensitive(wid_channel_topic, FALSE); gtk_widget_set_sensitive(wid_channel_topicbutton, FALSE); } else { gtk_widget_set_sensitive(wid_channel_topic, TRUE); gtk_widget_set_sensitive(wid_channel_topicbutton, TRUE); } } } gint gui_tab_type(gint pagenr) { GtkWidget *notebook = glade_xml_get_widget(xmlmain, "tabs"); GtkWidget *tab = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), pagenr); /* gpointer *data = NULL; if(!pagenr) return TAB_TYPE_CONSOLE; if((data = g_object_get_data(G_OBJECT(tab), "channel_name"))) return TAB_TYPE_CHANNEL; if((data = g_object_get_data(G_OBJECT(tab), "clientid"))) return TAB_TYPE_QUERY; return TAB_TYPE_UNKNOWN; */ return (gint)g_object_get_data(G_OBJECT(tab), "tab_type"); } void gui_renumber_tabs() { GtkNotebook *tabs = GTK_NOTEBOOK(glade_xml_get_widget(xmlmain, "tabs")); gint i; gchar *chname; SilcClientEntry ce; debug("starting renumbering"); /* we'll skip tab 0, because it is our console and should not move */ for( i = 1; i < gtk_notebook_get_n_pages(tabs); i++ ) { switch(gui_tab_type(i)) { case TAB_TYPE_CHANNEL: debug("Tab #%d is a CHANNEL tab", i); chname = g_object_get_data(G_OBJECT(gtk_notebook_get_nth_page(tabs, i)), "channel_name"); channel_pagenr_set_by_name(chname, i); break; case TAB_TYPE_QUERY: debug("Tab #%d is a QUERY tab", i); ce = g_object_get_data(G_OBJECT(gtk_notebook_get_nth_page(tabs, i)), "cliententry"); query_pagenr_set_by_cliententry(ce, i); break; case TAB_TYPE_CONSOLE: debug("Tab #%d is a CONSOLE tab", i); break; case TAB_TYPE_UNKNOWN: debug("Tab #%d is !!UNKNOWN!! type, this should not be"); break; } } } /* call this to set color and font tags for given GtkTextView */ void set_textview_colors(GtkTextView *widget_textview) { gchar *value; GdkColor color; GtkTextBuffer *textview_buffer; PangoFontDescription *pangofont; GtkTextTagTable *tag_table; GtkTextTag *tag; gint j; GtkTextTag *tag_context_nick; /* map option names to tag names */ struct { gchar *tagname; gchar *option_name; } tag_opt_map[] = { { "timestamp", "color_timestamp" }, { "server_messages", "color_server_messages" }, { "nickname", "color_nickname" }, { "nickname-own", "color_my_nickname" }, { "message", "color_text" }, { "message-own", "color_my_text" }, { "action", "color_action" }, { "action-own", "color_my_action" }, { NULL, NULL } /* DON'T REMOVE THESE! */ }; debug("set_textview_colors() / setting PANGO style tags"); /* set font */ value = prefs_get("font"); debug("set_font = '%s'", value); if (value && strlen(value) > 1 ) { /* font name must be more than just a '\n' */ pangofont = pango_font_description_from_string(value); gtk_widget_modify_font(GTK_WIDGET(widget_textview), pangofont); /* set font */ } /* set background color */ value = prefs_get("color_background"); if(!g_ascii_strcasecmp(value, "default")) value = ""; debug("set_opt_background = '%s'", value); if (value && strlen(value) > 1 ) { /* color must be more than just a '\n' */ gdk_color_parse(value, &color); /* parse background color */ } else { gdk_color_parse("#ffffff", &color); /* set default bgcolor to white */ } gtk_widget_modify_base(GTK_WIDGET(widget_textview), GTK_STATE_NORMAL, &color); /* set color */ /* get text buffer for output */ textview_buffer = gtk_text_view_get_buffer(widget_textview); /* remove all previous tags */ tag_table = gtk_text_buffer_get_tag_table(textview_buffer); /* set colortags using tag_opt_map */ j = 0; while ( tag_opt_map[j].option_name && tag_opt_map[j].tagname) { value = prefs_get(tag_opt_map[j].option_name); if(!g_ascii_strcasecmp(value, "default")) value = ""; debug("* '%s' = '%s'", tag_opt_map[j].tagname, value); /* try to find old pango tag */ tag = gtk_text_tag_table_lookup(tag_table, tag_opt_map[j].tagname); if (tag) { /* found, replace it's value */ if (value && strlen(value) > 1 ) { /* color must be more than just a '\n' */ g_object_set( G_OBJECT(tag), "foreground", value, NULL ); /* override previous color */ } else { g_object_set( G_OBJECT(tag), "foreground", "#000000", NULL ); /* set default fg color to black */ } } else { /* create new tag */ if (value && strlen(value) > 1 ) { /* color must be more than just a '\n' */ /* create new fg color tag with color */ gtk_text_buffer_create_tag (textview_buffer, tag_opt_map[j].tagname, "style", PANGO_STYLE_NORMAL, "foreground", value, NULL); } else { /* create new black fg color tag, because there was no color given */ gtk_text_buffer_create_tag (textview_buffer, tag_opt_map[j].tagname, "style", PANGO_STYLE_NORMAL, "foreground", "#000000", NULL); } } j++; /* this is what I call progress ;) */ } /* while */ /* let's create other tags here too */ if( !gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(textview_buffer), "context-nick") ) { tag_context_nick = gtk_text_buffer_create_tag(textview_buffer, "context-nick", NULL); g_signal_connect (tag_context_nick, "event", G_CALLBACK (context_nick_event), NULL); } } gboolean on_nicktree_columns_changed( GtkTreeView *tv, gpointer data ) { debug("nicktree columns has changed"); return FALSE; } /* Shows a MODAL error dialog */ void errordialog(const char *errormessage) { GtkWindow *mainwin; GtkMessageDialog *dialog; mainwin = GTK_WINDOW(glade_xml_get_widget (xmlmain, "window_main")); dialog = GTK_MESSAGE_DIALOG( gtk_message_dialog_new (mainwin, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, errormessage) ); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (GTK_WIDGET(dialog)); return; } /* this function closes all tabs in UI except the first (console) tab */ void close_all_tabs( void ) { GtkWidget *notebook; int i, n; if( !(notebook = glade_xml_get_widget(xmlmain, "tabs")) ) { debug("could not retrieve notebook, bailing out"); return; } if( (n = gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook))) > 1 ) { debug("removing tabs left over from previous connection"); gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0); for( i = n; i > 0; i-- ) gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), i); } } /* this prints given message to the ACTIVE tab */ int printconsole (const char *str) { GtkTextView *textview = NULL; gchar *timestamp; gchar *outstring; GtkTextBuffer *buffer; GtkTextIter iter; /* pointer to current location */ GtkNotebook *storednotebook; GtkWidget *active_page; gint apagenr; gchar *channel_name; GladeXML *stored_query_xml; /* make sure it was utf8 */ if (!g_utf8_validate(str, -1, NULL)) { debug("Found non-utf8 string: '%s'", str); str = g_strdup("Non-utf8 string received. Can not display."); } timestamp = g_strdup_printf("[%s] ", utf_timestamp() ); outstring = g_strdup_printf("%s", str); /* see if there's active channel or query tab first */ storednotebook = GTK_NOTEBOOK(glade_xml_get_widget (xmlmain, "tabs")); apagenr = gtk_notebook_get_current_page(GTK_NOTEBOOK(storednotebook)); /* console or other type of tab? 0 is always console */ if (apagenr == 0) { /* console tab */ debug("active: CONSOLE"); textview = GTK_TEXT_VIEW(glade_xml_get_widget (xmlmain, "textviewwidget")); } else { /* other tab */ debug("active: other tab... looking for type..."); active_page = gtk_notebook_get_nth_page(storednotebook, apagenr); /* active pagenr from GTK */ if (!active_page) { debug("no page was active, this should not happen!"); return FALSE; } /* test if it was a channel tab */ channel_name = g_object_get_data(G_OBJECT(active_page), "channel_name"); if (channel_name) { debug("active CHANNEL"); textview = GTK_TEXT_VIEW(get_stored_channel_widget(channel_name, "textviewwidget")); } else { /* this way we can get the textview widget without knowing the clientid */ stored_query_xml = glade_get_widget_tree(active_page); textview = GTK_TEXT_VIEW(glade_xml_get_widget (stored_query_xml, "textviewwidget")); } } if (!textview) { debug("active NONE. no textview found!"); return FALSE; } buffer = gtk_text_view_get_buffer(textview); /* append \n */ outstring = g_strdup_printf("%s\n", outstring); /* debug("`%s'", outstring); */ /* Get the end of the buffer */ gtk_text_buffer_get_end_iter(buffer, &iter); /* Print the text */ /* timestamp */ gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, timestamp, -1, "timestamp", NULL); /* server message */ gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, outstring, -1, "server_messages", NULL); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_create_mark(buffer, "end_mark", &iter, FALSE); gtk_text_view_scroll_to_mark(textview, gtk_text_buffer_get_mark(buffer, "end_mark"), 0.1, FALSE, 0,1); g_free(timestamp); g_free(outstring); return TRUE; } void silky_show_user_info(SilkyUserInfo *user) { gchar **uhost = g_strsplit(user->username, "@", 2); gchar **nickserv = g_strsplit(user->nickname, "@", 2); SilcAttributePayload attr; SilcAttribute attribute; char tmp[512]; gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_nick")), nickserv[0]); gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_server")), nickserv[1]); gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_user")), uhost[0]); gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_host")), uhost[1]); gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_realname")), user->realname); gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_fp")), user->fingerprint); gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_channels")), user->channels); /* FIXME: parse attrs */ if(!user->attrs) { debug("No attributes to parse."); } else { silc_dlist_start(user->attrs); while ((attr = silc_dlist_get(user->attrs)) != SILC_LIST_END) { attribute = silc_attribute_get_attribute(attr); memset(tmp, 0, sizeof(tmp)); switch(attribute) { case SILC_ATTRIBUTE_TIMEZONE: if (!silc_attribute_get_object(attr, (void *)&tmp, sizeof(tmp) - 1)) continue; gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_userinfo_tz")), tmp); break; } } } /* show the dialog */ gtk_widget_show_all(glade_xml_get_widget(xmlmain, "dialog_userinfo")); /* The struct itself is supposed to be freed outside of this function, so it can be reused if necessary. */ } void silky_free_user_info(SilkyUserInfo *user) { if( !user ) { debug("SilkyUserInfo is NULL, ignoring."); return; } if(user->nickname) g_free(user->nickname); if(user->username) g_free(user->username); if(user->realname) g_free(user->realname); if(user->fingerprint) g_free(user->fingerprint); if(user->channels) g_free(user->channels); g_free(user); }