/*
Silky - A GTK+ client for SILC.
Copyright (C) 2003,2004 Toni Willberg
- Handlers for SILC_NOTIFY_* server messages
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>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "ui_buddylist.h"
#include "ui_channel.h"
#include "ui_console.h"
#include "common.h"
#include "support.h"
#include "gui.h"
#include "silc-notify.h"
#include "log.h"
#include "channel.h"
#include "callbacks.h"
extern silkyStruct *silky;
extern GladeXML *xmlmain;
extern gchar *previous_nick; /* my nickname just before sending NICK command */
extern gchar * glade_silky_channel;
extern gchar * glade_silky_channel_label;
extern SilkyChannel *channels;
extern gint lastpong;
void silc_notify(SilcClient client, SilcClientConnection conn,
SilcNotifyType type, ...)
{
SilcIdType idtype;
void *entry;
SilcClientEntry client_entry;
SilcClientEntry client_entry2;
SilcChannelEntry channel_entry = NULL;
SilcClientID *client_id;
SilcStatus status;
char *str;
gchar *str_clientid;
gchar *str_fingerprint;
GtkNotebook *storednotebook;
gchar *str_client_id;
gchar *str_client_id2;
GtkNotebook *notebook;
GtkWidget *stored_query_widget;
GtkWidget *wid_tab_label;
GladeXML *stored_query_xml;
GtkLabel *label_nickname;
GtkWidget *wid_channel_topic;
SilcUInt32 mode;
gchar *changer = NULL;
SilcServerEntry serverentry;
SilcChannelEntry channelentry;
gchar *str_mode;
SilcHashTableList souserhtl;
SilcChannelUser chu = NULL;
SilcBuffer channel_pubkeys;
SilcNotifyType notification;
va_list va;
debug("silc_notify()");
va_start(va, type);
lastpong = time(NULL); /* update date of last received data, used in timer.c */
/*
This is the part where we receive all kind of different data from the
server. silky is only interested in receiving the less important
stuff...
*/
switch(type) {
case SILC_NOTIFY_TYPE_NONE:
debug_info("SILC_NOTIFY_TYPE_NONE");
str = va_arg(va, char *);
printconsole(g_strdup_printf("%s", str));
break;
case SILC_NOTIFY_TYPE_MOTD:
debug_info("SILC_NOTIFY_TYPE_MOTD");
str = va_arg(va, char *);
printconsole(g_strdup_printf("%s", str));
break;
case SILC_NOTIFY_TYPE_ERROR:
status = va_arg(va, int );
debug_info("SILC_NOTIFY_TYPE_ERROR (%d)", status);
switch(status) {
/* After sending a private message; There was no such user */
case SILC_STATUS_ERR_NO_SUCH_CLIENT_ID:
debug_info("No such client id");
client_id = va_arg(va, SilcClientID *);
if (!client_id) {
debug("Did not get client_id in _NO_SUCH_CLIENT_ID");
}
str_clientid = silc_id_id2str(client_id, SILC_ID_CLIENT);
client_entry = silc_client_get_client_by_id(silky->client, silky->conn, client_id);
if (!client_entry) {
debug("Did not find client_entry");
}
else {
debug_info("\tnick: '%s'", client_entry->nickname);
}
printconsole(_("No such user."));
break;
default:
debug("Unhandled error");
break;
}
break;
case SILC_NOTIFY_TYPE_KICKED:
debug_info("SILC_NOTIFY_TYPE_KICKED");
client_entry = va_arg(va, SilcClientEntry);
str = va_arg(va, char *);
client_entry2 = va_arg(va, SilcClientEntry);
channel_entry = va_arg(va, SilcChannelEntry);
if (SILC_ID_COMPARE(client_entry->id, conn->local_entry->id, sizeof(SilcClientID) ) ) {
/* I GOT KICKED */
debug_info("I have been kicked out from the channel '%s'", channel_entry->channel_name);
/* Close the tab in UI */
storednotebook = GTK_NOTEBOOK(glade_xml_get_widget (xmlmain, "tabs"));
gtk_widget_destroy(get_stored_channel_window(channel_entry->channel_name));
g_object_set_data(G_OBJECT(storednotebook), channel_entry->channel_name, NULL);
/* check that all tabs are associated with correct data structures, since
their numbers may have changed */
gui_renumber_tabs();
/* remove from ch */
channel_remove_by_entry(channel_entry);
printconsole(g_strdup_printf(_("%s kicked me from channel '%s' with reason '%s'."),
client_entry2->nickname,
channel_entry->channel_name,
str));
}
else {
printchannel(channel_entry->channel_name, g_strdup_printf(_("%s kicked %s from from channel '%s' with reason '%s'."),
client_entry2->nickname, /* kicker */
client_entry->nickname, /* target */
channel_entry->channel_name,
str));
debug("freeing channel member from list...");
channel_member_remove_by_entry(channel_find_by_entry(channel_entry), client_entry);
/* refresh the nicklist */
refresh_gui_nicklist(channel_find_by_entry(channel_entry));
}
break;
case SILC_NOTIFY_TYPE_JOIN:
debug_info("SILC_NOTIFY_TYPE_JOIN");
client_entry = va_arg(va, SilcClientEntry);
channel_entry = va_arg(va, SilcChannelEntry);
debug_info("'%s' (%s@%s) joined '%s'", client_entry->nickname, client_entry->username, client_entry->hostname, channel_entry->channel_name);
printchannel(channel_entry->channel_name, g_strdup_printf(_("%s (%s@%s) has joined %s"), client_entry->nickname, client_entry->username, client_entry->hostname, channel_entry->channel_name));
/* not yet fully implemented, disabled for now
silky_print(MSG_MOTION | MSG_PUBLIC, channel_entry, "%s joined %s", client_entry->nickname, channel_entry->channel_name);
*/
/* Did I join? */
if (!SILC_ID_COMPARE(client_entry->id, conn->local_entry->id, sizeof(SilcClientID) ) ) {
debug("Added user to the nicklist.");
channel_member_add(channel_find_by_entry(channel_entry), get_channel_user_by_entry(channel_entry, client_entry));
refresh_gui_nicklist(channel_find_by_entry(channel_entry));
}
else {
debug("I joined. No need to add myself to the userlist.");
}
break;
case SILC_NOTIFY_TYPE_LEAVE:
debug_info("SILC_NOTIFY_TYPE_LEAVE");
client_entry = va_arg(va, SilcClientEntry);
channel_entry = va_arg(va, SilcChannelEntry);
debug_info("'%s' (%s@%s) left '%s'", client_entry->nickname, client_entry->username, client_entry->hostname, channel_entry->channel_name);
printchannel(channel_entry->channel_name, g_strdup_printf(_("%s (%s@%s) left %s"), client_entry->nickname, client_entry->username, client_entry->hostname, channel_entry->channel_name));
debug("freeing channel member from list...");
channel_member_remove_by_entry(channel_find_by_entry(channel_entry), client_entry);
/* Ask the client library to re-resolve the channel */
refresh_gui_nicklist(channel_find_by_entry(channel_entry));
break;
case SILC_NOTIFY_TYPE_NICK_CHANGE:
debug("SILC_NOTIFY_TYPE_NICK_CHANGE");
client_entry = va_arg(va, SilcClientEntry);
client_entry2 = va_arg(va, SilcClientEntry);
str_client_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
str_client_id2 = silc_id_id2str(client_entry2->id, SILC_ID_CLIENT);
debug_info("NICK_CHANGE: '%s' is now known as '%s'",
client_entry->nickname, client_entry2->nickname);
/* Update the clientid and nickname of the user to the GUI */
/* get notebook widget */
notebook = GTK_NOTEBOOK(glade_xml_get_widget (xmlmain, "tabs"));
/* get query widget, if any */
stored_query_widget = g_object_get_data(G_OBJECT(notebook), str_client_id);
if (stored_query_widget) {
/* remove the old clientid */
g_object_set_data(G_OBJECT(notebook), str_client_id, NULL);
/* make the new clientid to point to the old query widget */
g_object_set_data(G_OBJECT(notebook), str_client_id2, stored_query_widget);
g_object_set_data(G_OBJECT(stored_query_widget), "str_clientid", str_client_id2);
g_object_set_data(G_OBJECT(stored_query_widget), "clientid", client_entry2->id);
g_object_set_data(G_OBJECT(stored_query_widget), "cliententry", client_entry2);
/* get the tab widget for nickname */
wid_tab_label = g_object_get_data(G_OBJECT(stored_query_widget), "tablabel");
if (!wid_tab_label) {
debug("Did not find wid_tab_label");
}
/* Update the nickname into the top of query window */
stored_query_xml = glade_get_widget_tree(stored_query_widget);
label_nickname = GTK_LABEL(glade_xml_get_widget (stored_query_xml, "query_nickname"));
gtk_label_set_text(label_nickname, client_entry2->nickname);
/* Update the nickname into the tab label */
gtk_label_set_text(GTK_LABEL(wid_tab_label), client_entry2->nickname);
}
else {
debug("Did not get stored_query_widget. This means I have no query open with the user who just changed his nick.");
}
/* FIXME: update other widgets too */
/* This must be last */
/* Update the nicklist of channel in the GUI */
channels_nick_change(client_entry, client_entry->id, client_entry2);
break;
case SILC_NOTIFY_TYPE_TOPIC_SET:
debug_info("SILC_NOTIFY_TYPE_TOPIC_SET");
/* SilcIdType setter_id_type, void *setter_entry, char *topic, SilcChannelEntry channel */
idtype = va_arg(va, int);
entry = va_arg(va, void *);
str = va_arg(va, char *);
channel_entry = va_arg(va, SilcChannelEntry);
if (idtype == SILC_ID_CLIENT) {
client_entry = (SilcClientEntry)entry;
/* Set new topic to UI */
wid_channel_topic = get_stored_channel_widget(channel_entry->channel_name, "channeltopic");
gtk_entry_set_text(GTK_ENTRY(wid_channel_topic), str);
channel_topic_set_by_entry( channel_entry, str );
debug_info(channel_entry->channel_name, g_strdup_printf(_("%s (%s@%s) changed topic for channel %s to '%s'"),
client_entry->nickname, client_entry->username, client_entry->hostname, channel_entry->channel_name, str));
printchannel(channel_entry->channel_name, g_strdup_printf(_("%s (%s@%s) changed topic for channel %s to '%s'"),
client_entry->nickname, client_entry->username, client_entry->hostname, channel_entry->channel_name, str));
}
else {
printchannel(channel_entry->channel_name, _("UNHANDLED TOPIC SET EVENT: Please report a bug to Silky development team"));
}
break;
case SILC_NOTIFY_TYPE_CMODE_CHANGE:
debug_info("SILC_NOTIFY_TYPE_CMODE_CHANGE:");
/* get attributes from va_list */
idtype = va_arg(va, int); /* changer's id */
entry = va_arg(va, void *);
mode = va_arg(va, SilcUInt32);
(void)va_arg(va, char *); /* cipher_name */
(void)va_arg(va, char *); /* hmac_name */
(void)va_arg(va, char *); /* passphrase */
(void)va_arg(va, SilcPublicKey); /* founder_key */
channel_pubkeys = va_arg(va, SilcBuffer);
channel_entry = va_arg(va, SilcChannelEntry);
/* verify we got the channel_entry */
if (channel_entry == NULL) {
debug("No channel entry, skipping.");
return;
}
/* Set some UI stuff. */
str_mode = set_cmode_window_widgets(channel_entry->channel_name, mode); /* set modes in the UI */
channel_mode_set_by_entry( channel_entry, mode );
/* look up the type of the changer */
if (idtype == SILC_ID_CLIENT) {
client_entry2 = (SilcClientEntry)entry;
changer = client_entry2->nickname;
printchannel(channel_entry->channel_name, g_strdup_printf(_("%s (%s@%s) changed mode on channel '%s' to %s"), changer, client_entry2->username, client_entry2->hostname, channel_entry->channel_name, str_mode));
}
if (idtype == SILC_ID_SERVER) {
serverentry = (SilcServerEntry)entry;
changer = serverentry->server_name;
printchannel(channel_entry->channel_name, g_strdup_printf(_("%s changed mode on channel '%s' to %s"), changer, channel_entry->channel_name, str_mode));
}
if (idtype == SILC_ID_CHANNEL) {
channelentry = (SilcChannelEntry)entry;
changer = channelentry->channel_name;
printchannel(channel_entry->channel_name, g_strdup_printf(_("Mode on '%s' is now '%s'"), channel_entry->channel_name, str_mode));
}
silky_gui_check_channel_cmodes(channel_entry, str_mode);
debug_info("*** '%s' changed mode '%s' on '%s'", changer, str_mode, channel_entry->channel_name);
break;
case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
debug_info("SILC_NOTIFY_TYPE_CUMODE_CHANGE:");
idtype = va_arg(va, int);
entry = va_arg(va, void *);
mode = va_arg(va, unsigned int);
client_entry = va_arg(va, SilcClientEntry);
channel_entry = va_arg(va, SilcChannelEntry);
/*
Refresh UI
*/
if (!channel_entry) {
debug("No channel entry, skipping.");
return;
}
/* Update GUI nicklist */
refresh_gui_nicklist(channel_find_by_entry(channel_entry));
/* look up the type of the changer */
if (idtype == SILC_ID_CLIENT) {
client_entry2 = (SilcClientEntry)entry;
changer = client_entry2->nickname;
}
if (idtype == SILC_ID_SERVER) {
serverentry = (SilcServerEntry)entry;
changer = serverentry->server_name;
}
if (idtype == SILC_ID_CHANNEL) {
channelentry = (SilcChannelEntry)entry;
changer = channelentry->channel_name;
}
/* set all modes cleared */
str_mode = g_strdup(""); /* clear dynamic string */
/* generate mode string for UI */
if (mode & SILC_CHANNEL_UMODE_NONE) {
str_mode = g_strdup("none");
}
if (mode & SILC_CHANNEL_UMODE_CHANFO) {
str_mode = g_strconcat(str_mode, "f", NULL);
}
/* CHANOP */
if (mode & SILC_CHANNEL_UMODE_CHANOP) {
str_mode = g_strconcat(str_mode, "o", NULL);
/* if I got CHANOP, let me change the topic... */
if (client_entry == silky->conn->local_entry) {
debug("I got @");
/* "change topic" -button */
wid_channel_topic = get_stored_channel_widget(channel_entry->channel_name, "button_change_topic");
gtk_widget_set_sensitive(wid_channel_topic, TRUE);
/* text input */
wid_channel_topic = get_stored_channel_widget(channel_entry->channel_name, "channeltopic");
gtk_widget_set_sensitive(wid_channel_topic, TRUE);
}
}
else {
/* if I lost CHANOP, don't let me change the topic... */
if (client_entry == silky->conn->local_entry) {
debug("I lost @");
/* "change topic" -button */
wid_channel_topic = get_stored_channel_widget(channel_entry->channel_name, "button_change_topic");
gtk_widget_set_sensitive(wid_channel_topic, FALSE);
/* text input */
wid_channel_topic = get_stored_channel_widget(channel_entry->channel_name, "channeltopic");
gtk_widget_set_sensitive(wid_channel_topic, FALSE);
}
}
if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) {
str_mode = g_strconcat(str_mode, "b", NULL);
}
if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) {
str_mode = g_strconcat(str_mode, "u", NULL);
}
if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) {
str_mode = g_strconcat(str_mode, "r", NULL);
}
if (mode & SILC_CHANNEL_UMODE_QUIET) {
str_mode = g_strconcat(str_mode, "q", NULL);
}
debug_info("*** '%s' changed mode '%s' for '%s' on '%s'", changer, str_mode, client_entry->nickname, channel_entry->channel_name);
printchannel(channel_entry->channel_name, g_strdup_printf(_("%s changed mode for '%s' on '%s' to %s"),
changer, client_entry->nickname, channel_entry->channel_name, str_mode));
break;
/* INVITE: SilcClientChannel channel, char *channel_name, SilcClientEntry inviter */
case SILC_NOTIFY_TYPE_INVITE:
debug_info("SILC_NOTIFY_TYPE_INVITE:");
channel_entry = va_arg(va, SilcChannelEntry);
str = va_arg(va, char *);
client_entry = va_arg(va, SilcClientEntry);
debug_info("I was invited to channel '%s' by '%s (%s@%s)", str, client_entry->nickname, client_entry->username, client_entry->hostname);
printconsole(g_strdup_printf(_("%s (%s@%s) invites you to channel %s."), client_entry->nickname, client_entry->username, client_entry->hostname, str));
gtk_label_set_markup(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_recinv_topic")),
g_strdup_printf("<b>Join channel '%s'?</b>", str));
gtk_label_set_markup(GTK_LABEL(glade_xml_get_widget(xmlmain, "label_recinv_text")),
g_strdup_printf(_("You were invited by %s\n(%s@%s)"),
client_entry->nickname, client_entry->username, client_entry->hostname));
gtk_widget_show(glade_xml_get_widget(xmlmain, "dialog_received_invite"));
g_signal_connect(glade_xml_get_widget(xmlmain, "button_received_invite_show_user_info"), "activate", G_CALLBACK(on_received_invite_user_info), client_entry);
g_signal_connect(glade_xml_get_widget(xmlmain, "button_received_invite_show_user_info"), "released", G_CALLBACK(on_received_invite_user_info), client_entry);
/* store channelname, so dialog 'Yes' callback function can access it */
g_object_set_data(G_OBJECT(glade_xml_get_widget(xmlmain, "dialog_received_invite")), "invited_channel", g_strdup(str));
break;
/* SIGNOFF */
case SILC_NOTIFY_TYPE_SIGNOFF:
debug_info("SILC_NOTIFY_TYPE_SIGNOFF:");
client_entry = va_arg(va, SilcClientEntry); /* user */
str = va_arg(va, char *); /* reason */
if (!client_entry) {
debug("Did not get client_entry");
return;
}
debug_info("User: '%s' quitted with reason '%s'", client_entry->nickname, str);
debug("Starting iteration of userchannels");
/* if the user was on some channel we are too */
if (client_entry->channels) {
silc_hash_table_list(client_entry->channels, &souserhtl); /* init list */
debug("hash_table initialized");
/* loop through all channels of this user */
while (silc_hash_table_get(&souserhtl, NULL, (void *)&chu )) {
debug("'%s' (%s@%s) signed off from '%s' (%s)", client_entry->nickname, client_entry->username, client_entry->hostname, chu->channel->channel_name, str);
debug("freeing channel member from list...");
channel_member_remove_by_entry(channel_find_by_entry(chu->channel), client_entry);
/* print to the channel tab */
printchannel(chu->channel->channel_name, g_strdup_printf(_("%s (%s@%s) has signed off (%s)"), client_entry->nickname, client_entry->username, client_entry->hostname, str));
/* remove user from the lists, not sure if this is safe?! FIXME */
silc_hash_table_del(chu->client->channels, chu->channel);
silc_hash_table_del(chu->channel->user_list, chu->client);
/* refresh the UI */
refresh_gui_nicklist(channel_find_by_entry(chu->channel));
}
silc_hash_table_list_reset(&souserhtl); /* reset the list */
debug("Iteration done.");
}
else {
debug_message("Got NULL client_entry->channels. This must be a bug in the SILC Client library.");
}
break;
/* WATCH */
case SILC_NOTIFY_TYPE_WATCH:
/* SilcClientEntry watched_client, char *new_nickname, SilcUInt32 user_mode, SilcNotifyType notification */
debug_info("SILC_NOTIFY_TYPE_WATCH");
client_entry = va_arg(va, SilcClientEntry);
str = va_arg(va, char *);
mode = va_arg(va, SilcUInt32);
notification = va_arg(va, int);
str_fingerprint = silc_fingerprint(client_entry->fingerprint, client_entry->fingerprint_len);
buddy_set_clientid_by_fp(str_fingerprint, client_entry->id);
switch (notification) {
case SILC_NOTIFY_TYPE_NICK_CHANGE:
debug_info("SILC_NOTIFY_TYPE_NICK_CHANGE");
debug_info("WATCH '%s' is now known as '%s'", str_fingerprint, client_entry->nickname);
if (buddy_set_nick_by_fp(str_fingerprint, client_entry->nickname)) {
refresh_gui_buddylist();
} else {
debug("fingerprint not found from the buddy list");
}
break;
case SILC_NOTIFY_TYPE_UMODE_CHANGE:
debug_info("SILC_NOTIFY_TYPE_UMODE_CHANGE");
debug_info("WATCH '%s' has changed umode %d", client_entry->nickname, mode);
if (buddy_set_mode_by_fp(silc_fingerprint(client_entry->fingerprint, client_entry->fingerprint_len), mode)) {
debug("mode set in the buddy list");
refresh_gui_buddylist();
} else {
debug("user not found in the buddy list");
}
break;
default:
debug_info("unhandled notification type: %d", notification);
break;
}
break;
/* UNHANDLED NOTIFIES */
default:
debug_message("unhandled SILC_NOTIFY_TYPE (%d)", type);
break;
}
va_end(va);
debug("returning");
}
syntax highlighted by Code2HTML, v. 0.9.1