Coverage Report

Created: 2025-07-18 06:32

/src/opensips/mi/item.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2006 Voice Sistem SRL
3
 * Copyright (C) 2018 OpenSIPS Solutions
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
 *
21
 *
22
 */
23
24
#include <string.h>
25
#include <stdio.h>
26
#include <errno.h>
27
#include <stdlib.h>
28
#include "../mem/mem.h"
29
#include "../mem/shm_mem.h"
30
#include "../dprint.h"
31
#include "../ut.h"
32
#include "item.h"
33
#include "fmt.h"
34
35
0
#define MI_PARAM_ERR_BUFLEN 255
36
37
0
#define MI_PARAM_ERR_MISSING -1
38
0
#define MI_PARAM_ERR_BAD_TYPE -2
39
0
#define MI_PARAM_ERR_EMPTY_ARR -3
40
0
#define MI_PARAM_ERR_ARR_BAD_TYPE -4
41
42
int param_err_type = -2;
43
char *param_err_pname;
44
45
static mi_response_t *_init_mi_result(mi_item_t **item_out, int type, int dval,
46
                    const char *sval, int sval_len)
47
0
{
48
0
  mi_response_t *res = NULL;
49
0
  mi_item_t *jsonrpc_vers;
50
51
0
  _init_mi_sys_mem_hooks();
52
53
0
  res = cJSON_CreateObject();
54
0
  if (!res)
55
0
    goto error;
56
57
0
  jsonrpc_vers = cJSON_CreateString(JSONRPC_VERS_S);
58
0
  if (!jsonrpc_vers)
59
0
    goto error;
60
0
  cJSON_AddItemToObject(res, JSONRPC_S, jsonrpc_vers);
61
62
0
  switch (type) {
63
0
  case cJSON_Array:
64
0
    *item_out = cJSON_CreateArray();
65
0
    break;
66
0
  case cJSON_Object:
67
0
    *item_out = cJSON_CreateObject();
68
0
    break;
69
0
  case cJSON_String:
70
0
    *item_out = cJSON_CreateStr(sval, sval_len);
71
0
    break;
72
0
  case cJSON_Number:
73
0
    *item_out = cJSON_CreateNumber(dval);
74
0
    break;
75
0
  case cJSON_True:
76
0
    *item_out = cJSON_CreateTrue();
77
0
    break;
78
0
  case cJSON_False:
79
0
    *item_out = cJSON_CreateFalse();
80
0
    break;
81
0
  case cJSON_NULL:
82
0
    *item_out = cJSON_CreateNull();
83
0
    break;
84
0
  default:
85
0
    *item_out = NULL;
86
0
    LM_BUG("Unknown MI item type: %d\n", type);
87
0
    goto error;
88
0
  }
89
0
  if (!*item_out)
90
0
    goto error;
91
92
0
  cJSON_AddItemToObject(res, JSONRPC_RESULT_S, *item_out);
93
94
0
  _init_mi_pkg_mem_hooks();
95
0
  return res;
96
97
0
error:
98
0
  if (res)
99
0
    cJSON_Delete(res);
100
0
  _init_mi_pkg_mem_hooks();
101
0
  return NULL;
102
0
}
103
104
105
mi_response_t *init_mi_result_array(mi_item_t **arr_out)
106
0
{
107
0
  return _init_mi_result(arr_out, cJSON_Array, 0, NULL, 0);
108
0
}
109
110
mi_response_t *init_mi_result_object(mi_item_t **obj_out)
111
0
{
112
0
  return _init_mi_result(obj_out, cJSON_Object, 0, NULL, 0);
113
0
}
114
115
mi_response_t *init_mi_result_string(const char *value, int value_len)
116
0
{
117
0
  mi_item_t *item;
118
119
0
  return _init_mi_result(&item, cJSON_String, 0, value, value_len);
120
0
}
121
122
mi_response_t *init_mi_result_number(double value)
123
0
{
124
0
  mi_item_t *item;
125
126
0
  return _init_mi_result(&item, cJSON_Number, value, NULL, 0);
127
0
}
128
129
mi_response_t *init_mi_result_bool(int b)
130
0
{
131
0
  mi_item_t *item;
132
133
0
  return _init_mi_result(&item, b ? cJSON_True : cJSON_False, 0, NULL, 0);
134
0
}
135
136
mi_response_t *init_mi_result_null(void)
137
0
{
138
0
  mi_item_t *item;
139
140
0
  return _init_mi_result(&item, cJSON_NULL, 0, NULL, 0);
141
0
}
142
143
mi_response_t *init_mi_error_extra(int code, const char *msg, int msg_len,
144
                const char *details, int details_len)
145
0
{
146
0
  mi_response_t *res;
147
0
  mi_item_t *err_item = NULL, *msg_item = NULL, *code_item = NULL, *data_item;
148
0
  mi_item_t *jsonrpc_vers;
149
150
0
  _init_mi_sys_mem_hooks();
151
152
0
  res = cJSON_CreateObject();
153
0
  if (!res)
154
0
    goto error;
155
156
0
  jsonrpc_vers = cJSON_CreateString(JSONRPC_VERS_S);
157
0
  if (!jsonrpc_vers)
158
0
    goto error;
159
0
  cJSON_AddItemToObject(res, JSONRPC_S, jsonrpc_vers);
160
161
0
  err_item = cJSON_CreateObject();
162
0
  if (!err_item)
163
0
    goto error;
164
0
  cJSON_AddItemToObject(res, JSONRPC_ERROR_S, err_item);
165
166
0
  code_item = cJSON_CreateNumber(code);
167
0
  if (!code_item)
168
0
    goto error;
169
0
  cJSON_AddItemToObject(err_item, JSONRPC_ERR_CODE_S, code_item);
170
171
0
  msg_item = cJSON_CreateStr(msg, msg_len);
172
0
  if (!msg_item)
173
0
    goto error;
174
0
  cJSON_AddItemToObject(err_item, JSONRPC_ERR_MSG_S, msg_item);
175
176
0
  if (details && details_len) {
177
0
    data_item = cJSON_CreateStr(details, details_len);
178
0
    if (!data_item)
179
0
      goto error;
180
0
    cJSON_AddItemToObject(err_item, JSONRPC_ERR_DATA_S, data_item);
181
0
  }
182
183
0
  _init_mi_pkg_mem_hooks();
184
0
  return res;
185
186
0
error:
187
0
  if (res)
188
0
    cJSON_Delete(res);
189
190
0
  _init_mi_pkg_mem_hooks();
191
0
  return NULL;
192
0
}
193
194
void free_mi_response(mi_response_t *response)
195
0
{
196
0
  _init_mi_sys_mem_hooks();
197
198
0
  cJSON_Delete(response);
199
200
0
  _init_mi_pkg_mem_hooks();
201
0
}
202
203
static mi_item_t *_add_mi_item(mi_item_t *to, char *name, int name_len,
204
              int type, double dval, const char *sval, int sval_len)
205
0
{
206
0
  mi_item_t *item = NULL;
207
0
  str name_str;
208
209
0
  _init_mi_sys_mem_hooks();
210
211
0
  switch (type) {
212
0
  case cJSON_Array:
213
0
    item = cJSON_CreateArray();
214
0
    break;
215
0
  case cJSON_Object:
216
0
    item = cJSON_CreateObject();
217
0
    break;
218
0
  case cJSON_String:
219
0
    if (!sval || sval_len == 0)
220
0
      item = cJSON_CreateStr("", 0);
221
0
    else
222
0
      item = cJSON_CreateStr(sval, sval_len);
223
0
    break;
224
0
  case cJSON_Number:
225
0
    item = cJSON_CreateNumber(dval);
226
0
    break;
227
0
  case cJSON_True:
228
0
    item = cJSON_CreateTrue();
229
0
    break;
230
0
  case cJSON_False:
231
0
    item = cJSON_CreateFalse();
232
0
    break;
233
0
  case cJSON_NULL:
234
0
    item = cJSON_CreateNull();
235
0
    break;
236
0
  default:
237
0
    item = NULL;
238
0
    LM_BUG("Unknown MI item type: %d\n", type);
239
0
    goto out;
240
0
  }
241
242
0
  if (!item)
243
0
    goto out;
244
245
0
  if (MI_ITEM_IS_ARRAY(to))
246
0
    cJSON_AddItemToArray(to, item);
247
0
  else {
248
0
    name_str.len = name_len;
249
0
    name_str.s = name;
250
0
    _cJSON_AddItemToObject(to, &name_str, item);
251
0
  }
252
253
0
out:
254
0
  _init_mi_pkg_mem_hooks();
255
0
  return item;
256
0
}
257
258
mi_item_t *add_mi_array(mi_item_t *to, char *name, int name_len)
259
0
{
260
0
  return _add_mi_item(to, name, name_len, cJSON_Array, 0, NULL, 0);
261
0
}
262
263
mi_item_t *add_mi_object(mi_item_t *to, char *name, int name_len)
264
0
{
265
0
  return _add_mi_item(to, name, name_len, cJSON_Object, 0, NULL, 0);
266
0
}
267
268
int add_mi_string(mi_item_t *to, char *name, int name_len,
269
          const char *value, int value_len)
270
0
{
271
0
  return _add_mi_item(to, name, name_len, cJSON_String, 0, value, value_len) ?
272
0
    0 : -1;
273
0
}
274
275
int add_mi_string_fmt(mi_item_t *to, char *name, int name_len,
276
            char *fmt_val, ...)
277
0
{
278
0
  va_list ap;
279
0
  char *value;
280
0
  int value_len;
281
282
0
  va_start(ap, fmt_val);
283
0
  value = mi_print_fmt(fmt_val, ap, &value_len);
284
0
  va_end(ap);
285
0
  if (!value)
286
0
    return -1;
287
288
0
  return _add_mi_item(to, name, name_len, cJSON_String, 0, value, value_len) ?
289
0
    0 : -1;
290
0
}
291
292
int add_mi_number(mi_item_t *to, char *name, int name_len, double value)
293
0
{
294
0
  return _add_mi_item(to, name, name_len, cJSON_Number, value, NULL, 0) ?
295
0
    0 : -1;
296
0
}
297
298
int add_mi_bool(mi_item_t *to, char *name, int name_len, int b)
299
0
{
300
0
  return _add_mi_item(to, name, name_len, b ? cJSON_True : cJSON_False,
301
0
    0, NULL, 0) ? 0 : -1;
302
0
}
303
304
int add_mi_null(mi_item_t *to, char *name, int name_len)
305
0
{
306
0
  return _add_mi_item(to, name, name_len, cJSON_NULL, 0, NULL, 0) ?
307
0
    0 : -1;
308
0
}
309
310
mi_response_t *shm_clone_mi_response(mi_response_t *src)
311
0
{
312
0
  mi_response_t *copy;
313
314
0
  _init_mi_shm_mem_hooks();
315
316
0
  copy = cJSON_Duplicate(src, 1);
317
318
0
  _init_mi_pkg_mem_hooks();
319
320
0
  return copy;
321
0
}
322
323
void free_shm_mi_response(mi_response_t *shm_response)
324
0
{
325
  /* if there is an id, this is probably in pkg mem, because that's how
326
   * add_id_to_response adds it; if we don't release it now, removing it
327
   * from shm will result in a memory corruption */
328
0
  _init_mi_sys_mem_hooks();
329
0
  cJSON_DeleteItemFromObject(shm_response, "id");
330
331
0
  _init_mi_shm_mem_hooks();
332
333
0
  cJSON_Delete(shm_response);
334
335
0
  _init_mi_pkg_mem_hooks();
336
0
}
337
338
mi_item_t *shm_clone_mi_item(mi_item_t *src)
339
0
{
340
0
  mi_item_t *copy;
341
342
0
  _init_mi_shm_mem_hooks();
343
344
0
  copy = cJSON_Duplicate(src, 1);
345
346
0
  _init_mi_pkg_mem_hooks();
347
348
0
  return copy;
349
0
}
350
351
void free_shm_mi_item(mi_item_t *item)
352
0
{
353
0
  _init_mi_shm_mem_hooks();
354
355
0
  cJSON_Delete(item);
356
357
0
  _init_mi_pkg_mem_hooks();
358
0
}
359
360
static mi_item_t * _get_mi_param(const mi_params_t *params, char *name)
361
0
{
362
0
  int i;
363
364
0
  if (!params->item)
365
0
    return NULL;
366
367
0
  if (MI_ITEM_IS_ARRAY(params->item)) {
368
0
    for (i = 0; params->list[i]; i++)
369
0
      if (!strcmp(params->list[i], name))
370
0
        break;
371
372
0
    if (!params->list[i])
373
0
      return NULL;
374
375
0
    return cJSON_GetArrayItem(params->item, i);
376
0
  } else
377
0
    return cJSON_GetObjectItem(params->item, name);
378
0
}
379
380
int try_get_mi_int_param(const mi_params_t *params, char *name, int *value)
381
0
{
382
0
  mi_item_t *p;
383
0
  str st;
384
385
0
  param_err_pname = name;
386
387
0
  p = _get_mi_param(params, name);
388
0
  if (!p) {
389
0
    param_err_type = MI_PARAM_ERR_MISSING;
390
0
    return MI_PARAM_ERR_MISSING;
391
0
  }
392
393
0
  if (!(p->type & (cJSON_Number|cJSON_String))) {
394
0
    param_err_type = MI_PARAM_ERR_BAD_TYPE;
395
0
    return MI_PARAM_ERR_BAD_TYPE;
396
0
  }
397
398
0
  if (p->type & cJSON_Number) {
399
0
    *value = p->valueint;
400
0
  } else {
401
0
    st.s = p->valuestring;
402
0
    st.len = strlen(st.s);
403
0
    if (str2sint(&st, value) < 0) {
404
0
      param_err_type = MI_PARAM_ERR_BAD_TYPE;
405
0
      return MI_PARAM_ERR_BAD_TYPE;
406
0
    }
407
0
  }
408
409
0
  return 0;
410
0
}
411
412
int get_mi_int_param(const mi_params_t *params, char *name, int *value)
413
0
{
414
0
  switch (try_get_mi_int_param(params, name, value))
415
0
  {
416
0
    case MI_PARAM_ERR_MISSING:
417
0
      LM_ERR("Parameter: %s not found\n", name);
418
0
      break;
419
0
    case MI_PARAM_ERR_BAD_TYPE:
420
0
      LM_ERR("Parameter: %s is not an valid integer\n", name);
421
0
      break;
422
0
    case 0:
423
0
      return 0;
424
0
  }
425
0
  return -1;
426
0
}
427
428
int try_get_mi_string_param(const mi_params_t *params, char *name,
429
          char **value, int *value_len)
430
0
{
431
0
  mi_item_t *p;
432
433
0
  param_err_pname = name;
434
435
0
  p = _get_mi_param(params, name);
436
0
  if (!p) {
437
0
    param_err_type = MI_PARAM_ERR_MISSING;
438
0
    return MI_PARAM_ERR_MISSING;
439
0
  }
440
441
0
  if (!(p->type & (cJSON_Number|cJSON_String))) {
442
0
    param_err_type = MI_PARAM_ERR_BAD_TYPE;
443
0
    return MI_PARAM_ERR_BAD_TYPE;
444
0
  }
445
446
0
  if (p->type & cJSON_String) {
447
0
    *value = p->valuestring;
448
0
    *value_len = strlen(p->valuestring);
449
0
  } else {
450
0
    *value = sint2str(p->valueint, value_len);
451
0
  }
452
453
0
  return 0;
454
0
}
455
456
int get_mi_string_param(const mi_params_t *params, char *name,
457
          char **value, int *value_len)
458
0
{
459
0
  switch (try_get_mi_string_param(params, name, value, value_len))
460
0
  {
461
0
    case MI_PARAM_ERR_MISSING:
462
0
      LM_ERR("Parameter: %s not found\n", name);
463
0
      break;
464
0
    case MI_PARAM_ERR_BAD_TYPE:
465
0
      LM_ERR("Bad data type for parameter: %s\n", name);
466
0
      break;
467
0
    case 0:
468
0
      return 0;
469
0
  }
470
0
  return -1;
471
0
}
472
473
474
int get_mi_bool_like_param(const mi_params_t *params, char *name,
475
          int default_value)
476
0
{
477
0
  str tmp;
478
479
0
  if (try_get_mi_string_param(params, name, &tmp.s, &tmp.len) != 0)
480
0
    return default_value;
481
482
0
  if (tmp.len != 1)
483
0
    return default_value;
484
485
0
  if (tmp.s[0] == '0' || tmp.s[0] == 'n' || tmp.s[0] == 'N')
486
0
    return 0;
487
  
488
0
  if (tmp.s[0] == '1' || tmp.s[0] == 'y' || tmp.s[0] == 'Y')
489
0
    return 1;
490
491
0
  return default_value;
492
0
}
493
494
int try_get_mi_array_param(const mi_params_t *params, char *name,
495
          mi_item_t **value, int *no_items)
496
0
{
497
0
  mi_item_t *p;
498
499
0
  param_err_pname = name;
500
501
0
  p = _get_mi_param(params, name);;
502
0
  if (!p) {
503
0
    param_err_type = MI_PARAM_ERR_MISSING;
504
0
    return MI_PARAM_ERR_MISSING;
505
0
  }
506
507
0
  if (!(p->type & cJSON_Array)) {
508
0
    param_err_type = MI_PARAM_ERR_BAD_TYPE;
509
0
    return MI_PARAM_ERR_BAD_TYPE;
510
0
  }
511
512
0
  *value = p;
513
0
  *no_items = cJSON_GetArraySize(p);
514
0
  if (*no_items == 0) {
515
0
    param_err_type = MI_PARAM_ERR_EMPTY_ARR;
516
0
    return MI_PARAM_ERR_EMPTY_ARR;
517
0
  }
518
519
0
  return 0;
520
0
}
521
522
int get_mi_array_param(const mi_params_t *params, char *name,
523
          mi_item_t **value, int *no_items)
524
0
{
525
0
  switch (try_get_mi_array_param(params, name, value, no_items))
526
0
  {
527
0
    case MI_PARAM_ERR_MISSING:
528
0
      LM_ERR("Parameter: %s not found\n", name);
529
0
      break;
530
0
    case MI_PARAM_ERR_BAD_TYPE:
531
0
      LM_ERR("Parameter: %s is not an array\n", name);
532
0
      break;
533
0
    case MI_PARAM_ERR_EMPTY_ARR:
534
0
      LM_ERR("Empty array for parameter: %s\n", name);
535
0
      break;
536
0
    case 0:
537
0
      return 0;
538
0
  }
539
0
  return -1;
540
0
}
541
542
int try_get_mi_arr_param_string(const mi_item_t *array, int pos,
543
            char **value, int *value_len)
544
0
{
545
0
  mi_item_t *s;
546
547
0
  if (!array) {
548
0
    param_err_type = MI_PARAM_ERR_MISSING;
549
0
    return MI_PARAM_ERR_MISSING;
550
0
  }
551
552
0
  s = cJSON_GetArrayItem(array, pos);
553
0
  if (!s) {
554
0
    param_err_type = MI_PARAM_ERR_MISSING;
555
0
    return MI_PARAM_ERR_MISSING;
556
0
  }
557
558
0
  if (!(s->type & (cJSON_Number|cJSON_String))) {
559
0
    param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE;
560
0
    return MI_PARAM_ERR_ARR_BAD_TYPE;
561
0
  }
562
563
0
  if (s->type & cJSON_String) {
564
0
    *value = s->valuestring;
565
0
    *value_len = strlen(s->valuestring);
566
0
  } else {
567
0
    *value = sint2str(s->valueint, value_len);
568
0
  }
569
570
0
  return 0;
571
0
}
572
573
int get_mi_arr_param_string(const mi_item_t *array, int pos,
574
            char **value, int *value_len)
575
0
{
576
0
  switch (try_get_mi_arr_param_string(array, pos, value, value_len))
577
0
  {
578
0
    case MI_PARAM_ERR_MISSING:
579
0
      LM_ERR("Array index out of bounds\n");
580
0
      break;
581
0
    case MI_PARAM_ERR_ARR_BAD_TYPE:
582
0
      LM_ERR("Bad data type for array item\n");
583
0
      break;
584
0
    case 0:
585
0
      return 0;
586
0
  }
587
0
  return -1;
588
0
}
589
590
int try_get_mi_arr_param_int(const mi_item_t *array, int pos, int *value)
591
0
{
592
0
  mi_item_t *i;
593
0
  str st;
594
595
0
  if (!array) {
596
0
    param_err_type = MI_PARAM_ERR_MISSING;
597
0
    return MI_PARAM_ERR_MISSING;
598
0
  }
599
600
0
  i = cJSON_GetArrayItem(array, pos);
601
0
  if (!i) {
602
0
    param_err_type = MI_PARAM_ERR_MISSING;
603
0
    return MI_PARAM_ERR_MISSING;
604
0
  }
605
606
0
  if (!(i->type & (cJSON_Number|cJSON_String))) {
607
0
    param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE;
608
0
    return MI_PARAM_ERR_ARR_BAD_TYPE;
609
0
  }
610
611
0
  if (i->type & cJSON_Number) {
612
0
    *value = i->valueint;
613
0
  } else {
614
0
    st.s = i->valuestring;
615
0
    st.len = strlen(st.s);
616
0
    if (str2sint(&st, value) < 0) {
617
0
      param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE;
618
0
      return MI_PARAM_ERR_ARR_BAD_TYPE;
619
0
    }
620
0
  }
621
622
0
  return 0;
623
0
}
624
625
int get_mi_arr_param_int(const mi_item_t *array, int pos, int *value)
626
0
{
627
0
  switch (try_get_mi_arr_param_int(array, pos, value))
628
0
  {
629
0
    case MI_PARAM_ERR_MISSING:
630
0
      LM_ERR("Array index out of bounds\n");
631
0
      break;
632
0
    case MI_PARAM_ERR_ARR_BAD_TYPE:
633
0
      LM_ERR("Array item is not an integer\n");
634
0
      break;
635
0
    case 0:
636
0
      return 0;
637
0
  }
638
0
  return -1;
639
0
}
640
641
int try_get_mi_arr_param_object(const mi_item_t *array, int pos,
642
            mi_item_t **s)
643
0
{
644
0
  if (!array) {
645
0
    param_err_type = MI_PARAM_ERR_MISSING;
646
0
    return MI_PARAM_ERR_MISSING;
647
0
  }
648
649
0
  *s = cJSON_GetArrayItem(array, pos);
650
0
  if (!*s) {
651
0
    param_err_type = MI_PARAM_ERR_MISSING;
652
0
    return MI_PARAM_ERR_MISSING;
653
0
  }
654
655
0
  if (!((*s)->type & (cJSON_Object))) {
656
0
    param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE;
657
0
    return MI_PARAM_ERR_ARR_BAD_TYPE;
658
0
  }
659
660
0
  return 0;
661
0
}
662
663
int get_mi_arr_param_object(const mi_item_t *array, int pos,
664
            mi_item_t **s)
665
0
{
666
0
  switch (try_get_mi_arr_param_object(array, pos, s))
667
0
  {
668
0
    case MI_PARAM_ERR_MISSING:
669
0
      LM_ERR("Array index out of bounds\n");
670
0
      break;
671
0
    case MI_PARAM_ERR_ARR_BAD_TYPE:
672
0
      LM_ERR("Bad data type for array item\n");
673
0
      break;
674
0
    case 0:
675
0
      return 0;
676
0
  }
677
0
  return -1;
678
0
}
679
680
681
mi_response_t *init_mi_param_error(void)
682
0
{
683
0
  char param_err_buf[MI_PARAM_ERR_BUFLEN];
684
0
  int len;
685
686
0
  switch (param_err_type) {
687
0
    case MI_PARAM_ERR_BAD_TYPE:
688
0
      len = snprintf(param_err_buf, MI_PARAM_ERR_BUFLEN,
689
0
        "Bad type for parameter '%s'", param_err_pname);
690
0
      if (len)
691
0
        return init_mi_error_extra(JSONRPC_INVAL_PARAMS_CODE,
692
0
          MI_SSTR(JSONRPC_INVAL_PARAMS_MSG), param_err_buf, len);
693
0
      break;
694
0
    case MI_PARAM_ERR_ARR_BAD_TYPE:
695
0
      len = snprintf(param_err_buf, MI_PARAM_ERR_BUFLEN,
696
0
        "Bad type for array item in parameter '%s'", param_err_pname);
697
0
      if (len)
698
0
        return init_mi_error_extra(JSONRPC_INVAL_PARAMS_CODE,
699
0
          MI_SSTR(JSONRPC_INVAL_PARAMS_MSG), param_err_buf, len);
700
0
      break;
701
0
    case MI_PARAM_ERR_EMPTY_ARR:
702
0
      len = snprintf(param_err_buf, MI_PARAM_ERR_BUFLEN,
703
0
        "Empty array in parameter '%s'", param_err_pname);
704
0
      if (len)
705
0
        return init_mi_error_extra(JSONRPC_INVAL_PARAMS_CODE,
706
0
          MI_SSTR(JSONRPC_INVAL_PARAMS_MSG), param_err_buf, len);
707
0
      break;
708
0
    case MI_PARAM_ERR_MISSING:
709
      /* the call has already been matched with one of the MI recipes so
710
       * treat a missing parameter as an unexpected server error (possibly
711
       * a bad param name was used by the handler when getting a param) */
712
0
      break;
713
0
  }
714
715
0
  return init_mi_error_extra(JSONRPC_SERVER_ERR_CODE,
716
0
    MI_SSTR(JSONRPC_SERVER_ERR_MSG), MI_SSTR(ERR_DET_PARAM_HANDLE_S));
717
0
}