+ va_start(va, type);
+
+ server = conn == NULL ? NULL : conn->context;
+
+ switch(type) {
+ case SILC_NOTIFY_TYPE_NONE:
+ /* Some generic notice from server */
+ printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
+ break;
+
+ case SILC_NOTIFY_TYPE_INVITE:
+ /*
+ * Invited or modified invite list.
+ */
+
+ SILC_LOG_DEBUG(("Notify: INVITE"));
+
+ channel = va_arg(va, SilcChannelEntry);
+ name = va_arg(va, char *);
+ client_entry = va_arg(va, SilcClientEntry);
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message invite", 4, server, channel ? channel->channel_name :
+ name, client_entry->nickname, buf);
+ break;
+
+ case SILC_NOTIFY_TYPE_JOIN:
+ /*
+ * Joined channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: JOIN"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ if (client_entry == server->conn->local_entry) {
+ /* You joined to channel */
+ chanrec = silc_channel_find(server, channel->channel_name);
+ if (chanrec != NULL && !chanrec->joined)
+ chanrec->entry = channel;
+ } else {
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
+ if (chu)
+ nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
+ }
+ }
+
+ memset(buf, 0, sizeof(buf));
+ if (client_entry->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message join", 4, server, channel->channel_name,
+ client_entry->nickname,
+ client_entry->username == NULL ? "" : buf);
+ break;
+
+ case SILC_NOTIFY_TYPE_LEAVE:
+ /*
+ * Left a channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: LEAVE"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ memset(buf, 0, sizeof(buf));
+ if (client_entry->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message part", 5, server, channel->channel_name,
+ client_entry->nickname, client_entry->username ?
+ buf : "", client_entry->nickname);
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ nickrec = silc_nicklist_find(chanrec, client_entry);
+ if (nickrec != NULL)
+ nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_SIGNOFF:
+ /*
+ * Left the network.
+ */
+
+ SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ tmp = va_arg(va, char *);
+
+ silc_server_free_ftp(server, client_entry);
+
+ /* Print only if we have the nickname. If this cliente has just quit
+ when we were only resolving it, it is possible we don't have the
+ nickname. */
+ if (client_entry->nickname) {
+ memset(buf, 0, sizeof(buf));
+ if (client_entry->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message quit", 4, server, client_entry->nickname,
+ client_entry->username ? buf : "",
+ tmp ? tmp : "");
+ }
+
+ list1 = nicklist_get_same_unique(SERVER(server), client_entry);
+ for (list_tmp = list1; list_tmp != NULL; list_tmp =
+ list_tmp->next->next) {
+ CHANNEL_REC *channel = list_tmp->data;
+ NICK_REC *nickrec = list_tmp->next->data;
+
+ nicklist_remove(channel, nickrec);
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_TOPIC_SET:
+ /*
+ * Changed topic.
+ */
+
+ SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
+
+ idtype = va_arg(va, int);
+ entry = va_arg(va, void *);
+ tmp = va_arg(va, char *);
+ channel = va_arg(va, SilcChannelEntry);
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ char tmp2[256], *cp, *dm = NULL;
+
+ g_free_not_null(chanrec->topic);
+ if (tmp && !silc_term_utf8() && silc_utf8_valid(tmp, strlen(tmp))) {
+ memset(tmp2, 0, sizeof(tmp2));
+ cp = tmp2;
+ if (strlen(tmp) > sizeof(tmp2) - 1) {
+ dm = silc_calloc(strlen(tmp) + 1, sizeof(*dm));
+ cp = dm;
+ }
+
+ silc_utf8_decode(tmp, strlen(tmp), SILC_STRING_LANGUAGE,
+ cp, strlen(tmp));
+ tmp = cp;
+ }
+
+ chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
+ signal_emit("channel topic changed", 1, chanrec);
+
+ silc_free(dm);
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry = (SilcClientEntry)entry;
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry->username, client_entry->hostname);
+ signal_emit("message topic", 5, server, channel->channel_name,
+ tmp, client_entry->nickname, buf);
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ signal_emit("message topic", 5, server, channel->channel_name,
+ tmp, server_entry->server_name,
+ server_entry->server_name);
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel = (SilcChannelEntry)entry;
+ signal_emit("message topic", 5, server, channel->channel_name,
+ tmp, channel->channel_name, channel->channel_name);
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_NICK_CHANGE:
+ /*
+ * Changed nickname.
+ */
+
+ SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ client_entry2 = va_arg(va, SilcClientEntry);
+
+ if (!strcmp(client_entry->nickname, client_entry2->nickname))
+ break;
+
+ memset(buf, 0, sizeof(buf));
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ client_entry2->username, client_entry2->hostname);
+ nicklist_rename_unique(SERVER(server),
+ client_entry, client_entry->nickname,
+ client_entry2, client_entry2->nickname);
+ signal_emit("message nick", 4, server, client_entry2->nickname,
+ client_entry->nickname, buf);
+ break;
+
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ /*
+ * Changed channel mode.
+ */
+
+ SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+
+ idtype = va_arg(va, int);
+ entry = va_arg(va, void *);
+ mode = va_arg(va, SilcUInt32);
+ (void)va_arg(va, char *); /* cipher */
+ (void)va_arg(va, char *); /* hmac */
+ (void)va_arg(va, char *); /* passphrase */
+ (void)va_arg(va, SilcPublicKey); /* founder key */
+ buffer = va_arg(va, SilcBuffer); /* channel public keys */
+ channel = va_arg(va, SilcChannelEntry);
+
+ tmp = silc_client_chmode(mode,
+ channel->channel_key ?
+ silc_cipher_get_name(channel->channel_key) : "",
+ channel->hmac ?
+ silc_hmac_get_name(channel->hmac) : "");
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ g_free_not_null(chanrec->mode);
+ chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
+ signal_emit("channel mode changed", 1, chanrec);
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+ channel->channel_name, tmp ? tmp : "removed all",
+ client_entry->nickname);
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+ channel->channel_name, tmp ? tmp : "removed all",
+ server_entry->server_name);
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel2 = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+ channel->channel_name, tmp ? tmp : "removed all",
+ channel2->channel_name);
+ }
+
+ /* Print the channel public key list */
+ if (buffer)
+ silc_parse_channel_public_keys(server, channel, buffer);
+
+ silc_free(tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ /*
+ * Changed user's mode on channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
+
+ idtype = va_arg(va, int);
+ entry = va_arg(va, void *);
+ mode = va_arg(va, SilcUInt32);
+ client_entry2 = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ tmp = silc_client_chumode(mode);
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ SILC_NICK_REC *nick;
+
+ if (client_entry2 == server->conn->local_entry)
+ chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+
+ nick = silc_nicklist_find(chanrec, client_entry2);
+ if (nick != NULL) {
+ nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+ nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
+ signal_emit("nick mode changed", 2, chanrec, nick);
+ }
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
+ channel->channel_name, client_entry2->nickname,
+ tmp ? tmp : "removed all",
+ client_entry->nickname);
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
+ channel->channel_name, client_entry2->nickname,
+ tmp ? tmp : "removed all",
+ server_entry->server_name);
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel2 = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
+ channel->channel_name, client_entry2->nickname,
+ tmp ? tmp : "removed all",
+ channel2->channel_name);
+ }
+
+ if (mode & SILC_CHANNEL_UMODE_CHANFO)
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_FOUNDER,
+ channel->channel_name, client_entry2->nickname);
+
+ if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
+ printformat_module("fe-common/silc",
+ server, channel->channel_name, MSGLEVEL_CRAP,
+ SILCTXT_CHANNEL_QUIETED, channel->channel_name);
+
+ silc_free(tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_MOTD:
+ /*
+ * Received MOTD.
+ */
+
+ SILC_LOG_DEBUG(("Notify: MOTD"));
+
+ tmp = va_arg(va, char *);
+
+ if (!settings_get_bool("skip_motd"))
+ printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_KICKED:
+ /*
+ * Someone was kicked from channel.
+ */
+
+ SILC_LOG_DEBUG(("Notify: KICKED"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ tmp = va_arg(va, char *);
+ client_entry2 = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ chanrec = silc_channel_find_entry(server, channel);
+
+ if (client_entry == conn->local_entry) {
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
+ channel->channel_name,
+ client_entry ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+ if (chanrec) {
+ chanrec->kicked = TRUE;
+ channel_destroy((CHANNEL_REC *)chanrec);
+ }
+ } else {
+ printformat_module("fe-common/silc", server, channel->channel_name,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
+ client_entry->nickname, channel->channel_name,
+ client_entry2 ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+
+ if (chanrec) {
+ SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
+ if (nickrec != NULL)
+ nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
+ }
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_KILLED:
+ /*
+ * Someone was killed from the network.
+ */
+
+ SILC_LOG_DEBUG(("Notify: KILLED"));
+
+ client_entry = va_arg(va, SilcClientEntry);
+ tmp = va_arg(va, char *);
+ idtype = va_arg(va, int);
+ entry = va_arg(va, SilcClientEntry);
+
+ if (client_entry == conn->local_entry) {
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry2 = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
+ client_entry2 ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
+ server_entry->server_name, tmp ? tmp : "");
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
+ channel->channel_name, tmp ? tmp : "");
+ }
+ } else {
+ list1 = nicklist_get_same_unique(SERVER(server), client_entry);
+ for (list_tmp = list1; list_tmp != NULL; list_tmp =
+ list_tmp->next->next) {
+ CHANNEL_REC *channel = list_tmp->data;
+ NICK_REC *nickrec = list_tmp->next->data;
+ nicklist_remove(channel, nickrec);
+ }
+
+ if (idtype == SILC_ID_CLIENT) {
+ client_entry2 = (SilcClientEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
+ client_entry->nickname,
+ client_entry2 ? client_entry2->nickname : "",
+ tmp ? tmp : "");
+ } else if (idtype == SILC_ID_SERVER) {
+ server_entry = (SilcServerEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
+ client_entry->nickname,
+ server_entry->server_name, tmp ? tmp : "");
+ } else if (idtype == SILC_ID_CHANNEL) {
+ channel = (SilcChannelEntry)entry;
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
+ client_entry->nickname,
+ channel->channel_name, tmp ? tmp : "");
+ }
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+ break;
+
+ case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+ {
+ /*
+ * Server has quit the network.
+ */
+ int i;
+ SilcClientEntry *clients;
+ SilcUInt32 clients_count;
+
+ SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
+ (void)va_arg(va, void *);
+ clients = va_arg(va, SilcClientEntry *);
+ clients_count = va_arg(va, SilcUInt32);
+
+ for (i = 0; i < clients_count; i++) {
+ memset(buf, 0, sizeof(buf));
+
+ /* Print only if we have the nickname. If this client has just quit
+ when we were only resolving it, it is possible we don't have the
+ nickname. */
+ if (clients[i]->nickname) {
+ if (clients[i]->username)
+ snprintf(buf, sizeof(buf) - 1, "%s@%s",
+ clients[i]->username, clients[i]->hostname);
+ signal_emit("message quit", 4, server, clients[i]->nickname,
+ clients[i]->username ? buf : "",
+ "server signoff");
+ }
+
+ silc_server_free_ftp(server, clients[i]);
+
+ list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
+ for (list_tmp = list1; list_tmp != NULL; list_tmp =
+ list_tmp->next->next) {
+ CHANNEL_REC *channel = list_tmp->data;
+ NICK_REC *nickrec = list_tmp->next->data;
+ nicklist_remove(channel, nickrec);
+ }
+ }
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_ERROR:
+ {
+ SilcStatus error = va_arg(va, int);
+
+ silc_say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_get_status_message(error));
+ }
+ break;
+
+ case SILC_NOTIFY_TYPE_WATCH:
+ {
+ SilcNotifyType notify;
+
+ client_entry = va_arg(va, SilcClientEntry);
+ name = va_arg(va, char *); /* Maybe NULL */
+ mode = va_arg(va, SilcUInt32);
+ notify = va_arg(va, int);
+
+ if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
+ if (name)
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_NICK_CHANGE,
+ client_entry->nickname, name);
+ else
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
+ client_entry->nickname);
+ } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
+ /* See if client was away and is now present */
+ if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
+ SILC_UMODE_BUSY | SILC_UMODE_PAGE |
+ SILC_UMODE_DETACHED)) &&
+ (client_entry->mode & SILC_UMODE_GONE ||
+ client_entry->mode & SILC_UMODE_INDISPOSED ||
+ client_entry->mode & SILC_UMODE_BUSY ||
+ client_entry->mode & SILC_UMODE_PAGE ||
+ client_entry->mode & SILC_UMODE_DETACHED)) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
+ client_entry->nickname);
+ }
+
+ if (mode) {
+ memset(buf, 0, sizeof(buf));
+ silc_get_umode_string(mode, buf, sizeof(buf) - 1);
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_UMODE_CHANGE,
+ client_entry->nickname, buf);
+ }
+ } else if (notify == SILC_NOTIFY_TYPE_KILLED) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_KILLED,
+ client_entry->nickname);
+ } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
+ notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF) {
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_SIGNOFF,
+ client_entry->nickname);
+ } else if (notify == SILC_NOTIFY_TYPE_NONE) {
+ /* Client logged in to the network */
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_WATCH_PRESENT,
+ client_entry->nickname);
+ }
+ }
+ break;
+
+ default:
+ /* Unknown notify */
+ printformat_module("fe-common/silc", server, NULL,
+ MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
+ break;
+ }
+
+ va_end(va);
+}
+
+/* Called to indicate that connection was either successfully established
+ or connecting failed. This is also the first time application receives
+ the SilcClientConnection object which it should save somewhere. */
+
+void silc_connect(SilcClient client, SilcClientConnection conn,
+ SilcClientConnectionStatus status)
+{
+ SILC_SERVER_REC *server = conn->context;
+
+ if (!server || server->disconnected) {
+ silc_client_close_connection(client, conn);
+ return;
+ }
+
+ switch (status) {
+ case SILC_CLIENT_CONN_SUCCESS:
+ /* We have successfully connected to server */
+ if ((client->nickname != NULL) &&
+ (strcmp(client->nickname, client->username)))
+ silc_queue_enable(conn); /* enable queueing until we have our nick */
+ server->connected = TRUE;
+ signal_emit("event connected", 1, server);
+ break;
+
+ case SILC_CLIENT_CONN_SUCCESS_RESUME:
+ /* We have successfully resumed old detached session */
+ server->connected = TRUE;
+ signal_emit("event connected", 1, server);
+
+ /* If we resumed old session check whether we need to update
+ our nickname */
+ if (strcmp(server->nick, conn->local_entry->nickname)) {
+ char *old;
+ old = g_strdup(server->nick);
+ server_change_nick(SERVER(server), conn->local_entry->nickname);
+ nicklist_rename_unique(SERVER(server),
+ conn->local_entry, server->nick,
+ conn->local_entry, conn->local_entry->nickname);
+ signal_emit("message own_nick", 4, server, server->nick, old, "");
+ g_free(old);
+ }
+
+ /* remove the detach data now */
+ {
+ char *file;
+
+ file = silc_get_session_filename(server);
+
+ unlink(file);
+ silc_free(file);
+ }
+ break;
+
+ default:
+ {
+ char * file;