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 /* Get command reply payload from packet */
71 payload = silc_command_payload_parse(buffer);
73 /* Silently ignore bad reply packet */
74 SILC_LOG_DEBUG(("Bad command reply packet"));
78 /* Allocate command reply context. This must be free'd by the
79 command reply routine receiving it. */
80 ctx = silc_calloc(1, sizeof(*ctx));
83 ctx->payload = payload;
84 ctx->args = silc_command_get_args(ctx->payload);
85 ident = silc_command_get_ident(ctx->payload);
87 /* Check for pending commands and mark to be exeucted */
88 silc_server_command_pending_check(ctx, silc_command_get(ctx->payload),
91 /* Execute command reply */
92 command = silc_command_get(ctx->payload);
93 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
94 if (cmd->cmd == command)
105 /* Free command reply context and its internals. */
107 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
110 silc_command_free_payload(cmd->payload);
115 /* Caches the received WHOIS information. If we are normal server currently
116 we cache global information only for short period of time. If we are
117 router we want to cache them a bit longer since we can receive information
118 if any of the information becomes invalid. Normal server cannot receive
119 that information. Returns FALSE if something was wrong with the reply. */
122 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
125 unsigned char *id_data;
126 char *nickname, *username, *realname;
127 SilcClientID *client_id;
129 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
130 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
131 username = silc_argument_get_arg_type(cmd->args, 4, &len);
132 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
133 if (!id_data || !nickname || !username || !realname)
136 client_id = silc_id_payload_parse_id(id_data, id_len);
142 /* Reiceved reply for WHOIS command. We sent the whois request to our
143 primary router, if we are normal server, and thus has now received reply
144 to the command. We will figure out what client originally sent us the
145 command and will send the reply to it. If we are router we will figure
146 out who server sent us the command and send reply to that one. */
148 SILC_SERVER_CMD_REPLY_FUNC(whois)
150 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
151 SilcServer server = cmd->server;
152 SilcCommandStatus status;
154 SILC_LOG_DEBUG(("Start"));
156 COMMAND_CHECK_STATUS_LIST;
158 /* Process one identify reply */
159 if (status == SILC_STATUS_OK) {
163 if (status == SILC_STATUS_LIST_START) {
167 if (status == SILC_STATUS_LIST_ITEM) {
171 if (status == SILC_STATUS_LIST_END) {
175 /* Execute pending IDENTIFY command so that the client who originally
176 requested the identify information will get it after all. */
177 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
180 silc_server_command_reply_free(cmd);
183 /* Received reply for forwarded IDENTIFY command. We have received the
184 requested identify information now and we will cache it. After this we
185 will call the pending command so that the requestee gets the information
188 SILC_SERVER_CMD_REPLY_FUNC(identify)
190 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
191 SilcServer server = cmd->server;
192 SilcCommandStatus status;
194 SILC_LOG_DEBUG(("Start"));
196 COMMAND_CHECK_STATUS_LIST;
198 /* Process one identify reply */
199 if (status == SILC_STATUS_OK) {
200 SilcClientID *client_id;
202 unsigned char *id_data;
203 char *nickname, *username;
205 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
206 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
207 if (!id_data || !nickname)
210 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
211 client_id = silc_id_payload_parse_id(id_data, len);
213 /* Add the client always to our global list. If normal or router server
214 ever gets here it means they don't have this client's information
216 silc_idlist_add_client(server->global_list, strdup(nickname),
217 username, NULL, client_id, NULL, NULL);
220 if (status == SILC_STATUS_LIST_START) {
224 if (status == SILC_STATUS_LIST_ITEM) {
228 if (status == SILC_STATUS_LIST_END) {
232 /* Execute pending IDENTIFY command so that the client who originally
233 requested the identify information will get it after all. */
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);
271 /* Add the channel to our local list. */
272 id = silc_id_payload_parse_id(id_string, len);
273 entry = silc_idlist_add_channel(server->local_list, channel_name,
274 SILC_CHANNEL_MODE_NONE, id,
275 server->id_entry->router, NULL);
277 silc_free(channel_name);
282 entry->global_users = TRUE;
284 /* Execute pending JOIN command so that the client who originally
285 wanted to join the channel will be joined after all. */
286 SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
289 silc_server_command_reply_free(cmd);