Browse code

pv: check parameters and fix log message for invalid values for {s.fmtline...}

Daniel-Constantin Mierla authored on 05/05/2022 09:38:41
Showing 1 changed files
... ...
@@ -1476,14 +1476,14 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
1476 1476
 				if(pv_get_spec_value(msg, (pv_spec_p)tp->next->v.data, &v)!=0
1477 1477
 						|| (!(v.flags&PV_VAL_INT)))
1478 1478
 				{
1479
-					LM_ERR("fmt cannot get p2 (cfg line: %d)\n",
1479
+					LM_ERR("fmtline cannot get p2 (cfg line: %d)\n",
1480 1480
 							get_cfg_crt_line());
1481 1481
 					return -1;
1482 1482
 				}
1483 1483
 				m = v.ri;
1484 1484
 			}
1485
-			if(n<0 || m<0) {
1486
-				LM_ERR("substr negative offset (cfg line: %d)\n",
1485
+			if(n<=0 || m<0) {
1486
+				LM_ERR("fmtline with invalid parameters (cfg line: %d)\n",
1487 1487
 						get_cfg_crt_line());
1488 1488
 				return -1;
1489 1489
 			}
Browse code

pv: free escaped value for {val.json} transformations

Daniel-Constantin Mierla authored on 07/12/2021 08:27:17
Showing 1 changed files
... ...
@@ -2580,6 +2580,7 @@ int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2580 2580
 					return 0;
2581 2581
 				}
2582 2582
 				if(sv.len >= TR_BUFFER_SIZE - 1) {
2583
+					free(sv.s);
2583 2584
 					LM_ERR("escaped value is too long\n");
2584 2585
 					return -1;
2585 2586
 				}
... ...
@@ -2588,6 +2589,7 @@ int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2588 2589
 				_tr_buffer[sv.len] = '\0';
2589 2590
 				val->rs.s = _tr_buffer;
2590 2591
 				val->rs.len = sv.len;
2592
+				free(sv.s);
2591 2593
 			}
2592 2594
 			break;
2593 2595
 		case TR_VAL_JSONQE:
... ...
@@ -2601,7 +2603,8 @@ int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2601 2603
 				val->rs.len = 2;
2602 2604
 				val->flags = PV_VAL_STR;
2603 2605
 			} else if(val->flags&PV_TYPE_INT) {
2604
-				break;
2606
+				/* no change needed */
2607
+				return 0;
2605 2608
 			} else if(val->flags&PV_VAL_STR) {
2606 2609
 				ksr_str_json_escape(&val->rs, &sv, &emode);
2607 2610
 				if(sv.s==NULL) {
... ...
@@ -2613,6 +2616,7 @@ int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2613 2616
 					return 0;
2614 2617
 				}
2615 2618
 				if(sv.len >= TR_BUFFER_SIZE - 3) {
2619
+					free(sv.s);
2616 2620
 					LM_ERR("escaped value is too long\n");
2617 2621
 					return -1;
2618 2622
 				}
... ...
@@ -2623,6 +2627,7 @@ int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2623 2627
 				_tr_buffer[sv.len + 2] = '\0';
2624 2628
 				val->rs.s = _tr_buffer;
2625 2629
 				val->rs.len = sv.len + 2;
2630
+				free(sv.s);
2626 2631
 			}
2627 2632
 			break;
2628 2633
 
Browse code

pv: added {val.jsonqe} - quoted json value

Daniel-Constantin Mierla authored on 06/12/2021 13:52:45
Showing 1 changed files
... ...
@@ -2590,6 +2590,41 @@ int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2590 2590
 				val->rs.len = sv.len;
2591 2591
 			}
2592 2592
 			break;
2593
+		case TR_VAL_JSONQE:
2594
+			if(val->flags&PV_VAL_NULL) {
2595
+				val->ri = 0;
2596
+				tr_set_crt_buffer();
2597
+				val->rs.s = _tr_buffer;
2598
+				val->rs.s[0] = '"';
2599
+				val->rs.s[1] = '"';
2600
+				val->rs.s[2] = '\0';
2601
+				val->rs.len = 2;
2602
+				val->flags = PV_VAL_STR;
2603
+			} else if(val->flags&PV_TYPE_INT) {
2604
+				break;
2605
+			} else if(val->flags&PV_VAL_STR) {
2606
+				ksr_str_json_escape(&val->rs, &sv, &emode);
2607
+				if(sv.s==NULL) {
2608
+					LM_ERR("failed to escape the value\n");
2609
+					return -1;
2610
+				}
2611
+				if(emode==0) {
2612
+					/* no escape was needed */
2613
+					return 0;
2614
+				}
2615
+				if(sv.len >= TR_BUFFER_SIZE - 3) {
2616
+					LM_ERR("escaped value is too long\n");
2617
+					return -1;
2618
+				}
2619
+				tr_set_crt_buffer();
2620
+				_tr_buffer[0] = '"';
2621
+				memcpy(_tr_buffer + 1, sv.s, sv.len);
2622
+				_tr_buffer[sv.len + 1] = '"';
2623
+				_tr_buffer[sv.len + 2] = '\0';
2624
+				val->rs.s = _tr_buffer;
2625
+				val->rs.len = sv.len + 2;
2626
+			}
2627
+			break;
2593 2628
 
2594 2629
 		default:
2595 2630
 			LM_ERR("unknown subtype %d\n",
... ...
@@ -3847,6 +3882,9 @@ char* tr_parse_val(str* in, trans_t *t)
3847 3882
 	} else if(name.len==4 && strncasecmp(name.s, "json", 4)==0) {
3848 3883
 		t->subtype = TR_VAL_JSON;
3849 3884
 		goto done;
3885
+	} else if(name.len==6 && strncasecmp(name.s, "jsonqe", 6)==0) {
3886
+		t->subtype = TR_VAL_JSONQE;
3887
+		goto done;
3850 3888
 	}
3851 3889
 
3852 3890
 
Browse code

pv: added {val.ne} transformation

- return empty string if the variable value is $null

Daniel-Constantin Mierla authored on 22/11/2021 17:54:02
Showing 1 changed files
... ...
@@ -2551,6 +2551,16 @@ int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2551 2551
 				val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR;
2552 2552
 			}
2553 2553
 			break;
2554
+		case TR_VAL_NE:
2555
+			if(val->flags&PV_VAL_NULL) {
2556
+				val->ri = 0;
2557
+				tr_set_crt_buffer();
2558
+				val->rs.s = _tr_buffer;
2559
+				val->rs.s[0] = '\0';
2560
+				val->rs.len = 0;
2561
+				val->flags = PV_VAL_STR;
2562
+			}
2563
+			break;
2554 2564
 		case TR_VAL_JSON:
2555 2565
 			if(val->flags&PV_VAL_NULL) {
2556 2566
 				val->ri = 0;
... ...
@@ -3831,6 +3841,9 @@ char* tr_parse_val(str* in, trans_t *t)
3831 3841
 	if(name.len==2 && strncasecmp(name.s, "n0", 2)==0) {
3832 3842
 		t->subtype = TR_VAL_N0;
3833 3843
 		goto done;
3844
+	} else if(name.len==2 && strncasecmp(name.s, "ne", 2)==0) {
3845
+		t->subtype = TR_VAL_NE;
3846
+		goto done;
3834 3847
 	} else if(name.len==4 && strncasecmp(name.s, "json", 4)==0) {
3835 3848
 		t->subtype = TR_VAL_JSON;
3836 3849
 		goto done;
Browse code

pv: new transformation class {val}

- {val.n0} - return int 0 instead of $null value, or existing value
- {val.json} - if value is $null, return empty string; if value is
string, then it is escaped for use as json value (without surrounding
quotes)

Daniel-Constantin Mierla authored on 17/11/2021 16:16:17
Showing 1 changed files
... ...
@@ -2521,6 +2521,76 @@ int tr_eval_urialias(struct sip_msg *msg, tr_param_t *tp, int subtype,
2521 2521
 }
2522 2522
 
2523 2523
 
2524
+/*!
2525
+ * \brief Evaluate val transformations
2526
+ * \param msg SIP message
2527
+ * \param tp transformation
2528
+ * \param subtype transformation type
2529
+ * \param val pseudo-variable
2530
+ * \return 0 on success, -1 on error
2531
+ */
2532
+int tr_eval_val(struct sip_msg *msg, tr_param_t *tp, int subtype,
2533
+		pv_value_t *val)
2534
+{
2535
+	str sv;
2536
+	int emode = 0;
2537
+
2538
+	if(val==NULL)
2539
+		return -1;
2540
+
2541
+	switch(subtype)
2542
+	{
2543
+		case TR_VAL_N0:
2544
+			if(val->flags&PV_VAL_NULL) {
2545
+				val->ri = 0;
2546
+				tr_set_crt_buffer();
2547
+				val->rs.s = _tr_buffer;
2548
+				val->rs.s[0] = '0';
2549
+				val->rs.s[1] = '\0';
2550
+				val->rs.len = 1;
2551
+				val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR;
2552
+			}
2553
+			break;
2554
+		case TR_VAL_JSON:
2555
+			if(val->flags&PV_VAL_NULL) {
2556
+				val->ri = 0;
2557
+				tr_set_crt_buffer();
2558
+				val->rs.s = _tr_buffer;
2559
+				val->rs.s[0] = '\0';
2560
+				val->rs.len = 0;
2561
+				val->flags = PV_VAL_STR;
2562
+			} else if(val->flags&PV_VAL_STR) {
2563
+				ksr_str_json_escape(&val->rs, &sv, &emode);
2564
+				if(sv.s==NULL) {
2565
+					LM_ERR("failed to escape the value\n");
2566
+					return -1;
2567
+				}
2568
+				if(emode==0) {
2569
+					/* no escape was needed */
2570
+					return 0;
2571
+				}
2572
+				if(sv.len >= TR_BUFFER_SIZE - 1) {
2573
+					LM_ERR("escaped value is too long\n");
2574
+					return -1;
2575
+				}
2576
+				tr_set_crt_buffer();
2577
+				memcpy(_tr_buffer, sv.s, sv.len);
2578
+				_tr_buffer[sv.len] = '\0';
2579
+				val->rs.s = _tr_buffer;
2580
+				val->rs.len = sv.len;
2581
+			}
2582
+			break;
2583
+
2584
+		default:
2585
+			LM_ERR("unknown subtype %d\n",
2586
+					subtype);
2587
+			return -1;
2588
+	}
2589
+
2590
+	return 0;
2591
+}
2592
+
2593
+
2524 2594
 #define _tr_parse_nparam(_p, _p0, _tp, _spec, _n, _sign, _in, _s) \
2525 2595
 	while(is_in_str(_p, _in) && (*_p==' ' || *_p=='\t' || *_p=='\n')) _p++; \
2526 2596
 	if(*_p==PV_MARKER) \
... ...
@@ -3717,6 +3787,56 @@ char* tr_parse_urialias(str* in, trans_t *t)
3717 3787
 	}
3718 3788
 
3719 3789
 
3790
+	LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s,
3791
+			name.len, name.s, name.len);
3792
+error:
3793
+	return NULL;
3794
+
3795
+done:
3796
+	t->name = name;
3797
+	return p;
3798
+}
3799
+
3800
+
3801
+/*!
3802
+ * \brief Helper fuction to parse val transformation
3803
+ * \param in parsed string
3804
+ * \param t transformation
3805
+ * \return pointer to the end of the transformation in the string - '}', null on error
3806
+ */
3807
+char* tr_parse_val(str* in, trans_t *t)
3808
+{
3809
+	char *p;
3810
+	str name;
3811
+
3812
+
3813
+	if(in==NULL || t==NULL)
3814
+		return NULL;
3815
+
3816
+	p = in->s;
3817
+	name.s = in->s;
3818
+	t->type = TR_VAL;
3819
+	t->trf = tr_eval_val;
3820
+
3821
+	/* find next token */
3822
+	while(is_in_str(p, in) && *p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) p++;
3823
+	if(*p=='\0') {
3824
+		LM_ERR("invalid transformation: %.*s\n",
3825
+				in->len, in->s);
3826
+		goto error;
3827
+	}
3828
+	name.len = p - name.s;
3829
+	trim(&name);
3830
+
3831
+	if(name.len==2 && strncasecmp(name.s, "n0", 2)==0) {
3832
+		t->subtype = TR_VAL_N0;
3833
+		goto done;
3834
+	} else if(name.len==4 && strncasecmp(name.s, "json", 4)==0) {
3835
+		t->subtype = TR_VAL_JSON;
3836
+		goto done;
3837
+	}
3838
+
3839
+
3720 3840
 	LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s,
3721 3841
 			name.len, name.s, name.len);
3722 3842
 error:
Browse code

pv: {line.count} - count last line without \n

Daniel-Constantin Mierla authored on 07/10/2021 07:21:20
Showing 1 changed files
... ...
@@ -2435,19 +2435,22 @@ int tr_eval_line(struct sip_msg *msg, tr_param_t *tp, int subtype,
2435 2435
 			break;
2436 2436
 
2437 2437
 		case TR_LINE_COUNT:
2438
-			n=0;
2439
-			for(i=0; i<val->rs.len; i++)
2440
-				if(val->rs.s[i]=='\n')
2438
+			n = 0;
2439
+			if(val->rs.len>0) {
2440
+				for(i=0; i<val->rs.len; i++) {
2441
+					if(val->rs.s[i]=='\n') {
2442
+						n++;
2443
+					}
2444
+				}
2445
+				if(val->rs.s[val->rs.len-1]!='\n') {
2441 2446
 					n++;
2442
-			if(n==0 && val->rs.len>0)
2443
-				n = 1;
2447
+				}
2448
+			}
2444 2449
 			val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR;
2445 2450
 			val->ri = n;
2446 2451
 			val->rs.s = int2str(val->ri, &val->rs.len);
2447 2452
 			break;
2448 2453
 
2449
-			break;
2450
-
2451 2454
 		default:
2452 2455
 			LM_ERR("unknown subtype %d\n",
2453 2456
 					subtype);
Browse code

pv: removed unused code in parsing paramlist transformation name

Daniel-Constantin Mierla authored on 10/08/2021 08:36:00
Showing 1 changed files
... ...
@@ -3460,8 +3460,6 @@ unknown:
3460 3460
 	LM_ERR("unknown transformation: %.*s/%.*s!\n",
3461 3461
 			in->len, in->s, name.len, name.s);
3462 3462
 error:
3463
-	if(tp)
3464
-		tr_param_free(tp);
3465 3463
 	if(spec)
3466 3464
 		pv_spec_free(spec);
3467 3465
 	return NULL;
Browse code

pv: added {s.fmtlines,n,m} and {s.fmtlinet,n,m}

- format the value in lines of n characters, adding m spaces or tabs to
the start of each new line (not to first line)

Daniel-Constantin Mierla authored on 25/06/2021 08:58:23
Showing 1 changed files
... ...
@@ -189,7 +189,7 @@ static int getNumericValue(str sin) {
189 189
 int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
190 190
 		pv_value_t *val)
191 191
 {
192
-	int i, j, max;
192
+	int i, j, n, m, max;
193 193
 	char *p, *s;
194 194
 	char c;
195 195
 	str st, st2;
... ...
@@ -1446,6 +1446,88 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
1446 1446
 			val->rs.s[val->rs.len] = '\0';
1447 1447
 			break;
1448 1448
 
1449
+		case TR_S_FMTLINES:
1450
+		case TR_S_FMTLINET:
1451
+			if(tp==NULL || tp->next==NULL)
1452
+			{
1453
+				LM_ERR("substr invalid parameters (cfg line: %d)\n",
1454
+						get_cfg_crt_line());
1455
+				return -1;
1456
+			}
1457
+			if(!(val->flags&PV_VAL_STR))
1458
+				val->rs.s = int2str(val->ri, &val->rs.len);
1459
+			if(tp->type==TR_PARAM_NUMBER)
1460
+			{
1461
+				n = tp->v.n;
1462
+			} else {
1463
+				if(pv_get_spec_value(msg, (pv_spec_p)tp->v.data, &v)!=0
1464
+						|| (!(v.flags&PV_VAL_INT)))
1465
+				{
1466
+					LM_ERR("fmtline cannot get p1 (cfg line: %d)\n",
1467
+							get_cfg_crt_line());
1468
+					return -1;
1469
+				}
1470
+				n = v.ri;
1471
+			}
1472
+			if(tp->next->type==TR_PARAM_NUMBER)
1473
+			{
1474
+				m = tp->next->v.n;
1475
+			} else {
1476
+				if(pv_get_spec_value(msg, (pv_spec_p)tp->next->v.data, &v)!=0
1477
+						|| (!(v.flags&PV_VAL_INT)))
1478
+				{
1479
+					LM_ERR("fmt cannot get p2 (cfg line: %d)\n",
1480
+							get_cfg_crt_line());
1481
+					return -1;
1482
+				}
1483
+				m = v.ri;
1484
+			}
1485
+			if(n<0 || m<0) {
1486
+				LM_ERR("substr negative offset (cfg line: %d)\n",
1487
+						get_cfg_crt_line());
1488
+				return -1;
1489
+			}
1490
+			if(n==0 || m>=val->rs.len) {
1491
+				if(val->rs.len>TR_BUFFER_SIZE-2) {
1492
+					LM_ERR("value too large: %d\n", val->rs.len);
1493
+					return -1;
1494
+				}
1495
+
1496
+				memcpy(_tr_buffer, val->rs.s, val->rs.len);
1497
+				val->flags = PV_VAL_STR;
1498
+				val->rs.s = _tr_buffer;
1499
+				val->rs.s[val->rs.len] = '\0';
1500
+			}
1501
+			if(val->rs.len + (((val->rs.len)/n)*(2+m)) > TR_BUFFER_SIZE-2) {
1502
+				LM_ERR("value too large: %d\n", val->rs.len);
1503
+				return -1;
1504
+			}
1505
+
1506
+			p = _tr_buffer;
1507
+			for(i=0; i<val->rs.len; i++) {
1508
+				if(i!=0 && (i/n)==0) {
1509
+					*p = '\r';
1510
+					p++;
1511
+					*p = '\n';
1512
+					p++;
1513
+					for(j=0; j<m; j++) {
1514
+						if(subtype==TR_S_FMTLINES) {
1515
+							*p = ' ';
1516
+						} else {
1517
+							*p = '\t';
1518
+						}
1519
+						p++;
1520
+					}
1521
+				}
1522
+				*p = val->rs.s[i];
1523
+				p++;
1524
+			}
1525
+			val->flags = PV_VAL_STR;
1526
+			val->rs.s = _tr_buffer;
1527
+			val->rs.len = p - _tr_buffer;
1528
+			val->rs.s[val->rs.len] = '\0';
1529
+			break;
1530
+
1449 1531
 		default:
1450 1532
 			LM_ERR("unknown subtype %d (cfg line: %d)\n",
1451 1533
 					subtype, get_cfg_crt_line());
... ...
@@ -3071,6 +3153,53 @@ char* tr_parse_string(str* in, trans_t *t)
3071 3153
 			goto error;
3072 3154
 		}
3073 3155
 		goto done;
3156
+	} else if(name.len==8 && (strncasecmp(name.s, "fmtlines", 8)==0
3157
+				|| strncasecmp(name.s, "fmtlinet", 8)==0)) {
3158
+		if(name.s[7]=='s' || name.s[7]=='S') {
3159
+			t->subtype = TR_S_FMTLINES;
3160
+		} else {
3161
+			t->subtype = TR_S_FMTLINET;
3162
+		}
3163
+		if(*p!=TR_PARAM_MARKER)
3164
+		{
3165
+			LM_ERR("invalid fmtline%c transformation: %.*s!\n", name.s[7],
3166
+					in->len, in->s);
3167
+			goto error;
3168
+		}
3169
+		p++;
3170
+		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s);
3171
+		if(tp->type==TR_PARAM_NUMBER && tp->v.n<0)
3172
+		{
3173
+			LM_ERR("fmtline%c negative line length value\n", name.s[7]);
3174
+			goto error;
3175
+		}
3176
+
3177
+		t->params = tp;
3178
+		tp = 0;
3179
+		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3180
+		if(*p!=TR_PARAM_MARKER)
3181
+		{
3182
+			LM_ERR("invalid fmtline%c transformation: %.*s!\n",
3183
+					 name.s[7], in->len, in->s);
3184
+			goto error;
3185
+		}
3186
+		p++;
3187
+		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s);
3188
+		if(tp->type==TR_PARAM_NUMBER && tp->v.n<0)
3189
+		{
3190
+			LM_ERR("fmtline%c negative padding lenght value\n", name.s[7]);
3191
+			goto error;
3192
+		}
3193
+		t->params->next = tp;
3194
+		tp = 0;
3195
+		while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3196
+		if(*p!=TR_RBRACKET)
3197
+		{
3198
+			LM_ERR("invalid fmtline%c transformation: %.*s!!\n",
3199
+					name.s[7], in->len, in->s);
3200
+			goto error;
3201
+		}
3202
+		goto done;
3074 3203
 	}
3075 3204
 
3076 3205
 	LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s,
Browse code

pv: added {s.rafter,x} and {s.rbefore,x}

- similar to {s.after,x} and {s.before,x}, but searches from end of the
value

Daniel-Constantin Mierla authored on 25/06/2021 07:51:10
Showing 1 changed files
... ...
@@ -1340,6 +1340,7 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
1340 1340
 			break;
1341 1341
 
1342 1342
 		case TR_S_BEFORE:
1343
+		case TR_S_RBEFORE:
1343 1344
 			if(tp==NULL)
1344 1345
 			{
1345 1346
 				LM_ERR("invalid parameters (cfg line: %d)\n",
... ...
@@ -1366,11 +1367,20 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
1366 1367
 				}
1367 1368
 				st = v.rs;
1368 1369
 			}
1369
-			for(i=0; i<val->rs.len; i++) {
1370
-				if(val->rs.s[i]==st.s[0]) {
1371
-					break;
1370
+			if(subtype==TR_S_BEFORE) {
1371
+				for(i=0; i<val->rs.len; i++) {
1372
+					if(val->rs.s[i]==st.s[0]) {
1373
+						break;
1374
+					}
1375
+				}
1376
+			} else {
1377
+				for(i=val->rs.len-1; i>=0; i++) {
1378
+					if(val->rs.s[i]==st.s[0]) {
1379
+						break;
1380
+					}
1372 1381
 				}
1373 1382
 			}
1383
+
1374 1384
 			if(i==0) {
1375 1385
 				_tr_buffer[0] = '\0';
1376 1386
 				val->rs.len = 0;
... ...
@@ -1384,6 +1394,7 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
1384 1394
 			break;
1385 1395
 
1386 1396
 		case TR_S_AFTER:
1397
+		case TR_S_RAFTER:
1387 1398
 			if(tp==NULL)
1388 1399
 			{
1389 1400
 				LM_ERR("invalid parameters (cfg line: %d)\n",
... ...
@@ -1410,9 +1421,17 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
1410 1421
 				}
1411 1422
 				st = v.rs;
1412 1423
 			}
1413
-			for(i=0; i<val->rs.len; i++) {
1414
-				if(val->rs.s[i]==st.s[0]) {
1415
-					break;
1424
+			if(subtype==TR_S_AFTER) {
1425
+				for(i=0; i<val->rs.len; i++) {
1426
+					if(val->rs.s[i]==st.s[0]) {
1427
+						break;
1428
+					}
1429
+				}
1430
+			} else {
1431
+				for(i=val->rs.len-1; i>=0; i++) {
1432
+					if(val->rs.s[i]==st.s[0]) {
1433
+						break;
1434
+					}
1416 1435
 				}
1417 1436
 			}
1418 1437
 			if(i>=val->rs.len-1) {
... ...
@@ -3012,6 +3031,46 @@ char* tr_parse_string(str* in, trans_t *t)
3012 3031
 			goto error;
3013 3032
 		}
3014 3033
 		goto done;
3034
+	} else if(name.len==7 && strncasecmp(name.s, "rbefore", 7)==0) {
3035
+		t->subtype = TR_S_RBEFORE;
3036
+		if(*p!=TR_PARAM_MARKER)
3037
+		{
3038
+			LM_ERR("invalid rbefore transformation: %.*s!\n",
3039
+					in->len, in->s);
3040
+			goto error;
3041
+		}
3042
+		p++;
3043
+		_tr_parse_sparamx(p, p0, tp, spec, ps, in, s, 1);
3044
+		t->params = tp;
3045
+		tp = 0;
3046
+		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3047
+		if(*p!=TR_RBRACKET)
3048
+		{
3049
+			LM_ERR("invalid rbefore transformation: %.*s!!\n",
3050
+					in->len, in->s);
3051
+			goto error;
3052
+		}
3053
+		goto done;
3054
+	} else if(name.len==6 && strncasecmp(name.s, "rafter", 6)==0) {
3055
+		t->subtype = TR_S_RAFTER;
3056
+		if(*p!=TR_PARAM_MARKER)
3057
+		{
3058
+			LM_ERR("invalid rafter transformation: %.*s!\n",
3059
+					in->len, in->s);
3060
+			goto error;
3061
+		}
3062
+		p++;
3063
+		_tr_parse_sparamx(p, p0, tp, spec, ps, in, s, 1);
3064
+		t->params = tp;
3065
+		tp = 0;
3066
+		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3067
+		if(*p!=TR_RBRACKET)
3068
+		{
3069
+			LM_ERR("invalid rafter transformation: %.*s!!\n",
3070
+					in->len, in->s);
3071
+			goto error;
3072
+		}
3073
+		goto done;
3015 3074
 	}
3016 3075
 
3017 3076
 	LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s,
Browse code

pv: fix {param.count} transformation broken by previous commit

Daniel-Constantin Mierla authored on 01/06/2021 17:45:16
Showing 1 changed files
... ...
@@ -3203,6 +3203,28 @@ char* tr_parse_paramlist(str* in, trans_t *t)
3203 3203
 		goto unknown;
3204 3204
 	}
3205 3205
 
3206
+	if(t->subtype == TR_PL_COUNT) {
3207
+		if(*p==TR_PARAM_MARKER) {
3208
+			start_pos = ++p;
3209
+			_tr_parse_sparamx(p, p0, tp, spec, ps, in, s, 1);
3210
+			t->params = tp;
3211
+			tp = 0;
3212
+			if (t->params->type != TR_PARAM_SPEC && p - start_pos != 1) {
3213
+				LM_ERR("invalid separator in transformation: "
3214
+						"%.*s\n", in->len, in->s);
3215
+				goto error;
3216
+			}
3217
+			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3218
+			if(*p!=TR_RBRACKET) {
3219
+				LM_ERR("invalid name transformation: %.*s!\n",
3220
+						in->len, in->s);
3221
+				goto error;
3222
+			}
3223
+		}
3224
+		goto done;
3225
+	}
3226
+
3227
+	/* now transformations with mandatory parameters */
3206 3228
 	if(*p!=TR_PARAM_MARKER)
3207 3229
 	{
3208 3230
 		LM_ERR("invalid %.*s transformation: %.*s\n",
... ...
@@ -3223,29 +3245,15 @@ char* tr_parse_paramlist(str* in, trans_t *t)
3223 3245
 		while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3224 3246
 	}
3225 3247
 
3226
-	if(t->subtype == TR_PL_COUNT) {
3227
-		if(*p==TR_PARAM_MARKER) {
3228
-			start_pos = ++p;
3229
-			_tr_parse_sparamx(p, p0, tp, spec, ps, in, s, 1);
3230
-			t->params = tp;
3231
-			tp = 0;
3232
-			if (tp->type != TR_PARAM_SPEC && p - start_pos != 1) {
3233
-				LM_ERR("invalid separator in transformation: "
3234
-						"%.*s\n", in->len, in->s);
3235
-				goto error;
3236
-			}
3237
-		}
3238
-	} else {
3239
-		if(*p==TR_PARAM_MARKER) {
3240
-			start_pos = ++p;
3241
-			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
3242
-			t->params->next = tp;
3243
-			tp = 0;
3244
-			if (p - start_pos != 1) {
3245
-				LM_ERR("invalid separator in transformation: "
3246
-						"%.*s\n", in->len, in->s);
3247
-				goto error;
3248
-			}
3248
+	if(*p==TR_PARAM_MARKER) {
3249
+		start_pos = ++p;
3250
+		_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
3251
+		t->params->next = tp;
3252
+		tp = 0;
3253
+		if (p - start_pos != 1) {
3254
+			LM_ERR("invalid separator in transformation: "
3255
+					"%.*s\n", in->len, in->s);
3256
+			goto error;
3249 3257
 		}
3250 3258
 	}
3251 3259
 
... ...
@@ -3256,6 +3264,7 @@ char* tr_parse_paramlist(str* in, trans_t *t)
3256 3264
 		goto error;
3257 3265
 	}
3258 3266
 
3267
+done:
3259 3268
 	t->name = name;
3260 3269
 	return p;
3261 3270
 
Browse code

pv: added {param.in,name[,sep]}

- return 1 if param name is found in the list, 0 if not found

Daniel-Constantin Mierla authored on 01/06/2021 08:36:26
Showing 1 changed files
... ...
@@ -1807,6 +1807,7 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype,
1807 1807
 	switch(subtype)
1808 1808
 	{
1809 1809
 		case TR_PL_VALUE:
1810
+		case TR_PL_IN:
1810 1811
 			if(tp==NULL)
1811 1812
 			{
1812 1813
 				LM_ERR("value invalid parameters\n");
... ...
@@ -1831,11 +1832,23 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype,
1831 1832
 				if (pit->name.len==sv.len
1832 1833
 						&& strncasecmp(pit->name.s, sv.s, sv.len)==0)
1833 1834
 				{
1834
-					val->rs = pit->body;
1835
+					if(subtype==TR_PL_IN) {
1836
+						val->ri = 1;
1837
+						val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR;
1838
+						val->rs.s = int2str(val->ri, &val->rs.len);
1839
+					} else {
1840
+						val->rs = pit->body;
1841
+					}
1835 1842
 					goto done;
1836 1843
 				}
1837 1844
 			}
1838
-			val->rs = _tr_empty;
1845
+			if(subtype==TR_PL_IN) {
1846
+				val->ri = 0;
1847
+				val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR;
1848
+				val->rs.s = int2str(val->ri, &val->rs.len);
1849
+			} else {
1850
+				val->rs = _tr_empty;
1851
+			}
1839 1852
 			break;
1840 1853
 
1841 1854
 		case TR_PL_VALUEAT:
... ...
@@ -3176,139 +3189,77 @@ char* tr_parse_paramlist(str* in, trans_t *t)
3176 3189
 	name.len = p - name.s;
3177 3190
 	trim(&name);
3178 3191
 
3179
-	if(name.len==5 && strncasecmp(name.s, "value", 5)==0)
3180
-	{
3192
+	if(name.len==5 && strncasecmp(name.s, "value", 5)==0) {
3181 3193
 		t->subtype = TR_PL_VALUE;
3182
-		if(*p!=TR_PARAM_MARKER)
3183
-		{
3184
-			LM_ERR("invalid value transformation: %.*s\n",
3185
-					in->len, in->s);
3186
-			goto error;
3187
-		}
3188
-		p++;
3194
+	} else if(name.len==2 && strncasecmp(name.s, "in", 2)==0) {
3195
+		t->subtype = TR_PL_IN;
3196
+	} else if(name.len==7 && strncasecmp(name.s, "valueat", 7)==0) {
3197
+		t->subtype = TR_PL_VALUEAT;
3198
+	} else if(name.len==4 && strncasecmp(name.s, "name", 4)==0) {
3199
+		t->subtype = TR_PL_NAME;
3200
+	} else if(name.len==5 && strncasecmp(name.s, "count", 5)==0) {
3201
+		t->subtype = TR_PL_COUNT;
3202
+	} else {
3203
+		goto unknown;
3204
+	}
3205
+
3206
+	if(*p!=TR_PARAM_MARKER)
3207
+	{
3208
+		LM_ERR("invalid %.*s transformation: %.*s\n",
3209
+				name.len, name.s, in->len, in->s);
3210
+		goto error;
3211
+	}
3212
+	p++;
3213
+
3214
+	if(t->subtype == TR_PL_VALUE || t->subtype == TR_PL_IN) {
3189 3215
 		_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
3190 3216
 		t->params = tp;
3191 3217
 		tp = 0;
3192 3218
 		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3193
-
3194
-		if(*p==TR_PARAM_MARKER)
3195
-		{
3196
-			start_pos = ++p;
3197
-			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
3198
-			t->params->next = tp;
3199
-			tp = 0;
3200
-			if (p - start_pos != 1)
3201
-			{
3202
-				LM_ERR("invalid separator in transformation: "
3203
-						"%.*s\n", in->len, in->s);
3204
-				goto error;
3205
-			}
3206
-			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3207
-		}
3208
-
3209
-		if(*p!=TR_RBRACKET)
3210
-		{
3211
-			LM_ERR("invalid value transformation: %.*s!\n",
3212
-					in->len, in->s);
3213
-			goto error;
3214
-		}
3215
-		goto done;
3216
-	} else if(name.len==7 && strncasecmp(name.s, "valueat", 7)==0) {
3217
-		t->subtype = TR_PL_VALUEAT;
3218
-		if(*p!=TR_PARAM_MARKER)
3219
-		{
3220
-			LM_ERR("invalid name transformation: %.*s\n",
3221
-					in->len, in->s);
3222
-			goto error;
3223
-		}
3224
-		p++;
3219
+	} else if(t->subtype == TR_PL_VALUEAT || t->subtype == TR_PL_NAME) {
3225 3220
 		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s)
3226 3221
 			t->params = tp;
3227 3222
 		tp = 0;
3228 3223
 		while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3224
+	}
3229 3225
 
3230
-		if(*p==TR_PARAM_MARKER)
3231
-		{
3226
+	if(t->subtype == TR_PL_COUNT) {
3227
+		if(*p==TR_PARAM_MARKER) {
3232 3228
 			start_pos = ++p;
3233
-			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
3234
-			t->params->next = tp;
3229
+			_tr_parse_sparamx(p, p0, tp, spec, ps, in, s, 1);
3230
+			t->params = tp;
3235 3231
 			tp = 0;
3236
-			if (p - start_pos != 1)
3237
-			{
3232
+			if (tp->type != TR_PARAM_SPEC && p - start_pos != 1) {
3238 3233
 				LM_ERR("invalid separator in transformation: "
3239 3234
 						"%.*s\n", in->len, in->s);
3240 3235
 				goto error;
3241 3236
 			}
3242
-			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3243
-		}
3244
-
3245
-		if(*p!=TR_RBRACKET)
3246
-		{
3247
-			LM_ERR("invalid name transformation: %.*s!\n",
3248
-					in->len, in->s);
3249
-			goto error;
3250
-		}
3251
-		goto done;
3252
-	} else if(name.len==4 && strncasecmp(name.s, "name", 4)==0) {
3253
-		t->subtype = TR_PL_NAME;
3254
-		if(*p!=TR_PARAM_MARKER)
3255
-		{
3256
-			LM_ERR("invalid name transformation: %.*s\n",
3257
-					in->len, in->s);
3258
-			goto error;
3259 3237
 		}
3260
-		p++;
3261
-		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s)
3262
-			t->params = tp;
3263
-		tp = 0;
3264
-		while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3265
-
3266
-		if(*p==TR_PARAM_MARKER)
3267
-		{
3238
+	} else {
3239
+		if(*p==TR_PARAM_MARKER) {
3268 3240
 			start_pos = ++p;
3269 3241
 			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
3270 3242
 			t->params->next = tp;
3271 3243
 			tp = 0;
3272
-			if (p - start_pos != 1)
3273
-			{
3274
-				LM_ERR("invalid separator in transformation: "
3275
-						"%.*s\n", in->len, in->s);
3276
-				goto error;
3277
-			}
3278
-			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3279
-		}
3280
-
3281
-		if(*p!=TR_RBRACKET)
3282
-		{
3283
-			LM_ERR("invalid name transformation: %.*s!\n",
3284
-					in->len, in->s);
3285
-			goto error;
3286
-		}
3287
-		goto done;
3288
-	} else if(name.len==5 && strncasecmp(name.s, "count", 5)==0) {
3289
-		t->subtype = TR_PL_COUNT;
3290
-		if(*p==TR_PARAM_MARKER) {
3291
-			start_pos = ++p;
3292
-			_tr_parse_sparamx(p, p0, tp, spec, ps, in, s, 1);
3293
-			t->params = tp;
3294
-			if (tp->type != TR_PARAM_SPEC && p - start_pos != 1) {
3244
+			if (p - start_pos != 1) {
3295 3245
 				LM_ERR("invalid separator in transformation: "
3296 3246
 						"%.*s\n", in->len, in->s);
3297 3247
 				goto error;
3298 3248
 			}
3299
-			tp = 0;
3300
-
3301
-			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3302
-			if(*p!=TR_RBRACKET) {
3303
-				LM_ERR("invalid name transformation: %.*s!\n",
3304
-						in->len, in->s);
3305
-				goto error;
3306
-			}
3307 3249
 		}
3250
+	}
3308 3251
 
3309
-		goto done;
3252
+	while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
3253
+	if(*p!=TR_RBRACKET) {
3254
+		LM_ERR("invalid %.*s transformation: %.*s!\n",
3255
+				name.len, name.s, in->len, in->s);
3256
+		goto error;
3310 3257
 	}
3311 3258
 
3259
+	t->name = name;
3260
+	return p;
3261
+
3262
+unknown:
3312 3263
 	LM_ERR("unknown transformation: %.*s/%.*s!\n",
3313 3264
 			in->len, in->s, name.len, name.s);
3314 3265
 error:
... ...
@@ -3317,9 +3268,6 @@ error:
3317 3268
 	if(spec)
3318 3269
 		pv_spec_free(spec);
3319 3270
 	return NULL;
3320
-done:
3321
-	t->name = name;
3322
-	return p;
3323 3271
 }
3324 3272
 
3325 3273
 
Browse code

pv: proper increment to check escaped char for s.select

Daniel-Constantin Mierla authored on 22/05/2021 15:53:50
Showing 1 changed files
... ...
@@ -2752,8 +2752,8 @@ char* tr_parse_string(str* in, trans_t *t)
2752 2752
 		tp->v.s.s = p;
2753 2753
 		tp->v.s.len = 1;
2754 2754
 		if(*p=='\\') {
2755
+			p++;
2755 2756
 			if(*p=='\\' || *p=='n' || *p=='r' || *p=='t') {
2756
-				p++;
2757 2757
 				tp->v.s.len = 2;
2758 2758
 			} else {
2759 2759
 				LM_ERR("unexpected escape char: %c\n", *p);
Browse code

pv: support escaped chars for s.select separator

- \\, \n, \r, \t

Daniel-Constantin Mierla authored on 21/05/2021 12:22:33
Showing 1 changed files
... ...
@@ -191,6 +191,7 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
191 191
 {
192 192
 	int i, j, max;
193 193
 	char *p, *s;
194
+	char c;
194 195
 	str st, st2;
195 196
 	pv_value_t v, w;
196 197
 	time_t t;
... ...
@@ -731,6 +732,28 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
731 732
 				}
732 733
 				i = v.ri;
733 734
 			}
735
+			if(tp->next->v.s.len>1) {
736
+				switch(tp->next->v.s.s[1]) {
737
+					case '\\':
738