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   /* Get command reply payload from packet */
71   payload = silc_command_payload_parse(buffer);
72   if (!payload) {
73     /* Silently ignore bad reply packet */
74     SILC_LOG_DEBUG(("Bad command reply packet"));
75     return;
76   }
77   
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));
81   ctx->server = server;
82   ctx->sock = sock;
83   ctx->payload = payload;
84   ctx->args = silc_command_get_args(ctx->payload);
85   ident = silc_command_get_ident(ctx->payload);
86       
87   /* Check for pending commands and mark to be exeucted */
88   silc_server_command_pending_check(ctx, silc_command_get(ctx->payload),
89                                     ident);
90
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)
95       break;
96
97   if (cmd == NULL) {
98     silc_free(ctx);
99     return;
100   }
101
102   cmd->cb(ctx);
103 }
104
105 /* Free command reply context and its internals. */
106
107 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
108 {
109   if (cmd) {
110     silc_command_free_payload(cmd->payload);
111     silc_free(cmd);
112   }
113 }
114
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. */
120
121 static char
122 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
123 {
124   int len, id_len;
125   unsigned char *id_data;
126   char *nickname, *username, *realname;
127   SilcClientID *client_id;
128
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) 
134     return FALSE;
135
136   client_id = silc_id_payload_parse_id(id_data, id_len);
137
138
139   return TRUE;
140 }
141
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. */
147
148 SILC_SERVER_CMD_REPLY_FUNC(whois)
149 {
150   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
151   SilcServer server = cmd->server;
152   SilcCommandStatus status;
153
154   SILC_LOG_DEBUG(("Start"));
155
156   COMMAND_CHECK_STATUS_LIST;
157
158   /* Process one identify reply */
159   if (status == SILC_STATUS_OK) {
160
161   }
162
163   if (status == SILC_STATUS_LIST_START) {
164
165   }
166
167   if (status == SILC_STATUS_LIST_ITEM) {
168
169   }
170
171   if (status == SILC_STATUS_LIST_END) {
172
173   }
174
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);
178
179  out:
180   silc_server_command_reply_free(cmd);
181 }
182
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
186    after all. */
187
188 SILC_SERVER_CMD_REPLY_FUNC(identify)
189 {
190   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
191   SilcServer server = cmd->server;
192   SilcCommandStatus status;
193
194   SILC_LOG_DEBUG(("Start"));
195
196   COMMAND_CHECK_STATUS_LIST;
197
198   /* Process one identify reply */
199   if (status == SILC_STATUS_OK) {
200     SilcClientID *client_id;
201     unsigned int len;
202     unsigned char *id_data;
203     char *nickname, *username;
204
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)
208       goto out;
209
210     username = silc_argument_get_arg_type(cmd->args, 4, NULL);
211     client_id = silc_id_payload_parse_id(id_data, len);
212
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
215        in their cache. */
216     silc_idlist_add_client(server->global_list, strdup(nickname),
217                            username, NULL, client_id, NULL, NULL);
218   }
219
220   if (status == SILC_STATUS_LIST_START) {
221
222   }
223
224   if (status == SILC_STATUS_LIST_ITEM) {
225
226   }
227
228   if (status == SILC_STATUS_LIST_END) {
229
230   }
231
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);
235
236  out:
237   silc_server_command_reply_free(cmd);
238 }
239
240 /* Received reply for forwarded JOIN command. Router has created or joined
241    the client to the channel. We save some channel information locally
242    for future use. */
243
244 SILC_SERVER_CMD_REPLY_FUNC(join)
245 {
246   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
247   SilcServer server = cmd->server;
248   SilcCommandStatus status;
249   SilcChannelID *id;
250   SilcChannelEntry entry;
251   unsigned int len;
252   unsigned char *id_string;
253   char *channel_name, *tmp;
254
255   SILC_LOG_DEBUG(("Start"));
256
257   COMMAND_CHECK_STATUS;
258
259   /* Get channel name */
260   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
261   if (!tmp)
262     goto out;
263
264   /* Get channel ID */
265   id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
266   if (!id_string)
267     goto out;
268
269   channel_name = strdup(tmp);
270
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);
276   if (!entry) {
277     silc_free(channel_name);
278     silc_free(id);
279     goto out;
280   }
281
282   entry->global_users = TRUE;
283
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);
287
288  out:
289   silc_server_command_reply_free(cmd);
290 }