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)
126 SilcServer server = cmd->server;
128 unsigned char *id_data;
129 char *nickname, *username, *realname;
130 SilcClientID *client_id;
131 SilcClientEntry client;
133 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
134 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
135 username = silc_argument_get_arg_type(cmd->args, 4, &len);
136 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
137 if (!id_data || !nickname || !username || !realname)
140 client_id = silc_id_payload_parse_id(id_data, id_len);
142 /* Check if we have this client cached already. */
144 client = silc_idlist_find_client_by_id(server->local_list, client_id);
145 if (!client && server->server_type == SILC_ROUTER)
146 client = silc_idlist_find_client_by_id(server->global_list, client_id);
149 /* We don't have that client anywhere, add it. The client is added
150 to global list since server or router didn't have it in the lists
151 so it must be global. */
152 silc_idlist_add_client(server->global_list, strdup(nickname),
153 username, realname, client_id, NULL, NULL);
155 /* We have the client already, update the data */
157 if (client->username)
158 silc_free(client->username);
159 if (client->userinfo)
160 silc_free(client->userinfo);
162 client->username = strdup(username);
163 client->userinfo = strdup(realname);
166 silc_free(client_id);
171 /* Reiceved reply for WHOIS command. We sent the whois request to our
172 primary router, if we are normal server, and thus has now received reply
173 to the command. We will figure out what client originally sent us the
174 command and will send the reply to it. If we are router we will figure
175 out who server sent us the command and send reply to that one. */
177 SILC_SERVER_CMD_REPLY_FUNC(whois)
179 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
180 SilcCommandStatus status;
182 SILC_LOG_DEBUG(("Start"));
184 COMMAND_CHECK_STATUS_LIST;
186 if (!silc_server_command_reply_whois_save(cmd))
191 /* Process one identify reply */
192 if (status == SILC_STATUS_OK) {
196 if (status == SILC_STATUS_LIST_START) {
200 if (status == SILC_STATUS_LIST_ITEM) {
204 if (status == SILC_STATUS_LIST_END) {
208 /* Execute any pending commands */
209 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
212 silc_server_command_reply_free(cmd);
215 /* Received reply for forwarded IDENTIFY command. We have received the
216 requested identify information now and we will cache it. After this we
217 will call the pending command so that the requestee gets the information
220 SILC_SERVER_CMD_REPLY_FUNC(identify)
222 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
223 SilcServer server = cmd->server;
224 SilcCommandStatus status;
226 SILC_LOG_DEBUG(("Start"));
228 COMMAND_CHECK_STATUS_LIST;
230 /* Process one identify reply */
231 if (status == SILC_STATUS_OK) {
232 SilcClientID *client_id;
234 unsigned char *id_data;
235 char *nickname, *username;
237 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
238 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
239 if (!id_data || !nickname)
242 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
243 client_id = silc_id_payload_parse_id(id_data, len);
245 /* Add the client always to our global list. If normal or router server
246 ever gets here it means they don't have this client's information
248 silc_idlist_add_client(server->global_list, strdup(nickname),
249 username, NULL, client_id, NULL, NULL);
252 if (status == SILC_STATUS_LIST_START) {
256 if (status == SILC_STATUS_LIST_ITEM) {
260 if (status == SILC_STATUS_LIST_END) {
264 /* Execute any pending commands */
265 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
268 silc_server_command_reply_free(cmd);
271 /* Received reply for forwarded JOIN command. Router has created or joined
272 the client to the channel. We save some channel information locally
275 SILC_SERVER_CMD_REPLY_FUNC(join)
277 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
278 SilcServer server = cmd->server;
279 SilcCommandStatus status;
281 SilcChannelEntry entry;
283 unsigned char *id_string;
284 char *channel_name, *tmp;
286 SILC_LOG_DEBUG(("Start"));
288 COMMAND_CHECK_STATUS;
290 /* Get channel name */
291 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
296 id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
300 channel_name = strdup(tmp);
301 id = silc_id_payload_parse_id(id_string, len);
303 /* XXX We should check that we have sent JOIN command to the router
304 in the first place. Also should check that we don't have the channel
305 already in the cache. These checks must be made because of possible
308 SILC_LOG_DEBUG(("Adding new channel %s id(%s)", channel_name,
309 silc_id_render(id, SILC_ID_CHANNEL)));
311 /* Add the channel to our local list. */
312 entry = silc_idlist_add_channel(server->local_list, channel_name,
313 SILC_CHANNEL_MODE_NONE, id,
314 server->router, NULL);
316 silc_free(channel_name);
321 //entry->global_users = TRUE;
323 /* Execute any pending commands */
324 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
327 silc_server_command_reply_free(cmd);