updates
[silc.git] / apps / silcd / command_reply.c
1 /*
2
3   command_reply.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /* $Id$ */
21
22 #include "serverincludes.h"
23 #include "server_internal.h"
24 #include "command_reply.h"
25
26 #define COMMAND_CHECK_STATUS                                              \
27 do {                                                                      \
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);                                  \
31     return;                                                               \
32   }                                                                       \
33 } while(0)
34
35 #define COMMAND_CHECK_STATUS_LIST                                         \
36 do {                                                                      \
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);                                  \
43     return;                                                               \
44   }                                                                       \
45 } while(0)
46
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[] =
50 {
51   SILC_SERVER_CMD_REPLY(join, JOIN),
52   SILC_SERVER_CMD_REPLY(identify, WHOIS),
53   SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
54
55   { NULL, 0 },
56 };
57
58 /* Process received command reply. */
59
60 void silc_server_command_reply_process(SilcServer server,
61                                        SilcSocketConnection sock,
62                                        SilcBuffer buffer)
63 {
64   SilcServerCommandReply *cmd;
65   SilcServerCommandReplyContext ctx;
66   SilcCommandPayload payload;
67   SilcCommand command;
68   unsigned short ident;
69
70   SILC_LOG_DEBUG(("Start"));
71
72   /* Get command reply payload from packet */
73   payload = silc_command_payload_parse(buffer);
74   if (!payload) {
75     /* Silently ignore bad reply packet */
76     SILC_LOG_DEBUG(("Bad command reply packet"));
77     return;
78   }
79   
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));
83   ctx->server = server;
84   ctx->sock = sock;
85   ctx->payload = payload;
86   ctx->args = silc_command_get_args(ctx->payload);
87   ident = silc_command_get_ident(ctx->payload);
88       
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);
92
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)
97       break;
98
99   if (cmd == NULL) {
100     silc_free(ctx);
101     return;
102   }
103
104   cmd->cb(ctx);
105 }
106
107 /* Free command reply context and its internals. */
108
109 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
110 {
111   if (cmd) {
112     silc_command_free_payload(cmd->payload);
113     silc_free(cmd);
114   }
115 }
116
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. */
122
123 static char
124 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
125 {
126   int len, id_len;
127   unsigned char *id_data;
128   char *nickname, *username, *realname;
129   SilcClientID *client_id;
130
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) 
136     return FALSE;
137
138   client_id = silc_id_payload_parse_id(id_data, id_len);
139
140
141   return TRUE;
142 }
143
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. */
149
150 SILC_SERVER_CMD_REPLY_FUNC(whois)
151 {
152   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
153   SilcServer server = cmd->server;
154   SilcCommandStatus status;
155
156   SILC_LOG_DEBUG(("Start"));
157
158   COMMAND_CHECK_STATUS_LIST;
159
160   /* Process one identify reply */
161   if (status == SILC_STATUS_OK) {
162
163   }
164
165   if (status == SILC_STATUS_LIST_START) {
166
167   }
168
169   if (status == SILC_STATUS_LIST_ITEM) {
170
171   }
172
173   if (status == SILC_STATUS_LIST_END) {
174
175   }
176
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);
180
181  out:
182   silc_server_command_reply_free(cmd);
183 }
184
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
188    after all. */
189
190 SILC_SERVER_CMD_REPLY_FUNC(identify)
191 {
192   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
193   SilcServer server = cmd->server;
194   SilcCommandStatus status;
195
196   SILC_LOG_DEBUG(("Start"));
197
198   COMMAND_CHECK_STATUS_LIST;
199
200   /* Process one identify reply */
201   if (status == SILC_STATUS_OK) {
202     SilcClientID *client_id;
203     unsigned int len;
204     unsigned char *id_data;
205     char *nickname, *username;
206
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)
210       goto out;
211
212     username = silc_argument_get_arg_type(cmd->args, 4, NULL);
213     client_id = silc_id_payload_parse_id(id_data, len);
214
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
217        in their cache. */
218     silc_idlist_add_client(server->global_list, strdup(nickname),
219                            username, NULL, client_id, NULL, NULL);
220   }
221
222   if (status == SILC_STATUS_LIST_START) {
223
224   }
225
226   if (status == SILC_STATUS_LIST_ITEM) {
227
228   }
229
230   if (status == SILC_STATUS_LIST_END) {
231
232   }
233
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);
237
238  out:
239   silc_server_command_reply_free(cmd);
240 }
241
242 /* Received reply for forwarded JOIN command. Router has created or joined
243    the client to the channel. We save some channel information locally
244    for future use. */
245
246 SILC_SERVER_CMD_REPLY_FUNC(join)
247 {
248   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
249   SilcServer server = cmd->server;
250   SilcCommandStatus status;
251   SilcChannelID *id;
252   SilcChannelEntry entry;
253   unsigned int len;
254   unsigned char *id_string;
255   char *channel_name, *tmp;
256
257   SILC_LOG_DEBUG(("Start"));
258
259   COMMAND_CHECK_STATUS;
260
261   /* Get channel name */
262   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
263   if (!tmp)
264     goto out;
265
266   /* Get channel ID */
267   id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
268   if (!id_string)
269     goto out;
270
271   channel_name = strdup(tmp);
272   id = silc_id_payload_parse_id(id_string, len);
273
274   SILC_LOG_DEBUG(("Adding new channel %s id(%s)", channel_name,
275                   silc_id_render(id, SILC_ID_CHANNEL)));
276
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);
281   if (!entry) {
282     silc_free(channel_name);
283     silc_free(id);
284     goto out;
285   }
286
287   //entry->global_users = TRUE;
288
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);
293
294  out:
295   silc_server_command_reply_free(cmd);
296 }