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 any pending commands */
178 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
181 silc_server_command_reply_free(cmd);
184 /* Received reply for forwarded IDENTIFY command. We have received the
185 requested identify information now and we will cache it. After this we
186 will call the pending command so that the requestee gets the information
189 SILC_SERVER_CMD_REPLY_FUNC(identify)
191 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
192 SilcServer server = cmd->server;
193 SilcCommandStatus status;
195 SILC_LOG_DEBUG(("Start"));
197 COMMAND_CHECK_STATUS_LIST;
199 /* Process one identify reply */
200 if (status == SILC_STATUS_OK) {
201 SilcClientID *client_id;
203 unsigned char *id_data;
204 char *nickname, *username;
206 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
207 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
208 if (!id_data || !nickname)
211 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
212 client_id = silc_id_payload_parse_id(id_data, len);
214 /* Add the client always to our global list. If normal or router server
215 ever gets here it means they don't have this client's information
217 silc_idlist_add_client(server->global_list, strdup(nickname),
218 username, NULL, client_id, NULL, NULL);
221 if (status == SILC_STATUS_LIST_START) {
225 if (status == SILC_STATUS_LIST_ITEM) {
229 if (status == SILC_STATUS_LIST_END) {
233 /* Execute any pending commands */
234 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
237 silc_server_command_reply_free(cmd);
240 /* Received reply for forwarded JOIN command. Router has created or joined
241 the client to the channel. We save some channel information locally
244 SILC_SERVER_CMD_REPLY_FUNC(join)
246 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
247 SilcServer server = cmd->server;
248 SilcCommandStatus status;
250 SilcChannelEntry entry;
252 unsigned char *id_string;
253 char *channel_name, *tmp;
255 SILC_LOG_DEBUG(("Start"));
257 COMMAND_CHECK_STATUS;
259 /* Get channel name */
260 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
265 id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
269 channel_name = strdup(tmp);
270 id = silc_id_payload_parse_id(id_string, len);
272 /* XXX We should check that we have sent JOIN command to the router
273 in the first place. Also should check that we don't have the channel
274 already in the cache. These checks must be made because of possible
277 SILC_LOG_DEBUG(("Adding new channel %s id(%s)", channel_name,
278 silc_id_render(id, SILC_ID_CHANNEL)));
280 /* Add the channel to our local list. */
281 entry = silc_idlist_add_channel(server->local_list, channel_name,
282 SILC_CHANNEL_MODE_NONE, id,
283 server->router, NULL);
285 silc_free(channel_name);
290 //entry->global_users = TRUE;
292 /* Execute any pending commands */
293 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
296 silc_server_command_reply_free(cmd);