/*
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 <glib.h>
#include <glade/glade.h>
#include <gtk/gtk.h>
#include <silcincludes.h>
#include <silcclient.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#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("<b>Silky %s</b>", 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);
}
syntax highlighted by Code2HTML, v. 0.9.1