5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "serverincludes.h"
23 #include "server_internal.h"
24 #include "command_reply.h"
26 #define COMMAND_CHECK_STATUS \
28 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
29 if (status != SILC_STATUS_OK) { \
30 silc_server_command_reply_free(cmd); \
35 #define COMMAND_CHECK_STATUS_LIST \
37 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
38 if (status != SILC_STATUS_OK && \
39 status != SILC_STATUS_LIST_START && \
40 status != SILC_STATUS_LIST_ITEM && \
41 status != SILC_STATUS_LIST_END) { \
42 silc_server_command_reply_free(cmd); \
47 /* Server command reply list. Not all commands have reply function as
48 they are never sent by server. More maybe added later if need appears. */
49 SilcServerCommandReply silc_command_reply_list[] =
51 SILC_SERVER_CMD_REPLY(join, JOIN),
52 SILC_SERVER_CMD_REPLY(whois, WHOIS),
53 SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
58 /* Process received command reply. */
60 void silc_server_command_reply_process(SilcServer server,
61 SilcSocketConnection sock,
64 SilcServerCommandReply *cmd;
65 SilcServerCommandReplyContext ctx;
66 SilcCommandPayload payload;
70 SILC_LOG_DEBUG(("Start"));
72 /* Get command reply payload from packet */
73 payload = silc_command_payload_parse(buffer);
75 /* Silently ignore bad reply packet */
76 SILC_LOG_DEBUG(("Bad command reply packet"));
80 /* Allocate command reply context. This must be free'd by the
81 command reply routine receiving it. */
82 ctx = silc_calloc(1, sizeof(*ctx));
85 ctx->payload = payload;
86 ctx->args = silc_command_get_args(ctx->payload);
87 ident = silc_command_get_ident(ctx->payload);
89 /* Check for pending commands and mark to be exeucted */
90 silc_server_command_pending_check(server, ctx,
91 silc_command_get(ctx->payload), ident);
93 /* Execute command reply */
94 command = silc_command_get(ctx->payload);
95 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
96 if (cmd->cmd == command)
107 /* Free command reply context and its internals. */
109 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
112 silc_command_free_payload(cmd->payload);
117 /* Caches the received WHOIS information. If we are normal server currently
118 we cache global information only for short period of time. */
119 /* XXX cache expirying not implemented yet! */
122 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
124 SilcServer server = cmd->server;
126 unsigned char *id_data;
127 char *nickname, *username, *realname;
128 SilcClientID *client_id;
129 SilcClientEntry client;
130 SilcIDCacheEntry cache = NULL;
134 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
135 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
136 username = silc_argument_get_arg_type(cmd->args, 4, &len);
137 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
138 if (!id_data || !nickname || !username || !realname)
141 client_id = silc_id_payload_parse_id(id_data, id_len);
143 /* Check if we have this client cached already. */
145 client = silc_idlist_find_client_by_id(server->local_list, client_id,
148 client = silc_idlist_find_client_by_id(server->global_list,
154 /* If router did not find such Client ID in its lists then this must
155 be bogus client or some router in the net is buggy. */
156 if (server->server_type == SILC_ROUTER)
159 /* Take hostname out of nick string if it includes it. */
160 if (strchr(nickname, '@')) {
161 int len = strcspn(nickname, "@");
162 nick = silc_calloc(len + 1, sizeof(char));
163 memcpy(nick, nickname, len);
165 nick = strdup(nickname);
168 /* We don't have that client anywhere, add it. The client is added
169 to global list since server didn't have it in the lists so it must be
171 silc_idlist_add_client(server->global_list, nick,
173 strdup(realname), client_id, NULL, NULL);
175 /* We have the client already, update the data */
177 SILC_LOG_DEBUG(("Updating client data"));
179 /* Take hostname out of nick string if it includes it. */
180 if (strchr(nickname, '@')) {
181 int len = strcspn(nickname, "@");
182 nick = silc_calloc(len + 1, sizeof(char));
183 memcpy(nick, nickname, len);
185 nick = strdup(nickname);
188 if (client->nickname)
189 silc_free(client->nickname);
190 if (client->username)
191 silc_free(client->username);
192 if (client->userinfo)
193 silc_free(client->userinfo);
195 client->nickname = nick;
196 client->username = strdup(username);
197 client->userinfo = strdup(realname);
201 silc_idcache_sort_by_data(global ? server->global_list->clients :
202 server->local_list->clients);
205 silc_free(client_id);
211 /* Reiceved reply for WHOIS command. We sent the whois request to our
212 primary router, if we are normal server, and thus has now received reply
213 to the command. We will figure out what client originally sent us the
214 command and will send the reply to it. If we are router we will figure
215 out who server sent us the command and send reply to that one. */
217 SILC_SERVER_CMD_REPLY_FUNC(whois)
219 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
220 SilcCommandStatus status;
222 SILC_LOG_DEBUG(("Start"));
224 COMMAND_CHECK_STATUS_LIST;
226 if (!silc_server_command_reply_whois_save(cmd))
231 /* Process one identify reply */
232 if (status == SILC_STATUS_OK) {
236 if (status == SILC_STATUS_LIST_START) {
240 if (status == SILC_STATUS_LIST_ITEM) {
244 if (status == SILC_STATUS_LIST_END) {
248 /* Execute any pending commands */
249 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
252 silc_server_command_reply_free(cmd);
255 /* Caches the received IDENTIFY information. */
258 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
260 SilcServer server = cmd->server;
262 unsigned char *id_data;
263 char *nickname, *username;
264 SilcClientID *client_id;
265 SilcClientEntry client;
266 SilcIDCacheEntry cache = NULL;
270 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
271 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
272 username = silc_argument_get_arg_type(cmd->args, 4, &len);
276 client_id = silc_id_payload_parse_id(id_data, id_len);
278 /* Check if we have this client cached already. */
280 client = silc_idlist_find_client_by_id(server->local_list, client_id,
283 client = silc_idlist_find_client_by_id(server->global_list,
289 /* If router did not find such Client ID in its lists then this must
290 be bogus client or some router in the net is buggy. */
291 if (server->server_type == SILC_ROUTER)
294 /* Take hostname out of nick string if it includes it. */
296 if (strchr(nickname, '@')) {
297 int len = strcspn(nickname, "@");
298 nick = silc_calloc(len + 1, sizeof(char));
299 memcpy(nick, nickname, len);
301 nick = strdup(nickname);
305 /* We don't have that client anywhere, add it. The client is added
306 to global list since server didn't have it in the lists so it must be
308 silc_idlist_add_client(server->global_list, nick,
309 username ? strdup(username) : NULL, NULL,
310 client_id, NULL, NULL);
312 /* We have the client already, update the data */
314 SILC_LOG_DEBUG(("Updating client data"));
316 /* Take hostname out of nick string if it includes it. */
318 if (strchr(nickname, '@')) {
319 int len = strcspn(nickname, "@");
320 nick = silc_calloc(len + 1, sizeof(char));
321 memcpy(nick, nickname, len);
323 nick = strdup(nickname);
327 if (nickname && client->nickname) {
328 silc_free(client->nickname);
329 client->nickname = nick;
332 if (username && client->username) {
333 silc_free(client->username);
334 client->username = strdup(username);
337 if (nickname && cache) {
339 silc_idcache_sort_by_data(global ? server->global_list->clients :
340 server->local_list->clients);
343 silc_free(client_id);
349 /* Received reply for forwarded IDENTIFY command. We have received the
350 requested identify information now and we will cache it. After this we
351 will call the pending command so that the requestee gets the information
354 SILC_SERVER_CMD_REPLY_FUNC(identify)
356 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
357 SilcCommandStatus status;
359 SILC_LOG_DEBUG(("Start"));
361 COMMAND_CHECK_STATUS_LIST;
363 if (!silc_server_command_reply_identify_save(cmd))
368 if (status == SILC_STATUS_OK) {
372 if (status == SILC_STATUS_LIST_START) {
376 if (status == SILC_STATUS_LIST_ITEM) {
380 if (status == SILC_STATUS_LIST_END) {
384 /* Execute any pending commands */
385 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
388 silc_server_command_reply_free(cmd);
391 /* Received reply for forwarded JOIN command. Router has created or joined
392 the client to the channel. We save some channel information locally
395 SILC_SERVER_CMD_REPLY_FUNC(join)
397 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
398 SilcServer server = cmd->server;
399 SilcCommandStatus status;
401 SilcChannelEntry entry;
403 unsigned char *id_string;
404 char *channel_name, *tmp;
406 SILC_LOG_DEBUG(("Start"));
408 COMMAND_CHECK_STATUS;
410 /* Get channel name */
411 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
416 id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
420 channel_name = strdup(tmp);
421 id = silc_id_payload_parse_id(id_string, len);
423 /* XXX We should check that we have sent JOIN command to the router
424 in the first place. Also should check that we don't have the channel
425 already in the cache. These checks must be made because of possible
428 SILC_LOG_DEBUG(("Adding new channel %s id(%s)", channel_name,
429 silc_id_render(id, SILC_ID_CHANNEL)));
431 /* Add the channel to our local list. */
432 entry = silc_idlist_add_channel(server->local_list, channel_name,
433 SILC_CHANNEL_MODE_NONE, id,
434 server->router, NULL);
436 silc_free(channel_name);
441 //entry->global_users = TRUE;
443 /* Execute any pending commands */
444 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
447 silc_server_command_reply_free(cmd);