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(identify, 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. If we are
119 router we want to cache them a bit longer since we can receive information
120 if any of the information becomes invalid. Normal server cannot receive
121 that information. Returns FALSE if something was wrong with the reply. */
124 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
127 unsigned char *id_data;
128 char *nickname, *username, *realname;
129 SilcClientID *client_id;
131 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
132 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
133 username = silc_argument_get_arg_type(cmd->args, 4, &len);
134 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
135 if (!id_data || !nickname || !username || !realname)
138 client_id = silc_id_payload_parse_id(id_data, id_len);
144 /* Reiceved reply for WHOIS command. We sent the whois request to our
145 primary router, if we are normal server, and thus has now received reply
146 to the command. We will figure out what client originally sent us the
147 command and will send the reply to it. If we are router we will figure
148 out who server sent us the command and send reply to that one. */
150 SILC_SERVER_CMD_REPLY_FUNC(whois)
152 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
153 SilcServer server = cmd->server;
154 SilcCommandStatus status;
156 SILC_LOG_DEBUG(("Start"));
158 COMMAND_CHECK_STATUS_LIST;
160 /* Process one identify reply */
161 if (status == SILC_STATUS_OK) {
165 if (status == SILC_STATUS_LIST_START) {
169 if (status == SILC_STATUS_LIST_ITEM) {
173 if (status == SILC_STATUS_LIST_END) {
177 /* Execute pending IDENTIFY command so that the client who originally
178 requested the identify information will get it after all. */
179 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
182 silc_server_command_reply_free(cmd);
185 /* Received reply for forwarded IDENTIFY command. We have received the
186 requested identify information now and we will cache it. After this we
187 will call the pending command so that the requestee gets the information
190 SILC_SERVER_CMD_REPLY_FUNC(identify)
192 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
193 SilcServer server = cmd->server;
194 SilcCommandStatus status;
196 SILC_LOG_DEBUG(("Start"));
198 COMMAND_CHECK_STATUS_LIST;
200 /* Process one identify reply */
201 if (status == SILC_STATUS_OK) {
202 SilcClientID *client_id;
204 unsigned char *id_data;
205 char *nickname, *username;
207 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
208 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
209 if (!id_data || !nickname)
212 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
213 client_id = silc_id_payload_parse_id(id_data, len);
215 /* Add the client always to our global list. If normal or router server
216 ever gets here it means they don't have this client's information
218 silc_idlist_add_client(server->global_list, strdup(nickname),
219 username, NULL, client_id, NULL, NULL);
222 if (status == SILC_STATUS_LIST_START) {
226 if (status == SILC_STATUS_LIST_ITEM) {
230 if (status == SILC_STATUS_LIST_END) {
234 /* Execute pending IDENTIFY command so that the client who originally
235 requested the identify information will get it after all. */
236 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
239 silc_server_command_reply_free(cmd);
242 /* Received reply for forwarded JOIN command. Router has created or joined
243 the client to the channel. We save some channel information locally
246 SILC_SERVER_CMD_REPLY_FUNC(join)
248 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
249 SilcServer server = cmd->server;
250 SilcCommandStatus status;
252 SilcChannelEntry entry;
254 unsigned char *id_string;
255 char *channel_name, *tmp;
257 SILC_LOG_DEBUG(("Start"));
259 COMMAND_CHECK_STATUS;
261 /* Get channel name */
262 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
267 id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
271 channel_name = strdup(tmp);
272 id = silc_id_payload_parse_id(id_string, len);
274 SILC_LOG_DEBUG(("Adding new channel %s id(%s)", channel_name,
275 silc_id_render(id, SILC_ID_CHANNEL)));
277 /* Add the channel to our local list. */
278 entry = silc_idlist_add_channel(server->local_list, channel_name,
279 SILC_CHANNEL_MODE_NONE, id,
280 server->id_entry->router, NULL);
282 silc_free(channel_name);
287 //entry->global_users = TRUE;
289 /* Execute pending JOIN command so that the client who originally
290 wanted to join the channel will be joined after all. */
291 SILC_LOG_DEBUG(("Re-executing JOIN command"));
292 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
295 silc_server_command_reply_free(cmd);