AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
-SUBDIRS = lib silcd silc doc includes
+SUBDIRS = lib silc silcd doc includes
dist-bzip: distdir
-chmod -R a+r $(distdir)
autoconf
echo "Running automake --gnu $am_opt ..."
automake --add-missing --gnu $am_opt
-
-conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso-c
AC_INIT(src)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(Irssi SILC, 0.7.98.3)
+AM_INIT_AUTOMAKE(Irssi-SILC, 0.7.98.3)
AM_MAINTAINER_MODE
+++ /dev/null
-/* automatically created by autogen.sh */
-#define IRSSI_VERSION "@VERSION@"
-#define IRSSI_VERSION_DATE "20010524"
--- /dev/null
+INCLUDES = $(GLIB_CFLAGS) -I$(IRSSI_INCLUDE) -I$(IRSSI_INCLUDE)/src
+
+SILC_INCLUDE=../../../..
+IRSSI_INCLUDE=../../..
+
+INCLUDES = \
+ $(GLIB_CFLAGS) \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -I$(IRSSI_INCLUDE) -I$(IRSSI_INCLUDE)/src \
+ -I$(IRSSI_INCLUDE)/src/core \
+ -I$(SILC_INCLUDE)/includes \
+ -I$(SILC_INCLUDE)/lib/silccore \
+ -I$(SILC_INCLUDE)/lib/silccrypt \
+ -I$(SILC_INCLUDE)/lib/silcmath \
+ -I$(SILC_INCLUDE)/lib/silcske \
+ -I$(SILC_INCLUDE)/lib/silcsim \
+ -I$(SILC_INCLUDE)/lib/silcutil \
+ -I$(SILC_INCLUDE)/lib/silcclient \
+ -I$(SILC_INCLUDE)/lib/silcmath/gmp \
+ -I$(SILC_INCLUDE)/lib/trq
+
+noinst_LIBRARIES=libsilc_core.a
+
+libsilc_core_a_SOURCES = \
+ silc-channels.c \
+ silc-core.c \
+ silc-nicklist.c \
+ silc-queries.c \
+ silc-servers.c \
+ silc-servers-reconnect.c
+
+noinst_HEADERS = \
+ module.h \
+ silc-channels.h \
+ silc-core.h \
+ silc-nicklist.h \
+ silc-queries.h \
+ silc-servers.h
--- /dev/null
+/*
+ silc-channels.c : irssi
+
+ Copyright (C) 2000-2001 Timo Sirainen
+
+ 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
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "commands.h"
+#include "levels.h"
+#include "misc.h"
+#include "channels-setup.h"
+#include "levels.h"
+
+#include "silc-channels.h"
+#include "silc-nicklist.h"
+
+#include "fe-common/core/printtext.h"
+
+SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
+ const char *name, int automatic)
+{
+ SILC_CHANNEL_REC *rec;
+
+ g_return_val_if_fail(server == NULL || IS_SILC_SERVER(server), NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ rec = g_new0(SILC_CHANNEL_REC, 1);
+ rec->chat_type = SILC_PROTOCOL;
+ rec->name = g_strdup(name);
+ rec->server = server;
+
+ channel_init((CHANNEL_REC *) rec, automatic);
+ return rec;
+}
+
+static void sig_channel_destroyed(SILC_CHANNEL_REC *channel)
+{
+ if (!IS_SILC_CHANNEL(channel))
+ return;
+
+ if (channel->server != NULL && !channel->left && !channel->kicked) {
+ /* destroying channel record without actually
+ having left the channel yet */
+ silc_command_exec(channel->server, "PART", channel->name);
+ }
+}
+
+static void silc_channels_join(SILC_SERVER_REC *server,
+ const char *channels, int automatic)
+{
+ char **list, **tmp, *channel;
+
+ list = g_strsplit(channels, ",", -1);
+ for (tmp = list; *tmp != NULL; tmp++) {
+ channel = **tmp == '#' ? g_strdup(*tmp) :
+ g_strconcat("#", *tmp, NULL);
+ silc_channel_create(server, channel, FALSE);
+ silc_command_exec(server, "JOIN", channel);
+ g_free(channel);
+ }
+ g_strfreev(list);
+}
+
+static void sig_connected(SILC_SERVER_REC *server)
+{
+ if (IS_SILC_SERVER(server))
+ server->channels_join = (void *) silc_channels_join;
+}
+
+SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
+ SilcChannelEntry entry)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(IS_SILC_SERVER(server), NULL);
+
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ SILC_CHANNEL_REC *rec = tmp->data;
+
+ if (rec->entry == entry)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static void event_join(SILC_SERVER_REC *server, va_list va)
+{
+ SILC_CHANNEL_REC *chanrec;
+ SILC_NICK_REC *nickrec;
+ SilcClientEntry client;
+ SilcChannelEntry channel;
+
+ client = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ if (client == 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 user;
+
+ silc_list_start(chanrec->entry->clients);
+ while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
+ if (user->client == client) {
+ nickrec = silc_nicklist_insert(chanrec, user, TRUE);
+ break;
+ }
+ }
+ }
+
+ signal_emit("message join", 4, server, channel->channel_name,
+ client->nickname,
+ client->username == NULL ? "" : client->username);
+}
+
+static void event_leave(SILC_SERVER_REC *server, va_list va)
+{
+ SILC_CHANNEL_REC *chanrec;
+ SILC_NICK_REC *nickrec;
+ SilcClientEntry client;
+ SilcChannelEntry channel;
+
+ client = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ signal_emit("message part", 5, server, channel->channel_name,
+ client->nickname,
+ client->username == NULL ? "" : client->username, "");
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ nickrec = silc_nicklist_find(chanrec, client);
+ if (nickrec != NULL)
+ nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
+ }
+}
+
+static void event_signoff(SILC_SERVER_REC *server, va_list va)
+{
+ SilcClientEntry client;
+ GSList *nicks, *tmp;
+
+ client = va_arg(va, SilcClientEntry);
+
+ signal_emit("message quit", 4, server, client->nickname,
+ client->username == NULL ? "" : client->username, "");
+
+ nicks = nicklist_get_same_unique(SERVER(server), client);
+ for (tmp = nicks; tmp != NULL; tmp = tmp->next->next) {
+ CHANNEL_REC *channel = tmp->data;
+ NICK_REC *nickrec = tmp->next->data;
+
+ nicklist_remove(channel, nickrec);
+ }
+}
+
+static void event_topic(SILC_SERVER_REC *server, va_list va)
+{
+ SILC_CHANNEL_REC *chanrec;
+ SilcClientEntry client;
+ SilcChannelEntry channel;
+ char *topic;
+
+ client = va_arg(va, SilcClientEntry);
+ topic = va_arg(va, char *);
+ channel = va_arg(va, SilcChannelEntry);
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ g_free_not_null(chanrec->topic);
+ chanrec->topic = *topic == '\0' ? NULL : g_strdup(topic);
+ signal_emit("channel topic changed", 1, chanrec);
+ }
+
+ signal_emit("message topic", 5, server, channel->channel_name,
+ topic, client->nickname, client->username);
+}
+
+static void event_invite(SILC_SERVER_REC *server, va_list va)
+{
+ SilcClientEntry client;
+ SilcChannelEntry channel;
+
+ client = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ signal_emit("message invite", 4, server, channel->channel_name,
+ client->nickname, client->username);
+}
+
+static void event_nick(SILC_SERVER_REC *server, va_list va)
+{
+ SilcClientEntry oldclient, newclient;
+
+ oldclient = va_arg(va, SilcClientEntry);
+ newclient = va_arg(va, SilcClientEntry);
+
+ nicklist_rename_unique(SERVER(server),
+ oldclient, oldclient->nickname,
+ newclient, newclient->nickname);
+
+ signal_emit("message nick", 4, server, newclient->nickname,
+ oldclient->nickname, newclient->username);
+}
+
+static void event_cmode(SILC_SERVER_REC *server, va_list va)
+{
+ SILC_CHANNEL_REC *chanrec;
+ SilcClientEntry client;
+ SilcChannelEntry channel;
+ char *mode;
+ uint32 modei;
+
+ client = va_arg(va, SilcClientEntry);
+ modei = va_arg(va, uint32);
+ channel = va_arg(va, SilcChannelEntry);
+ mode = silc_client_chmode(modei, channel);
+
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ g_free_not_null(chanrec->mode);
+ chanrec->mode = g_strdup(mode == NULL ? "" : mode);
+ signal_emit("channel mode changed", 1, chanrec);
+ }
+
+ /*signal_emit("message mode", 5, server, chanrec->name,
+ client->nickname, client->username, mode);*/
+ printtext(server, channel->channel_name, MSGLEVEL_MODES,
+ "mode/%s [%s] by %s", channel->channel_name, mode,
+ client->nickname);
+
+ g_free(mode);
+}
+
+static void event_cumode(SILC_SERVER_REC *server, va_list va)
+{
+ SILC_CHANNEL_REC *chanrec;
+ SilcClientEntry client, destclient;
+ SilcChannelEntry channel;
+ int mode;
+ char *modestr;
+
+ client = va_arg(va, SilcClientEntry);
+ mode = va_arg(va, uint32);
+ destclient = va_arg(va, SilcClientEntry);
+ channel = va_arg(va, SilcChannelEntry);
+
+ modestr = silc_client_chumode(mode);
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec != NULL) {
+ SILC_NICK_REC *nick;
+
+ if (destclient == server->conn->local_entry) {
+ chanrec->chanop =
+ (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+ }
+
+ nick = silc_nicklist_find(chanrec, client);
+ if (nick != NULL) {
+ nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+ signal_emit("nick mode changed", 2, chanrec, nick);
+ }
+ }
+
+ /*signal_emit("message mode", 5, server, chanrec->name,
+ client->nickname, client->username, modestr);*/
+ printtext(server, channel->channel_name, MSGLEVEL_MODES,
+ "mode/%s [%s] by %s", channel->channel_name, modestr,
+ client->nickname);
+
+ g_free(modestr);
+}
+
+static void command_part(const char *data, SILC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ SILC_CHANNEL_REC *chanrec;
+
+ if (!IS_SILC_SERVER(server) || !server->connected)
+ return;
+
+ if (*data == '\0') {
+ if (!IS_SILC_CHANNEL(item))
+ cmd_return_error(CMDERR_NOT_JOINED);
+ data = item->name;
+ }
+
+ chanrec = silc_channel_find(server, data);
+ if (chanrec == NULL) cmd_return_error(CMDERR_CHAN_NOT_FOUND);
+
+ signal_emit("message part", 5, server, chanrec->name,
+ server->nick, "", "");
+
+ silc_command_exec(server, "LEAVE", chanrec->name);
+ signal_stop();
+
+ channel_destroy(CHANNEL(chanrec));
+}
+
+void silc_channels_init(void)
+{
+ signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
+ signal_add("server connected", (SIGNAL_FUNC) sig_connected);
+
+ signal_add("silc event join", (SIGNAL_FUNC) event_join);
+ signal_add("silc event leave", (SIGNAL_FUNC) event_leave);
+ signal_add("silc event signoff", (SIGNAL_FUNC) event_signoff);
+ signal_add("silc event topic", (SIGNAL_FUNC) event_topic);
+ signal_add("silc event invite", (SIGNAL_FUNC) event_invite);
+ signal_add("silc event nick", (SIGNAL_FUNC) event_nick);
+ signal_add("silc event cmode", (SIGNAL_FUNC) event_cmode);
+ signal_add("silc event cumode", (SIGNAL_FUNC) event_cumode);
+
+ command_bind("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
+
+ silc_nicklist_init();
+}
+
+void silc_channels_deinit(void)
+{
+ signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed);
+ signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
+
+ signal_remove("silc event join", (SIGNAL_FUNC) event_join);
+ signal_remove("silc event leave", (SIGNAL_FUNC) event_leave);
+ signal_remove("silc event signoff", (SIGNAL_FUNC) event_signoff);
+ signal_remove("silc event topic", (SIGNAL_FUNC) event_topic);
+ signal_remove("silc event invite", (SIGNAL_FUNC) event_invite);
+ signal_remove("silc event nick", (SIGNAL_FUNC) event_nick);
+ signal_remove("silc event cmode", (SIGNAL_FUNC) event_cmode);
+ signal_remove("silc event cumode", (SIGNAL_FUNC) event_cumode);
+
+ command_unbind("part", (SIGNAL_FUNC) command_part);
+
+ silc_nicklist_deinit();
+}
--- /dev/null
+/*
+
+ silc-core.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 2001 Pekka Riikonen
+
+ 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.
+
+*/
+
+#include "module.h"
+#include "chat-protocols.h"
+
+#include "chatnets.h"
+#include "servers-setup.h"
+#include "channels-setup.h"
+#include "silc-servers.h"
+#include "silc-channels.h"
+#include "silc-queries.h"
+#include "silc-nicklist.h"
+#include "version_internal.h"
+
+#include "signals.h"
+#include "levels.h"
+#include "settings.h"
+#include "fe-common/core/printtext.h"
+#include "fe-common/core/fe-channels.h"
+
+#define SILC_CLIENT_PUBLIC_KEY_NAME "public_key.pub"
+#define SILC_CLIENT_PRIVATE_KEY_NAME "private_key.prv"
+
+#define SILC_CLIENT_DEF_PKCS "rsa"
+#define SILC_CLIENT_DEF_PKCS_LEN 1024
+
+SilcClient silc_client;
+const char *silc_version_string = SILC_PROTOCOL_VERSION_STRING;
+
+static int idletag;
+
+extern SilcClientOperations ops;
+
+static void silc_say(SilcClient client, SilcClientConnection conn,
+ char *msg, ...)
+{
+ SILC_SERVER_REC *server;
+ va_list va;
+ char *str;
+
+ server = conn == NULL ? NULL : conn->context;
+
+ va_start(va, msg);
+ str = g_strdup_vprintf(msg, va);
+ printtext(server, "#silc", MSGLEVEL_CRAP, "%s", str);
+ g_free(str);
+ va_end(va);
+}
+
+/* Message for a channel. The `sender' is the nickname of the sender
+ received in the packet. The `channel_name' is the name of the channel. */
+
+static void
+silc_channel_message(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry sender, SilcChannelEntry channel,
+ SilcMessageFlags flags, char *msg)
+{
+ SILC_SERVER_REC *server;
+ SILC_NICK_REC *nick;
+ SILC_CHANNEL_REC *chanrec;
+
+ server = conn == NULL ? NULL : conn->context;
+ chanrec = silc_channel_find_entry(server, channel);
+
+ nick = silc_nicklist_find(chanrec, sender);
+ signal_emit("message public", 6, server, msg,
+ nick == NULL ? "(unknown)" : nick->nick,
+ nick == NULL ? NULL : nick->host,
+ chanrec->name, nick);
+}
+
+/* Private message to the client. The `sender' is the nickname of the
+ sender received in the packet. */
+
+static void
+silc_private_message(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry sender, SilcMessageFlags flags,
+ char *msg)
+{
+ SILC_SERVER_REC *server;
+
+ server = conn == NULL ? NULL : conn->context;
+ signal_emit("message private", 4, server, msg,
+ sender->nickname ? sender->nickname : "(unknown)",
+ sender->username ? sender->username : NULL);
+}
+
+/* Notify message to the client. The notify arguments are sent in the
+ same order as servers sends them. The arguments are same as received
+ from the server except for ID's. If ID is received application receives
+ the corresponding entry to the ID. For example, if Client ID is received
+ application receives SilcClientEntry. Also, if the notify type is
+ for channel the channel entry is sent to application (even if server
+ does not send it). */
+
+typedef struct {
+ int type;
+ const char *name;
+} NOTIFY_REC;
+
+#define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
+static NOTIFY_REC notifies[] = {
+ { SILC_NOTIFY_TYPE_NONE, NULL },
+ { SILC_NOTIFY_TYPE_INVITE, "invite" },
+ { SILC_NOTIFY_TYPE_JOIN, "join" },
+ { SILC_NOTIFY_TYPE_LEAVE, "leave" },
+ { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" },
+ { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" },
+ { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" },
+ { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" },
+ { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" },
+ { SILC_NOTIFY_TYPE_MOTD, "motd" }
+};
+
+static void silc_notify(SilcClient client, SilcClientConnection conn,
+ SilcNotifyType type, ...)
+{
+ SILC_SERVER_REC *server;
+ va_list va;
+
+ server = conn == NULL ? NULL : conn->context;
+ va_start(va, type);
+
+ if (type == SILC_NOTIFY_TYPE_NONE) {
+ /* some generic notice from server */
+ printtext(server, NULL, MSGLEVEL_CRAP, "%s",
+ (char *) va_arg(va, char *));
+ } else if (type < MAX_NOTIFY) {
+ /* send signal about the notify event */
+ char signal[50];
+
+ g_snprintf(signal, sizeof(signal), "silc event %s",
+ notifies[type].name);
+ signal_emit(signal, 2, server, va);
+ } else {
+ /* unknown notify */
+ printtext(server, NULL, MSGLEVEL_CRAP,
+ "Unknown notify %d", type);
+ }
+ 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 objecet which it should save somewhere. */
+
+static void
+silc_connect(SilcClient client, SilcClientConnection conn, int success)
+{
+ SILC_SERVER_REC *server = conn->context;
+
+ if (success) {
+ server->connected = TRUE;
+ signal_emit("event connected", 1, server);
+ } else {
+ server->connection_lost = TRUE;
+ server->conn->context = NULL;
+ server_disconnect(SERVER(server));
+ }
+}
+
+/* Called to indicate that connection was disconnected to the server. */
+
+static void
+silc_disconnect(SilcClient client, SilcClientConnection conn)
+{
+ SILC_SERVER_REC *server = conn->context;
+
+ server->conn->context = NULL;
+ server->conn = NULL;
+ server->connection_lost = TRUE;
+ server_disconnect(SERVER(server));
+}
+
+/* Command handler. This function is called always in the command function.
+ If error occurs it will be called as well. `conn' is the associated
+ client connection. `cmd_context' is the command context that was
+ originally sent to the command. `success' is FALSE if error occured
+ during command. `command' is the command being processed. It must be
+ noted that this is not reply from server. This is merely called just
+ after application has called the command. Just to tell application
+ that the command really was processed. */
+
+static void
+silc_command(SilcClient client, SilcClientConnection conn,
+ SilcClientCommandContext cmd_context, int success,
+ SilcCommand command)
+{
+}
+
+/* Command reply handler. This function is called always in the command reply
+ function. If error occurs it will be called as well. Normal scenario
+ is that it will be called after the received command data has been parsed
+ and processed. The function is used to pass the received command data to
+ the application.
+
+ `conn' is the associated client connection. `cmd_payload' is the command
+ payload data received from server and it can be ignored. It is provided
+ if the application would like to re-parse the received command data,
+ however, it must be noted that the data is parsed already by the library
+ thus the payload can be ignored. `success' is FALSE if error occured.
+ In this case arguments are not sent to the application. `command' is the
+ command reply being processed. The function has variable argument list
+ and each command defines the number and type of arguments it passes to the
+ application (on error they are not sent). */
+
+static void
+silc_command_reply(SilcClient client, SilcClientConnection conn,
+ SilcCommandPayload cmd_payload, int success,
+ SilcCommand command, SilcCommandStatus status, ...)
+
+{
+ SILC_SERVER_REC *server = conn->context;
+ SILC_CHANNEL_REC *chanrec;
+ va_list va;
+
+ va_start(va, status);
+
+ /*g_snprintf(signal, sizeof(signal), "silc command reply %s",
+ silc_commands[type]);
+ signal_emit(signal, 2, server, va);*/
+
+ switch(command) {
+ case SILC_COMMAND_JOIN:
+ {
+ char *channel, *mode;
+ uint32 modei;
+ SilcChannelEntry channel_entry;
+
+ channel = va_arg(va, char *);
+ channel_entry = va_arg(va, SilcChannelEntry);
+ modei = va_arg(va, uint32);
+ mode = silc_client_chmode(modei, channel_entry);
+
+ chanrec = silc_channel_find(server, channel);
+ if (chanrec != NULL && !success)
+ channel_destroy(CHANNEL(chanrec));
+ else if (chanrec == NULL && success)
+ chanrec = silc_channel_create(server, channel, TRUE);
+
+ g_free_not_null(chanrec->mode);
+ chanrec->mode = g_strdup(mode == NULL ? "" : mode);
+ signal_emit("channel mode changed", 1, chanrec);
+ break;
+ }
+ case SILC_COMMAND_NICK:
+ {
+ SilcClientEntry client = va_arg(va, SilcClientEntry);
+ char *old;
+
+ old = g_strdup(server->nick);
+ server_change_nick(SERVER(server), client->nickname);
+ nicklist_rename_unique(SERVER(server),
+ server->conn->local_entry, server->nick,
+ client, client->nickname);
+
+ signal_emit("message own_nick", 4,
+ server, server->nick, old, "");
+ g_free(old);
+ break;
+ }
+ case SILC_COMMAND_USERS:
+ {
+ SilcChannelEntry channel;
+ SilcChannelUser user;
+ NICK_REC *ownnick;
+
+ channel = va_arg(va, SilcChannelEntry);
+ chanrec = silc_channel_find_entry(server, channel);
+ if (chanrec == NULL)
+ break;
+
+ silc_list_start(channel->clients);
+ while ((user = silc_list_get(channel->clients)) != NULL)
+ silc_nicklist_insert(chanrec, user, FALSE);
+
+ ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
+ nicklist_set_own(CHANNEL(chanrec), ownnick);
+ signal_emit("channel joined", 1, chanrec);
+ fe_channels_nicklist(CHANNEL(chanrec),
+ CHANNEL_NICKLIST_FLAG_ALL);
+ break;
+ }
+ }
+
+ va_end(va);
+}
+
+/* Verifies received public key. If user decides to trust the key it is
+ saved as public server key for later use. If user does not trust the
+ key this returns FALSE. */
+
+static int silc_verify_public_key(SilcClient client,
+ SilcClientConnection conn,
+ SilcSocketType conn_type,
+ unsigned char *pk, uint32 pk_len,
+ SilcSKEPKType pk_type)
+{
+ return TRUE;
+}
+
+/* Asks passphrase from user on the input line. */
+
+static unsigned char *silc_ask_passphrase(SilcClient client,
+ SilcClientConnection conn)
+{
+ return NULL;
+}
+
+/* Find authentication method and authentication data by hostname and
+ port. The hostname may be IP address as well. The found authentication
+ method and authentication data is returned to `auth_meth', `auth_data'
+ and `auth_data_len'. The function returns TRUE if authentication method
+ is found and FALSE if not. `conn' may be NULL. */
+
+static int
+silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+ char *hostname, uint16 port,
+ SilcProtocolAuthMeth *auth_meth,
+ unsigned char **auth_data,
+ uint32 *auth_data_len)
+{
+ return FALSE;
+}
+
+/* Notifies application that failure packet was received. This is called
+ if there is some protocol active in the client. The `protocol' is the
+ protocol context. The `failure' is opaque pointer to the failure
+ indication. Note, that the `failure' is protocol dependant and application
+ must explicitly cast it to correct type. Usually `failure' is 32 bit
+ failure type (see protocol specs for all protocol failure types). */
+
+static void
+silc_failure(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure)
+{
+ if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+ SilcSKEStatus status = (SilcSKEStatus)failure;
+
+ if (status == SILC_SKE_STATUS_BAD_VERSION)
+ silc_say(client, conn,
+ "You are running incompatible client version (it may be "
+ "too old or too new)");
+ if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
+ silc_say(client, conn, "Server does not support your public key type");
+ if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
+ silc_say(client, conn,
+ "Server does not support one of your proposed KE group");
+ if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
+ silc_say(client, conn,
+ "Server does not support one of your proposed cipher");
+ if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
+ silc_say(client, conn,
+ "Server does not support one of your proposed PKCS");
+ if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
+ silc_say(client, conn,
+ "Server does not support one of your proposed hash function");
+ if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
+ silc_say(client, conn,
+ "Server does not support one of your proposed HMAC");
+ if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
+ silc_say(client, conn, "Incorrect signature");
+ }
+
+ if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
+ uint32 err = (uint32)failure;
+
+ if (err == SILC_AUTH_FAILED)
+ silc_say(client, conn, "Authentication failed");
+ }
+}
+
+/* Asks whether the user would like to perform the key agreement protocol.
+ This is called after we have received an key agreement packet or an
+ reply to our key agreement packet. This returns TRUE if the user wants
+ the library to perform the key agreement protocol and FALSE if it is not
+ desired (application may start it later by calling the function
+ silc_client_perform_key_agreement). */
+
+static int
+silc_key_agreement(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry, char *hostname,
+ int port,
+ SilcKeyAgreementCallback *completion,
+ void **context)
+{
+ char host[256];
+
+ /* We will just display the info on the screen and return FALSE and user
+ will have to start the key agreement with a command. */
+
+ if (hostname) {
+ memset(host, 0, sizeof(host));
+ snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port);
+ }
+
+ silc_say(client, conn, "%s wants to perform key agreement %s",
+ client_entry->nickname, hostname ? host : "");
+
+ *completion = NULL;
+ *context = NULL;
+
+ return FALSE;
+}
+
+/* SILC client operations */
+SilcClientOperations ops = {
+ silc_say,
+ silc_channel_message,
+ silc_private_message,
+ silc_notify,
+ silc_command,
+ silc_command_reply,
+ silc_connect,
+ silc_disconnect,
+ silc_get_auth_method,
+ silc_verify_public_key,
+ silc_ask_passphrase,
+ silc_failure,
+ silc_key_agreement,
+};
+
+/* Loads public and private key from files. */
+
+static void silc_client_create_key_pair(char *pkcs_name, int bits,
+ char *identifier,
+ SilcPublicKey *pub_key,
+ SilcPrivateKey *prv_key)
+{
+ SilcPKCS pkcs;
+ SilcRng rng;
+ unsigned char *key;
+ uint32 key_len;
+
+ rng = silc_rng_alloc();
+ silc_rng_init(rng);
+ silc_rng_global_init(rng);
+
+ silc_pkcs_alloc(pkcs_name, &pkcs);
+ pkcs->pkcs->init(pkcs->context, bits, rng);
+
+ /* Create public key */
+ key = silc_pkcs_get_public_key(pkcs, &key_len);
+ *pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
+ key, key_len);
+
+ memset(key, 0, sizeof(key_len));
+ silc_free(key);
+
+ /* Create private key */
+ key = silc_pkcs_get_private_key(pkcs, &key_len);
+ *prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
+
+ memset(key, 0, sizeof(key_len));
+ silc_free(key);
+
+ silc_rng_free(rng);
+ silc_pkcs_free(pkcs);
+}
+
+static int read_keyfiles(SilcClient client, char *public_file,
+ char *private_file)
+{
+ struct stat statbuf;
+
+ if (stat(public_file, &statbuf) != 0 ||
+ stat(private_file, &statbuf) != 0)
+ return FALSE;
+
+ if (!silc_pkcs_load_private_key(private_file, &client->private_key,
+ SILC_PKCS_FILE_BIN) &&
+ !silc_pkcs_load_private_key(private_file, &client->private_key,
+ SILC_PKCS_FILE_PEM))
+ return FALSE;
+
+ if (!silc_pkcs_load_public_key(public_file, &client->public_key,
+ SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(public_file, &client->public_key,
+ SILC_PKCS_FILE_BIN))
+ return FALSE;
+
+ return TRUE;
+}
+
+static char *silc_create_identifier(SilcClient client)
+{
+ char hostname[256], *email, *ret;
+
+ if (gethostname(hostname, sizeof(hostname)) != 0)
+ hostname[0] = '\0';
+
+ email = g_strdup_printf("%s@%s", client->username, hostname);
+ ret = silc_pkcs_encode_identifier(client->username, hostname,
+ client->realname, email,
+ NULL, NULL);
+ g_free(email);
+ return ret;
+}
+
+static int load_keys(SilcClient client)
+{
+ char *public_file, *private_file;
+ char *identifier;
+
+ public_file = g_strdup_printf("%s/.irssi/%s", g_get_home_dir(),
+ SILC_CLIENT_PUBLIC_KEY_NAME);
+ private_file = g_strdup_printf("%s/.irssi/%s", g_get_home_dir(),
+ SILC_CLIENT_PRIVATE_KEY_NAME);
+
+ if (!read_keyfiles(client, public_file, private_file)) {
+ /* couldn't read key files, recreate them */
+ identifier = silc_create_identifier(client);
+ silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
+ SILC_CLIENT_DEF_PKCS_LEN,
+ identifier,
+ &client->public_key,
+ &client->private_key);
+ silc_free(identifier);
+
+ silc_pkcs_save_public_key(public_file, client->public_key,
+ SILC_PKCS_FILE_PEM);
+ silc_pkcs_save_private_key(private_file, client->private_key,
+ NULL, SILC_PKCS_FILE_BIN);
+ }
+
+ g_free(public_file);
+ g_free(private_file);
+ return TRUE;
+}
+
+static int my_silc_scheduler(void)
+{
+ silc_schedule_one(0);
+ return 1;
+}
+
+static CHATNET_REC *create_chatnet(void)
+{
+ return g_malloc0(sizeof(CHATNET_REC));
+}
+
+static SERVER_SETUP_REC *create_server_setup(void)
+{
+ return g_malloc0(sizeof(SERVER_SETUP_REC));
+}
+
+static CHANNEL_SETUP_REC *create_channel_setup(void)
+{
+ return g_malloc0(sizeof(CHANNEL_SETUP_REC));
+}
+
+static SERVER_CONNECT_REC *create_server_connect(void)
+{
+ return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC));
+}
+
+/* Command line option variables */
+void silc_core_init(void)
+{
+ CHAT_PROTOCOL_REC *rec;
+
+ silc_client = silc_client_alloc(&ops, NULL);
+ silc_client->username = g_strdup(settings_get_str("user_name"));
+ silc_client->hostname = silc_net_localhost();
+ silc_client->realname = g_strdup(settings_get_str("real_name"));
+
+ if (!load_keys(silc_client)) {
+ idletag = -1;
+ return;
+ }
+
+ silc_client_init(silc_client);
+
+ rec = g_new0(CHAT_PROTOCOL_REC, 1);
+ rec->name = "SILC";
+ rec->fullname = "Secure Internet Live Conferencing";
+ rec->chatnet = "silcnet";
+
+ rec->create_chatnet = create_chatnet;
+ rec->create_server_setup = create_server_setup;
+ rec->create_channel_setup = create_channel_setup;
+ rec->create_server_connect = create_server_connect;
+
+ rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *))
+ silc_server_connect;
+ rec->channel_create =
+ (CHANNEL_REC *(*) (SERVER_REC *, const char *, int))
+ silc_channel_create;
+ rec->query_create =
+ (QUERY_REC *(*) (const char *, const char *, int))
+ silc_query_create;
+
+ chat_protocol_register(rec);
+ g_free(rec);
+
+ silc_server_init();
+ silc_channels_init();
+ silc_queries_init();
+
+ idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL);
+}
+
+void silc_core_deinit(void)
+{
+ if (idletag != -1) {
+ signal_emit("chat protocol deinit", 1,
+ chat_protocol_find("SILC"));
+
+ silc_server_deinit();
+ silc_channels_deinit();
+ silc_queries_deinit();
+
+ chat_protocol_unregister("SILC");
+
+ g_source_remove(idletag);
+ }
+
+ g_free(silc_client->username);
+ g_free(silc_client->realname);
+ silc_client_free(silc_client);
+}
--- /dev/null
+/*
+ silc-server.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ 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
+*/
+
+#include "module.h"
+
+#include "net-nonblock.h"
+#include "net-sendbuffer.h"
+#include "signals.h"
+#include "servers.h"
+#include "commands.h"
+#include "levels.h"
+#include "modules.h"
+#include "rawlog.h"
+#include "misc.h"
+#include "settings.h"
+
+#include "servers-setup.h"
+
+#include "silc-servers.h"
+#include "silc-channels.h"
+#include "silc-queries.h"
+#include "window-item-def.h"
+
+#include "fe-common/core/printtext.h"
+
+void silc_servers_reconnect_init(void);
+void silc_servers_reconnect_deinit(void);
+
+static void silc_send_channel(SILC_SERVER_REC *server,
+ char *channel, char *msg)
+{
+ SILC_CHANNEL_REC *rec;
+
+ rec = silc_channel_find(server, channel);
+ if (rec == NULL)
+ return;
+
+ silc_client_send_channel_message(silc_client, server->conn, rec->entry,
+ NULL, 0, msg, strlen(msg), TRUE);
+}
+
+typedef struct {
+ char *nick;
+ char *msg;
+} PRIVMSG_REC;
+
+static void silc_send_msg_clients(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry *clients,
+ uint32 clients_count,
+ void *context)
+{
+ PRIVMSG_REC *rec = context;
+ SilcClientEntry target;
+
+ if (clients_count == 0) {
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ "Unknown nick: %s", rec->nick);
+ } else {
+ target = clients[0]; /* FIXME: not a good idea :) */
+
+ silc_client_send_private_message(client, conn, target, 0,
+ rec->msg, strlen(rec->msg),
+ TRUE);
+ }
+
+ g_free(rec->nick);
+ g_free(rec->msg);
+ g_free(rec);
+}
+
+static void silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg)
+{
+ PRIVMSG_REC *rec;
+
+ rec = g_new0(PRIVMSG_REC, 1);
+ rec->nick = g_strdup(nick);
+ rec->msg = g_strdup(msg);
+
+ silc_client_get_clients(silc_client, server->conn,
+ nick, "", silc_send_msg_clients, rec);
+}
+
+static int isnickflag_func(char flag)
+{
+ return flag == '@' || flag == '+';
+}
+
+static int ischannel_func(const char *data)
+{
+ return *data == '#';
+}
+
+const char *get_nick_flags(void)
+{
+ return "@\0\0";
+}
+
+static void send_message(SILC_SERVER_REC *server, char *target, char *msg)
+{
+ g_return_if_fail(server != NULL);
+ g_return_if_fail(target != NULL);
+ g_return_if_fail(msg != NULL);
+
+ if (*target == '#')
+ silc_send_channel(server, target, msg);
+ else
+ silc_send_msg(server, target, msg);
+}
+
+static void sig_connected(SILC_SERVER_REC *server)
+{
+ SilcClientConnection conn;
+ int fd;
+
+ if (!IS_SILC_SERVER(server))
+ return;
+
+ conn = silc_client_add_connection(silc_client,
+ server->connrec->address,
+ server->connrec->port,
+ server);
+ server->conn = conn;
+
+ fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
+ if (!silc_client_start_key_exchange(silc_client, conn, fd)) {
+ /* some internal error occured */
+ server_disconnect(SERVER(server));
+ signal_stop();
+ return;
+ }
+
+ server->isnickflag = isnickflag_func;
+ server->ischannel = ischannel_func;
+ server->get_nick_flags = get_nick_flags;
+ server->send_message = (void *) send_message;
+}
+
+static void sig_disconnected(SILC_SERVER_REC *server)
+{
+ if (!IS_SILC_SERVER(server) || server->conn == NULL)
+ return;
+
+ if (server->conn->sock != NULL) {
+ silc_client_close_connection(silc_client, NULL, server->conn);
+
+ /* SILC closes the handle */
+ g_io_channel_unref(net_sendbuffer_handle(server->handle));
+ net_sendbuffer_destroy(server->handle, FALSE);
+ server->handle = NULL;
+ }
+}
+
+SILC_SERVER_REC *silc_server_connect(SILC_SERVER_CONNECT_REC *conn)
+{
+ SILC_SERVER_REC *server;
+
+ g_return_val_if_fail(IS_SILC_SERVER_CONNECT(conn), NULL);
+ if (conn->address == NULL || *conn->address == '\0') return NULL;
+ if (conn->nick == NULL || *conn->nick == '\0') return NULL;
+
+ server = g_new0(SILC_SERVER_REC, 1);
+ server->chat_type = SILC_PROTOCOL;
+ server->connrec = conn;
+ if (server->connrec->port <= 0) server->connrec->port = 706;
+
+ if (!server_start_connect((SERVER_REC *) server)) {
+ server_connect_free(SERVER_CONNECT(conn));
+ g_free(server);
+ return NULL;
+ }
+
+ return server;
+}
+
+/* Return a string of all channels in server in
+ server->channels_join() format */
+char *silc_server_get_channels(SILC_SERVER_REC *server)
+{
+ GSList *tmp;
+ GString *chans;
+ char *ret;
+
+ g_return_val_if_fail(server != NULL, FALSE);
+
+ chans = g_string_new(NULL);
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ CHANNEL_REC *channel = tmp->data;
+
+ g_string_sprintfa(chans, "%s,", channel->name);
+ }
+
+ if (chans->len > 0)
+ g_string_truncate(chans, chans->len-1);
+
+ ret = chans->str;
+ g_string_free(chans, FALSE);
+
+ return ret;
+}
+
+void silc_command_exec(SILC_SERVER_REC *server,
+ const char *command, const char *args)
+{
+ uint32 argc = 0;
+ unsigned char **argv;
+ uint32 *argv_lens, *argv_types;
+ char *data, *tmpcmd;
+ SilcClientCommand *cmd;
+ SilcClientCommandContext ctx;
+
+ g_return_if_fail(server != NULL);
+
+ tmpcmd = g_strdup(command); g_strup(tmpcmd);
+ cmd = silc_client_command_find(tmpcmd);
+ g_free(tmpcmd);
+ if (cmd == NULL) return;
+
+ /* Now parse all arguments */
+ data = g_strconcat(command, " ", args, NULL);
+ silc_parse_command_line(data, &argv, &argv_lens,
+ &argv_types, &argc, cmd->max_args);
+ g_free(data);
+
+ /* Allocate command context. This and its internals must be free'd
+ by the command routine receiving it. */
+ ctx = silc_client_command_alloc();
+ ctx->client = silc_client;
+ ctx->conn = server->conn;
+ ctx->command = cmd;
+ ctx->argc = argc;
+ ctx->argv = argv;
+ ctx->argv_lens = argv_lens;
+ ctx->argv_types = argv_types;
+
+ /* Execute command */
+ (*cmd->cb)(ctx);
+}
+
+static void command_users(const char *data, SILC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ signal_emit("command names", 3, data, server, item);
+}
+
+static void command_self(const char *data, SILC_SERVER_REC *server)
+{
+ if (!IS_SILC_SERVER(server) || !server->connected)
+ return;
+
+ silc_command_exec(server, current_command, data);
+ signal_stop();
+}
+
+static void event_motd(SILC_SERVER_REC *server, va_list va)
+{
+ char *text = va_arg(va, char *);
+
+ if (!settings_get_bool("skip_motd"))
+ printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
+}
+
+static void event_text(const char *line, SILC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ char *str;
+
+ g_return_if_fail(line != NULL);
+
+ if (!IS_SILC_ITEM(item))
+ return;
+
+ str = g_strdup_printf("%s %s", item->name, line);
+ signal_emit("command msg", 3, str, server, item);
+ g_free(str);
+
+ signal_stop();
+}
+
+void silc_server_init(void)
+{
+ silc_servers_reconnect_init();
+
+ signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
+ signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
+ signal_add("send text", (SIGNAL_FUNC) event_text);
+ signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
+ command_bind("whois", MODULE_NAME, (SIGNAL_FUNC) command_self);
+ command_bind("nick", MODULE_NAME, (SIGNAL_FUNC) command_self);
+ command_bind("topic", MODULE_NAME, (SIGNAL_FUNC) command_self);
+ command_bind("cmode", MODULE_NAME, (SIGNAL_FUNC) command_self);
+ command_bind("cumode", MODULE_NAME, (SIGNAL_FUNC) command_self);
+ command_bind("users", MODULE_NAME, (SIGNAL_FUNC) command_users);
+
+ command_set_options("connect", "+silcnet");
+}
+
+void silc_server_deinit(void)
+{
+ silc_servers_reconnect_deinit();
+
+ signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
+ signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
+ signal_remove("send text", (SIGNAL_FUNC) event_text);
+ signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
+ command_unbind("whois", (SIGNAL_FUNC) command_self);
+ command_unbind("nick", (SIGNAL_FUNC) command_self);
+ command_unbind("topic", (SIGNAL_FUNC) command_self);
+ command_unbind("cmode", (SIGNAL_FUNC) command_self);
+ command_unbind("cumode", (SIGNAL_FUNC) command_self);
+ command_unbind("users", (SIGNAL_FUNC) command_users);
+}
#LIBS="$LIBS -lefence"
# Other configure scripts
-#AC_CONFIG_SUBDIRS(lib/zlib)
+AC_CONFIG_SUBDIRS(irssi)
AC_CONFIG_SUBDIRS(lib/dotconf)
AC_CONFIG_SUBDIRS(lib/silcmath/gmp)
AC_CONFIG_SUBDIRS(lib/trq)
+#AC_CONFIG_SUBDIRS(lib/zlib)
AC_OUTPUT( \
Makefile
echo "#define SILC_VERSION_STRING \"$version\"" >>$file
echo "#define SILC_PROTOCOL_VERSION_STRING \"SILC-1.0-$version\"" >>$file
+# preparing irssi
+if [ -d irssi ]; then
+ cd irssi
+ ./autogen.sh 2>/dev/null 1>/dev/null
+ cd ..
+ file=irssi/irssi-version.h
+ version_date=`date +%Y%m%d`
+ echo "/* automatically created by autogen.sh */" > $file
+ echo "#define IRSSI_VERSION \"$version (Irssi base: @VERSION@ - SILC base: SILC Toolkit $version)\"" >> $file
+ echo "#define IRSSI_VERSION_DATE \"$version_date\"" >> $file
+fi
+
echo "Done, now run ./configure and make."
rm -f aclocal.m4
rm -f config.status
rm -f configure
+if [ -d irssi ]; then
+ cd irssi
+ rm -f COPYING
+ rm -f INSTALL
+ rm -f Makefile.in
+ rm -f */Makefile.in
+ rm -f */*/Makefile.in
+ rm -f */*/*/Makefile.in
+ rm -f */*/*/*/Makefile.in
+ rm -f default-theme.h
+ rm -f libtool-shared
+ rm -f stamp-*
+ rm -f docs/startup*.txt
+ cd docs/help
+ cp Makefile.am.gen ..
+ rm -f * 2>/dev/null
+ mv ../Makefile.am.gen .
+ cd ../..
+ rm -f docs/help/in/Makefile.am
+fi
echo "Done."