X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilccommand.c;h=83dbde8cf6263e1f218019c410123a572747e1cc;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=50d96200eddc547736e9604514524af7479de95a;hpb=a818c5b5411bbc4436d1c5f011236985c96bb787;p=silc.git diff --git a/lib/silccore/silccommand.c b/lib/silccore/silccommand.c index 50d96200..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" /****************************************************************************** @@ -45,7 +44,7 @@ SilcCommandPayload silc_command_payload_parse(const unsigned char *payload, SilcUInt32 payload_len) { SilcBufferStruct buffer; - SilcCommandPayload new; + SilcCommandPayload newp; unsigned char args_num; SilcUInt16 p_len; int ret; @@ -53,42 +52,48 @@ SilcCommandPayload silc_command_payload_parse(const unsigned char *payload, SILC_LOG_DEBUG(("Parsing command payload")); silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); - new = silc_calloc(1, sizeof(*new)); + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + 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(&new->cmd), + SILC_STR_UI_CHAR(&newp->cmd), SILC_STR_UI_CHAR(&args_num), - SILC_STR_UI_SHORT(&new->ident), + SILC_STR_UI_SHORT(&newp->ident), SILC_STR_END); if (ret == -1) { - silc_free(new); + 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")); - silc_free(new); + if (p_len != silc_buffer_len(&buffer)) { + SILC_LOG_ERROR(("Incorrect command payload in packet")); + silc_free(newp); return NULL; } - if (new->cmd == 0) { - silc_free(new); + 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) { - new->args = silc_argument_payload_parse(buffer.data, buffer.len, args_num); - if (!new->args) { - silc_free(new); + newp->args = silc_argument_payload_parse(buffer.data, + silc_buffer_len(&buffer), + args_num); + if (!newp->args) { + silc_free(newp); return NULL; } } silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN); - return new; + return newp; } /* Encodes Command Payload returning it to SilcBuffer. */ @@ -108,12 +113,15 @@ 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; - buffer = silc_buffer_alloc(len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(len); + if (!buffer) + return NULL; /* Create Command payload */ silc_buffer_format(buffer, @@ -127,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); @@ -150,13 +159,18 @@ 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); } len += SILC_COMMAND_PAYLOAD_LEN; - buffer = silc_buffer_alloc(len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(len); + if (!buffer) { + if (args) + silc_buffer_free(args); + return NULL; + } /* Create Command payload */ silc_buffer_format(buffer, @@ -170,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); @@ -180,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; @@ -203,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; @@ -212,32 +227,41 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, unsigned char *x; SilcUInt32 x_len; SilcUInt32 x_type; - SilcBuffer buffer; + SilcBuffer buffer = NULL; int i, k = 0; if (argc) { argv = silc_calloc(argc, sizeof(unsigned char *)); + if (!argv) + return NULL; argv_lens = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_lens) + return NULL; argv_types = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_types) + return NULL; for (i = 0, k = 0; i < argc; i++) { 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; argv_lens[k] = x_len; argv_types[k] = x_type; 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: for (i = 0; i < k; i++) silc_free(argv[i]); silc_free(argv); @@ -252,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, ...) { @@ -262,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; @@ -280,16 +307,34 @@ silc_command_reply_payload_encode_vap(SilcCommand cmd, unsigned char *x; SilcUInt32 x_len; SilcUInt32 x_type; - SilcBuffer buffer; + SilcBuffer buffer = NULL; int i, k; argc++; argv = silc_calloc(argc, sizeof(unsigned char *)); + if (!argv) + return NULL; argv_lens = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_lens) { + silc_free(argv); + return NULL; + } argv_types = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_types) { + silc_free(argv_lens); + silc_free(argv); + 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); + silc_free(argv_lens); + silc_free(argv); + return NULL; + } argv_lens[0] = sizeof(status_data); argv_types[0] = 1; @@ -302,14 +347,17 @@ silc_command_reply_payload_encode_vap(SilcCommand cmd, continue; argv[k] = silc_memdup(x, x_len); + if (!argv[k]) + goto out; argv_lens[k] = x_len; argv_types[k] = x_type; 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: for (i = 0; i < k; i++) silc_free(argv[i]); silc_free(argv); @@ -350,6 +398,49 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload) return payload->ident; } +/* Return command status */ + +SilcBool silc_command_get_status(SilcCommandPayload payload, + SilcStatus *status, + SilcStatus *error) +{ + unsigned char *tmp; + SilcUInt32 tmp_len; + + if (!payload->args) + return 0; + tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len); + if (!tmp || tmp_len != 2) + return 0; + + /* 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 payloads are frequentlly resent in SILC and thusly this makes it easy to set the identifier. */