updates.
[silc.git] / apps / irssi / src / silc / core / silc-servers.c
1 /*
2  silc-server.c : irssi
3
4     Copyright (C) 2000 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "module.h"
22
23 #include "net-nonblock.h"
24 #include "net-sendbuffer.h"
25 #include "signals.h"
26 #include "servers.h"
27 #include "commands.h"
28 #include "levels.h"
29 #include "modules.h"
30 #include "rawlog.h"
31 #include "misc.h"
32 #include "settings.h"
33
34 #include "servers-setup.h"
35
36 #include "silc-servers.h"
37 #include "silc-channels.h"
38 #include "silc-queries.h"
39 #include "window-item-def.h"
40
41 #include "fe-common/core/printtext.h"
42
43 void silc_servers_reconnect_init(void);
44 void silc_servers_reconnect_deinit(void);
45
46 static void silc_send_channel(SILC_SERVER_REC *server,
47                               char *channel, char *msg)
48 {
49   SILC_CHANNEL_REC *rec;
50   
51   rec = silc_channel_find(server, channel);
52   if (rec == NULL)
53     return;
54   
55   silc_client_send_channel_message(silc_client, server->conn, rec->entry, 
56                                    NULL, 0, msg, strlen(msg), TRUE);
57 }
58
59 typedef struct {
60         char *nick;
61         char *msg;
62 } PRIVMSG_REC;
63
64 static void silc_send_msg_clients(SilcClient client,
65                                   SilcClientConnection conn,
66                                   SilcClientEntry *clients,
67                                   uint32 clients_count,
68                                   void *context)
69 {
70   PRIVMSG_REC *rec = context;
71   SilcClientEntry target;
72   
73   if (clients_count == 0) {
74     printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
75               "Unknown nick: %s", rec->nick);
76   } else {
77     target = clients[0]; /* FIXME: not a good idea :) */
78     
79     silc_client_send_private_message(client, conn, target, 0,
80                                      rec->msg, strlen(rec->msg),
81                                      TRUE);
82   }
83   
84   g_free(rec->nick);
85   g_free(rec->msg);
86   g_free(rec);
87 }
88
89 static void silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg)
90 {
91   PRIVMSG_REC *rec;
92   
93   rec = g_new0(PRIVMSG_REC, 1);
94   rec->nick = g_strdup(nick);
95   rec->msg = g_strdup(msg);
96   
97   silc_client_get_clients(silc_client, server->conn,
98                           nick, "", silc_send_msg_clients, rec);
99 }
100
101 static int isnickflag_func(char flag)
102 {
103         return flag == '@' || flag == '+';
104 }
105
106 static int ischannel_func(const char *data)
107 {
108         return *data == '#';
109 }
110
111 const char *get_nick_flags(void)
112 {
113         return "@\0\0";
114 }
115
116 static void send_message(SILC_SERVER_REC *server, char *target, char *msg)
117 {
118         g_return_if_fail(server != NULL);
119         g_return_if_fail(target != NULL);
120         g_return_if_fail(msg != NULL);
121
122         if (*target == '#')
123                 silc_send_channel(server, target, msg);
124         else
125                 silc_send_msg(server, target, msg);
126 }
127
128 static void sig_connected(SILC_SERVER_REC *server)
129 {
130         SilcClientConnection conn;
131         int fd;
132
133         if (!IS_SILC_SERVER(server))
134                 return;
135
136         conn = silc_client_add_connection(silc_client,
137                                           server->connrec->address,
138                                           server->connrec->port,
139                                           server);
140         server->conn = conn;
141
142         fd = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
143         if (!silc_client_start_key_exchange(silc_client, conn, fd)) {
144                 /* some internal error occured */
145                 server_disconnect(SERVER(server));
146                 signal_stop();
147                 return;
148         }
149
150         server->isnickflag = isnickflag_func;
151         server->ischannel = ischannel_func;
152         server->get_nick_flags = get_nick_flags;
153         server->send_message = (void *) send_message;
154 }
155
156 static void sig_disconnected(SILC_SERVER_REC *server)
157 {
158   if (!IS_SILC_SERVER(server) || server->conn == NULL)
159     return;
160   
161   if (server->conn->sock != NULL) {
162     silc_client_close_connection(silc_client, NULL, server->conn);
163     
164     /* SILC closes the handle */
165     g_io_channel_unref(net_sendbuffer_handle(server->handle));
166     net_sendbuffer_destroy(server->handle, FALSE);
167     server->handle = NULL;
168   }
169 }
170
171 SILC_SERVER_REC *silc_server_connect(SILC_SERVER_CONNECT_REC *conn)
172 {
173         SILC_SERVER_REC *server;
174
175         g_return_val_if_fail(IS_SILC_SERVER_CONNECT(conn), NULL);
176         if (conn->address == NULL || *conn->address == '\0') return NULL;
177         if (conn->nick == NULL || *conn->nick == '\0') return NULL;
178
179         server = g_new0(SILC_SERVER_REC, 1);
180         server->chat_type = SILC_PROTOCOL;
181         server->connrec = conn;
182         if (server->connrec->port <= 0) server->connrec->port = 706;
183
184         if (!server_start_connect((SERVER_REC *) server)) {
185                 server_connect_free(SERVER_CONNECT(conn));
186                 g_free(server);
187                 return NULL;
188         }
189
190         return server;
191 }
192
193 /* Return a string of all channels in server in
194    server->channels_join() format */
195 char *silc_server_get_channels(SILC_SERVER_REC *server)
196 {
197         GSList *tmp;
198         GString *chans;
199         char *ret;
200
201         g_return_val_if_fail(server != NULL, FALSE);
202
203         chans = g_string_new(NULL);
204         for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
205                 CHANNEL_REC *channel = tmp->data;
206
207                 g_string_sprintfa(chans, "%s,", channel->name);
208         }
209
210         if (chans->len > 0)
211                 g_string_truncate(chans, chans->len-1);
212
213         ret = chans->str;
214         g_string_free(chans, FALSE);
215
216         return ret;
217 }
218
219 void silc_command_exec(SILC_SERVER_REC *server,
220                        const char *command, const char *args)
221 {
222         uint32 argc = 0;
223         unsigned char **argv;
224         uint32 *argv_lens, *argv_types;
225         char *data, *tmpcmd;
226         SilcClientCommand *cmd;
227         SilcClientCommandContext ctx;
228
229         g_return_if_fail(server != NULL);
230
231         tmpcmd = g_strdup(command); g_strup(tmpcmd);
232         cmd = silc_client_command_find(tmpcmd);
233         g_free(tmpcmd);
234         if (cmd == NULL) return;
235
236         /* Now parse all arguments */
237         data = g_strconcat(command, " ", args, NULL);
238         silc_parse_command_line(data, &argv, &argv_lens,
239                                 &argv_types, &argc, cmd->max_args);
240         g_free(data);
241
242         /* Allocate command context. This and its internals must be free'd
243            by the command routine receiving it. */
244         ctx = silc_client_command_alloc();
245         ctx->client = silc_client;
246         ctx->conn = server->conn;
247         ctx->command = cmd;
248         ctx->argc = argc;
249         ctx->argv = argv;
250         ctx->argv_lens = argv_lens;
251         ctx->argv_types = argv_types;
252
253         /* Execute command */
254         (*cmd->cb)(ctx);
255 }
256
257 static void command_users(const char *data, SILC_SERVER_REC *server,
258                           WI_ITEM_REC *item)
259 {
260         signal_emit("command names", 3, data, server, item);
261 }
262
263 static void command_self(const char *data, SILC_SERVER_REC *server)
264 {
265         if (!IS_SILC_SERVER(server) || !server->connected)
266                 return;
267
268         silc_command_exec(server, current_command, data);
269         signal_stop();
270 }
271
272 static void event_motd(SILC_SERVER_REC *server, va_list va)
273 {
274         char *text = va_arg(va, char *);
275
276         if (!settings_get_bool("skip_motd"))
277                 printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", text);
278 }
279
280 static void event_text(const char *line, SILC_SERVER_REC *server,
281                        WI_ITEM_REC *item)
282 {
283         char *str;
284
285         g_return_if_fail(line != NULL);
286
287         if (!IS_SILC_ITEM(item))
288                 return;
289
290         str = g_strdup_printf("%s %s", item->name, line);
291         signal_emit("command msg", 3, str, server, item);
292         g_free(str);
293
294         signal_stop();
295 }
296
297 void silc_server_init(void)
298 {
299         silc_servers_reconnect_init();
300
301         signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
302         signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
303         signal_add("send text", (SIGNAL_FUNC) event_text);
304         signal_add("silc event motd", (SIGNAL_FUNC) event_motd);
305         command_bind("whois", MODULE_NAME, (SIGNAL_FUNC) command_self);
306         command_bind("nick", MODULE_NAME, (SIGNAL_FUNC) command_self);
307         command_bind("topic", MODULE_NAME, (SIGNAL_FUNC) command_self);
308         command_bind("cmode", MODULE_NAME, (SIGNAL_FUNC) command_self);
309         command_bind("cumode", MODULE_NAME, (SIGNAL_FUNC) command_self);
310         command_bind("users", MODULE_NAME, (SIGNAL_FUNC) command_users);
311
312         command_set_options("connect", "+silcnet");
313 }
314
315 void silc_server_deinit(void)
316 {
317         silc_servers_reconnect_deinit();
318
319         signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
320         signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
321         signal_remove("send text", (SIGNAL_FUNC) event_text);
322         signal_remove("silc event motd", (SIGNAL_FUNC) event_motd);
323         command_unbind("whois", (SIGNAL_FUNC) command_self);
324         command_unbind("nick", (SIGNAL_FUNC) command_self);
325         command_unbind("topic", (SIGNAL_FUNC) command_self);
326         command_unbind("cmode", (SIGNAL_FUNC) command_self);
327         command_unbind("cumode", (SIGNAL_FUNC) command_self);
328         command_unbind("users", (SIGNAL_FUNC) command_users);
329 }