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),
54 SILC_SERVER_CMD_REPLY(names, NAMES),
59 /* Process received command reply. */
61 void silc_server_command_reply_process(SilcServer server,
62 SilcSocketConnection sock,
65 SilcServerCommandReply *cmd;
66 SilcServerCommandReplyContext ctx;
67 SilcCommandPayload payload;
71 SILC_LOG_DEBUG(("Start"));
73 /* Get command reply payload from packet */
74 payload = silc_command_payload_parse(buffer);
76 /* Silently ignore bad reply packet */
77 SILC_LOG_DEBUG(("Bad command reply packet"));
81 /* Allocate command reply context. This must be free'd by the
82 command reply routine receiving it. */
83 ctx = silc_calloc(1, sizeof(*ctx));
86 ctx->payload = payload;
87 ctx->args = silc_command_get_args(ctx->payload);
88 ident = silc_command_get_ident(ctx->payload);
90 /* Check for pending commands and mark to be exeucted */
91 silc_server_command_pending_check(server, ctx,
92 silc_command_get(ctx->payload), ident);
94 /* Execute command reply */
95 command = silc_command_get(ctx->payload);
96 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
97 if (cmd->cmd == command)
100 if (cmd == NULL || !cmd->cb) {
108 /* Free command reply context and its internals. */
110 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
113 silc_command_free_payload(cmd->payload);
118 /* Caches the received WHOIS information. If we are normal server currently
119 we cache global information only for short period of time. */
120 /* XXX cache expirying not implemented yet! */
123 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
125 SilcServer server = cmd->server;
127 unsigned char *id_data;
128 char *nickname, *username, *realname;
129 SilcClientID *client_id;
130 SilcClientEntry client;
131 SilcIDCacheEntry cache = NULL;
135 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
136 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
137 username = silc_argument_get_arg_type(cmd->args, 4, &len);
138 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
139 if (!id_data || !nickname || !username || !realname)
142 client_id = silc_id_payload_parse_id(id_data, id_len);
144 /* Check if we have this client cached already. */
146 client = silc_idlist_find_client_by_id(server->local_list, client_id,
149 client = silc_idlist_find_client_by_id(server->global_list,
155 /* If router did not find such Client ID in its lists then this must
156 be bogus client or some router in the net is buggy. */
157 if (server->server_type == SILC_ROUTER)
160 /* Take hostname out of nick string if it includes it. */
161 if (strchr(nickname, '@')) {
162 int len = strcspn(nickname, "@");
163 nick = silc_calloc(len + 1, sizeof(char));
164 memcpy(nick, nickname, len);
166 nick = strdup(nickname);
169 /* We don't have that client anywhere, add it. The client is added
170 to global list since server didn't have it in the lists so it must be
172 silc_idlist_add_client(server->global_list, nick,
174 strdup(realname), client_id, NULL, NULL);
176 /* We have the client already, update the data */
178 SILC_LOG_DEBUG(("Updating client data"));
180 /* Take hostname out of nick string if it includes it. */
181 if (strchr(nickname, '@')) {
182 int len = strcspn(nickname, "@");
183 nick = silc_calloc(len + 1, sizeof(char));
184 memcpy(nick, nickname, len);
186 nick = strdup(nickname);
189 if (client->nickname)
190 silc_free(client->nickname);
191 if (client->username)
192 silc_free(client->username);
193 if (client->userinfo)
194 silc_free(client->userinfo);
196 client->nickname = nick;
197 client->username = strdup(username);
198 client->userinfo = strdup(realname);
202 silc_idcache_sort_by_data(global ? server->global_list->clients :
203 server->local_list->clients);
206 silc_free(client_id);
212 /* Reiceved reply for WHOIS command. We sent the whois request to our
213 primary router, if we are normal server, and thus has now received reply
214 to the command. We will figure out what client originally sent us the
215 command and will send the reply to it. If we are router we will figure
216 out who server sent us the command and send reply to that one. */
218 SILC_SERVER_CMD_REPLY_FUNC(whois)
220 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
221 SilcCommandStatus status;
223 SILC_LOG_DEBUG(("Start"));
225 COMMAND_CHECK_STATUS_LIST;
227 if (!silc_server_command_reply_whois_save(cmd))
232 /* Process one identify reply */
233 if (status == SILC_STATUS_OK) {
237 if (status == SILC_STATUS_LIST_START) {
241 if (status == SILC_STATUS_LIST_ITEM) {
245 if (status == SILC_STATUS_LIST_END) {
249 /* Execute any pending commands */
250 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
253 silc_server_command_reply_free(cmd);
256 /* Caches the received IDENTIFY information. */
259 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
261 SilcServer server = cmd->server;
263 unsigned char *id_data;
264 char *nickname, *username;
265 SilcClientID *client_id;
266 SilcClientEntry client;
267 SilcIDCacheEntry cache = NULL;
271 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
272 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
273 username = silc_argument_get_arg_type(cmd->args, 4, &len);
277 client_id = silc_id_payload_parse_id(id_data, id_len);
279 /* Check if we have this client cached already. */
281 client = silc_idlist_find_client_by_id(server->local_list, client_id,
284 client = silc_idlist_find_client_by_id(server->global_list,
290 /* If router did not find such Client ID in its lists then this must
291 be bogus client or some router in the net is buggy. */
292 if (server->server_type == SILC_ROUTER)
295 /* Take hostname out of nick string if it includes it. */
297 if (strchr(nickname, '@')) {
298 int len = strcspn(nickname, "@");
299 nick = silc_calloc(len + 1, sizeof(char));
300 memcpy(nick, nickname, len);
302 nick = strdup(nickname);
306 /* We don't have that client anywhere, add it. The client is added
307 to global list since server didn't have it in the lists so it must be
309 silc_idlist_add_client(server->global_list, nick,
310 username ? strdup(username) : NULL, NULL,
311 client_id, NULL, NULL);
313 /* We have the client already, update the data */
315 SILC_LOG_DEBUG(("Updating client data"));
317 /* Take hostname out of nick string if it includes it. */
319 if (strchr(nickname, '@')) {
320 int len = strcspn(nickname, "@");
321 nick = silc_calloc(len + 1, sizeof(char));
322 memcpy(nick, nickname, len);
324 nick = strdup(nickname);
328 if (nickname && client->nickname) {
329 silc_free(client->nickname);
330 client->nickname = nick;
333 if (username && client->username) {
334 silc_free(client->username);
335 client->username = strdup(username);
338 if (nickname && cache) {
340 silc_idcache_sort_by_data(global ? server->global_list->clients :
341 server->local_list->clients);
344 silc_free(client_id);
350 /* Received reply for forwarded IDENTIFY command. We have received the
351 requested identify information now and we will cache it. After this we
352 will call the pending command so that the requestee gets the information
355 SILC_SERVER_CMD_REPLY_FUNC(identify)
357 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
358 SilcCommandStatus status;
360 SILC_LOG_DEBUG(("Start"));
362 COMMAND_CHECK_STATUS_LIST;
364 if (!silc_server_command_reply_identify_save(cmd))
369 if (status == SILC_STATUS_OK) {
373 if (status == SILC_STATUS_LIST_START) {
377 if (status == SILC_STATUS_LIST_ITEM) {
381 if (status == SILC_STATUS_LIST_END) {
385 /* Execute any pending commands */
386 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
389 silc_server_command_reply_free(cmd);
392 /* Received reply for forwarded JOIN command. Router has created or joined
393 the client to the channel. We save some channel information locally
396 SILC_SERVER_CMD_REPLY_FUNC(join)
398 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
399 SilcServer server = cmd->server;
400 SilcCommandStatus status;
402 SilcChannelEntry entry;
404 unsigned char *id_string;
405 char *channel_name, *tmp;
406 unsigned int mode, created;
409 SILC_LOG_DEBUG(("Start"));
411 COMMAND_CHECK_STATUS;
413 /* Get channel name */
414 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
419 id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
424 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
427 SILC_GET32_MSB(mode, tmp);
429 /* Get created boolean value */
430 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
433 SILC_GET32_MSB(created, tmp);
435 /* Get channel key */
436 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
439 keyp = silc_buffer_alloc(len);
440 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
441 silc_buffer_put(keyp, tmp, len);
443 id = silc_id_payload_parse_id(id_string, len);
445 /* See whether we already have the channel. */
446 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
448 /* Add new channel */
450 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
451 (created == 0 ? "existing" : "created"), channel_name,
452 silc_id_render(id, SILC_ID_CHANNEL)));
454 /* Add the channel to our local list. */
455 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
456 SILC_CHANNEL_MODE_NONE, id,
457 server->router, NULL);
466 /* If channel was not created we know there is global users on the
468 entry->global_users = (created == 0 ? TRUE : FALSE);
470 /* If channel was just created the mask must be zero */
471 if (!entry->global_users && mode) {
472 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
473 "new channel, forcing it to zero", cmd->sock->hostname));
477 /* Save channel mode */
480 /* Save channel key */
481 silc_server_save_channel_key(server, keyp, entry);
482 silc_buffer_free(keyp);
484 /* Execute any pending commands */
485 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
488 silc_server_command_reply_free(cmd);
491 SILC_SERVER_CMD_REPLY_FUNC(names)
493 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
494 SilcServer server = cmd->server;
495 SilcCommandStatus status;
497 SILC_LOG_DEBUG(("Start"));
499 COMMAND_CHECK_STATUS;