X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilccommand.c;h=83dbde8cf6263e1f218019c410123a572747e1cc;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=3be0583e3a04006ffbf3573184aaea3804abc9c0;hpb=33fde1853daddd7f34565507cb96652f0cec4ee2;p=silc.git diff --git a/lib/silccore/silccommand.c b/lib/silccore/silccommand.c index 3be0583e..83dbde8c 100644 --- a/lib/silccore/silccommand.c +++ b/lib/silccore/silccommand.c @@ -4,13 +4,12 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2001 Pekka Riikonen + Copyright (C) 1997 - 2005 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -19,7 +18,7 @@ */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" #include "silccommand.h" /****************************************************************************** @@ -58,31 +57,35 @@ SilcCommandPayload silc_command_payload_parse(const unsigned char *payload, return NULL; /* Parse the Command Payload */ - ret = silc_buffer_unformat(&buffer, + ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&p_len), SILC_STR_UI_CHAR(&newp->cmd), SILC_STR_UI_CHAR(&args_num), SILC_STR_UI_SHORT(&newp->ident), SILC_STR_END); if (ret == -1) { + SILC_LOG_ERROR(("Incorrect command payload in packet")); silc_free(newp); return NULL; } - if (p_len != buffer.len) { - SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped")); + if (p_len != silc_buffer_len(&buffer)) { + SILC_LOG_ERROR(("Incorrect command payload in packet")); silc_free(newp); return NULL; } if (newp->cmd == 0) { + SILC_LOG_ERROR(("Incorrect command type in command payload")); silc_free(newp); return NULL; } silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN); if (args_num) { - newp->args = silc_argument_payload_parse(buffer.data, buffer.len, args_num); + newp->args = silc_argument_payload_parse(buffer.data, + silc_buffer_len(&buffer), + args_num); if (!newp->args) { silc_free(newp); return NULL; @@ -110,7 +113,9 @@ SilcBuffer silc_command_payload_encode(SilcCommand cmd, if (argc) { args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types); - len = args->len; + if (!args) + return NULL; + len = silc_buffer_len(args); } len += SILC_COMMAND_PAYLOAD_LEN; @@ -130,7 +135,8 @@ SilcBuffer silc_command_payload_encode(SilcCommand cmd, if (argc) { silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_format(buffer, - SILC_STR_UI_XNSTRING(args->data, args->len), + SILC_STR_UI_XNSTRING(args->data, + silc_buffer_len(args)), SILC_STR_END); silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_free(args); @@ -153,7 +159,8 @@ SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload) if (payload->args) { args = silc_argument_payload_encode_payload(payload->args); - len = args->len; + if (args) + len = silc_buffer_len(args); argc = silc_argument_get_arg_num(payload->args); } @@ -177,7 +184,8 @@ SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload) if (args) { silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_format(buffer, - SILC_STR_UI_XNSTRING(args->data, args->len), + SILC_STR_UI_XNSTRING(args->data, + silc_buffer_len(args)), SILC_STR_END); silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_free(args); @@ -187,15 +195,15 @@ SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload) } /* Encodes Command payload with variable argument list. The arguments - must be: SilcUInt32, unsigned char *, unsigned int, ... One - {SilcUInt32, unsigned char * and unsigned int} forms one argument, - thus `argc' in case when sending one {SilcUInt32, unsigned char * + must be: SilcUInt32, unsigned char *, unsigned int, ... One + {SilcUInt32, unsigned char * and unsigned int} forms one argument, + thus `argc' in case when sending one {SilcUInt32, unsigned char * and SilcUInt32} equals one (1) and when sending two of those it equals two (2), and so on. This has to be preserved or bad things will happen. The variable arguments is: {type, data, data_len}. */ -SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, - SilcUInt16 ident, +SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, + SilcUInt16 ident, SilcUInt32 argc, ...) { va_list ap; @@ -210,8 +218,8 @@ SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, /* Same as above but with va_list. */ -SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, - SilcUInt16 ident, +SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, + SilcUInt16 ident, SilcUInt32 argc, va_list ap) { unsigned char **argv = NULL; @@ -237,10 +245,10 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, x_type = va_arg(ap, SilcUInt32); x = va_arg(ap, unsigned char *); x_len = va_arg(ap, SilcUInt32); - + if (!x_type || !x || !x_len) continue; - + argv[k] = silc_memdup(x, x_len); if (!argv[k]) goto out; @@ -250,7 +258,7 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, } } - buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, + buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, argv_types, ident); out: @@ -268,9 +276,10 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, extra argument to this function. The `argc' must not count `status' as on argument. */ -SilcBuffer -silc_command_reply_payload_encode_va(SilcCommand cmd, - SilcCommandStatus status, +SilcBuffer +silc_command_reply_payload_encode_va(SilcCommand cmd, + SilcStatus status, + SilcStatus error, SilcUInt16 ident, SilcUInt32 argc, ...) { @@ -278,16 +287,18 @@ silc_command_reply_payload_encode_va(SilcCommand cmd, SilcBuffer buffer; va_start(ap, argc); - buffer = silc_command_reply_payload_encode_vap(cmd, status, ident, argc, ap); + buffer = silc_command_reply_payload_encode_vap(cmd, status, error, + ident, argc, ap); va_end(ap); return buffer; } -SilcBuffer -silc_command_reply_payload_encode_vap(SilcCommand cmd, - SilcCommandStatus status, - SilcUInt16 ident, SilcUInt32 argc, +SilcBuffer +silc_command_reply_payload_encode_vap(SilcCommand cmd, + SilcStatus status, + SilcStatus error, + SilcUInt16 ident, SilcUInt32 argc, va_list ap) { unsigned char **argv; @@ -315,7 +326,8 @@ silc_command_reply_payload_encode_vap(SilcCommand cmd, return NULL; } - SILC_PUT16_MSB(status, status_data); + status_data[0] = status; + status_data[1] = error; argv[0] = silc_memdup(status_data, sizeof(status_data)); if (!argv[0]) { silc_free(argv_types); @@ -342,7 +354,7 @@ silc_command_reply_payload_encode_vap(SilcCommand cmd, k++; } - buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, + buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, argv_types, ident); out: @@ -388,19 +400,45 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload) /* Return command status */ -SilcCommandStatus silc_command_get_status(SilcCommandPayload payload) +SilcBool silc_command_get_status(SilcCommandPayload payload, + SilcStatus *status, + SilcStatus *error) { unsigned char *tmp; - SilcCommandStatus status; + SilcUInt32 tmp_len; if (!payload->args) return 0; - tmp = silc_argument_get_arg_type(payload->args, 1, NULL); - if (!tmp) + tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len); + if (!tmp || tmp_len != 2) return 0; - SILC_GET16_MSB(status, tmp); - return status; + /* Check for 1.0 protocol version which didn't have `error' */ + if (tmp[0] == 0 && tmp[1] != 0) { + /* Protocol 1.0 version */ + SilcStatus s; + SILC_GET16_MSB(s, tmp); + if (status) + *status = s; + if (error) + *error = 0; + if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error) + *error = s; + return (s < SILC_STATUS_ERR_NO_SUCH_NICK); + } + + /* Take both status and possible error */ + if (status) + *status = (SilcStatus)tmp[0]; + if (error) + *error = (SilcStatus)tmp[1]; + + /* If single error occurred have the both `status' and `error' indicate + the error value for convenience. */ + if (tmp[0] >= SILC_STATUS_ERR_NO_SUCH_NICK && error) + *error = tmp[0]; + + return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK); } /* Function to set identifier to already allocated Command Payload. Command