Browse code

Merge ef5985563f4a7c222d4e2eb623df4fd049c057e1 into 9051033ac04fc94a0f19f8fbec6ec507fa6ab8d1

rhys-hanrahan authored on 17/05/2022 15:02:55 • GitHub committed on 17/05/2022 15:02:55
Showing 3 changed files
... ...
@@ -168,6 +168,7 @@ void dlg_clean_timer_exec(unsigned int ticks, void* param);
168 168
 static int fixup_profile(void** param, int param_no);
169 169
 static int fixup_get_profile2(void** param, int param_no);
170 170
 static int fixup_get_profile3(void** param, int param_no);
171
+static int fixup_dlg_get_matches(void** param, int param_no);
171 172
 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
172 173
 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
173 174
 static int w_is_in_profile(struct sip_msg*, char*, char*);
... ...
@@ -192,6 +193,8 @@ static int fixup_dlg_bridge(void** param, int param_no);
192 193
 static int w_dlg_get(struct sip_msg*, char*, char*, char*);
193 194
 static int w_is_known_dlg(struct sip_msg *);
194 195
 static int w_dlg_set_ruri(sip_msg_t *, char *, char *);
196
+static int w_dlg_get_matches1(struct sip_msg*, char*, char*, char*, char*);
197
+static int w_dlg_get_matches2(struct sip_msg*, char*, char*, char*, char*, char*);
195 198
 static int w_dlg_db_load_callid(sip_msg_t *msg, char *ci, char *p2);
196 199
 static int w_dlg_db_load_extra(sip_msg_t *msg, char *p1, char *p2);
197 200
 static int fixup_dlg_get_var(void** param, int param_no);
... ...
@@ -257,6 +260,10 @@ static cmd_export_t cmds[]={
257 260
 			0, ANY_ROUTE },
258 261
 	{"dlg_set_ruri",       (cmd_function)w_dlg_set_ruri,  0, NULL,
259 262
 			0, ANY_ROUTE },
263
+	{"dlg_get_matches",    (cmd_function)w_dlg_get_matches1,   4, fixup_dlg_get_matches,
264
+		        0, ANY_ROUTE },
265
+	{"dlg_get_matches",    (cmd_function)w_dlg_get_matches2,   5, fixup_dlg_get_matches,
266
+			0, ANY_ROUTE },
260 267
 	{"dlg_db_load_callid", (cmd_function)w_dlg_db_load_callid, 1, fixup_spve_null,
261 268
 			0, ANY_ROUTE },
262 269
 	{"dlg_db_load_extra", (cmd_function)w_dlg_db_load_extra, 0, 0,
... ...
@@ -448,6 +455,48 @@ static int fixup_get_profile3(void** param, int param_no)
448 455
 	return 0;
449 456
 }
450 457
 
458
+static int fixup_dlg_get_matches(void **param, int param_no)
459
+{
460
+	str s;
461
+
462
+	s.s = (char *)(*param);
463
+	s.len = strlen(s.s);
464
+	if(s.len == 0) {
465
+		LM_ERR("param %d is empty string!\n", param_no);
466
+		return E_CFG;
467
+	}
468
+
469
+	//Match key
470
+	if(param_no == 1) {
471
+		if(strncmp(s.s, "ruri", s.len) != 0 
472
+				&& strncmp(s.s, "turi", s.len) != 0
473
+				&& strncmp(s.s, "furi", s.len) != 0
474
+				&& strncmp(s.s, "callid", s.len) != 0
475
+				&& strncmp(s.s, "start_ts", s.len) != 0) {
476
+			LM_ERR("param %d must be 'ruri', 'turi', 'furi', 'callid' or 'start_ts'.\n",
477
+					param_no);
478
+			return E_CFG;
479
+		}
480
+	// Match operator
481
+	} else if(param_no == 2) {
482
+		if(strncmp(s.s, "eq", s.len) != 0 
483
+				&& strncmp(s.s, "sw", s.len) != 0
484
+				&& strncmp(s.s, "re", s.len) != 0
485
+				&& strncmp(s.s, "gt", s.len) != 0
486
+				&& strncmp(s.s, "lt", s.len) != 0) {
487
+			LM_ERR("param %d must be 'eq', 'sw', 're', 'gt' or 'lt'.\n", param_no);
488
+			return E_CFG;
489
+		}
490
+	//No extra validation for param 3
491
+
492
+	//XAVP result variable
493
+	} else if(param_no == 4) {
494
+		/* We don't to evaluate the variable, just accept a string name to use as the XAVP class name.
495
+		 * no further validation needed.
496
+		 */
497
+	}
498
+	return 0;
499
+}
451 500
 
452 501
 
453 502
 int load_dlg( struct dlg_binds *dlgb )
... ...
@@ -2784,6 +2833,611 @@ static int w_dlg_set_ruri(sip_msg_t *msg, char *p1, char *p2)
2784 2833
 	return	dlg_set_ruri(msg);
2785 2834
 }
2786 2835
 
2836
+/*!
2837
+ * \brief Helper function that outputs ptrs to matching dialogs in an array to be used elsewhere.
2838
+ *
2839
+ * \param list Ptr to hold array of dlg_cell_match_t struct ptrs to return results in.
2840
+ * \param mkey The dlg field to match against
2841
+ * \param mop The matching operation to use
2842
+ * \param mval The value to match against
2843
+ * \param max_results The max amount of results to return, or 0 if no limit
2844
+ * 
2845
+ * \return -1 if error, or otherwise the number of matches returned in the array.
2846
+ */
2847
+static int dlg_list_matches(dlg_cell_match_t **list, str mkey, str mop, str mval, int max_results)
2848
+{
2849
+	dlg_cell_t *dlg = NULL;
2850
+	int i = 0;
2851
+	str sval = {NULL, 0};
2852
+	unsigned int ival = 0;
2853
+	unsigned int mival = 0;
2854
+	int matches = 0;
2855
+	int vkey = 0;
2856
+	int vop = 0;
2857
+	int matched = 0;
2858
+	regex_t mre;
2859
+	regmatch_t pmatch;
2860
+	size_t arr_size = 0; //Start at 0 as shm for array is allocated below.
2861
+
2862
+	if(mkey.s==NULL || mkey.len<=0 || mop.s==NULL || mop.len<=0
2863
+			|| mval.s==NULL || mval.len<=0) {
2864
+		LM_ERR("invalid parameters\n");
2865
+		return -1;
2866
+	}
2867
+	if(mkey.len==4 && strncmp(mkey.s, "ruri", mkey.len)==0) {
2868
+		vkey = 0;
2869
+	} else if(mkey.len==4 && strncmp(mkey.s, "furi", mkey.len)==0) {
2870
+		vkey = 1;
2871
+	} else if(mkey.len==4 && strncmp(mkey.s, "turi", mkey.len)==0) {
2872
+		vkey = 2;
2873
+	} else if(mkey.len==6 && strncmp(mkey.s, "callid", mkey.len)==0) {
2874
+		vkey = 3;
2875
+	} else if(mkey.len==8 && strncmp(mkey.s, "start_ts", mkey.len)==0) {
2876
+		vkey = 4;
2877
+	} else {
2878
+		LM_ERR("invalid key %.*s\n", mkey.len, mkey.s);
2879
+		return -1;
2880
+	}
2881
+	if(mop.len!=2) {
2882
+		LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
2883
+		return -1;
2884
+
2885
+	}
2886
+	if(strncmp(mop.s, "eq", 2)==0) {
2887
+		vop = 0;
2888
+	} else if(strncmp(mop.s, "re", 2)==0) {
2889
+		vop = 1;
2890
+		memset(&mre, 0, sizeof(regex_t));
2891
+		if (regcomp(&mre, mval.s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)!=0) {
2892
+			LM_ERR("failed to compile regex: %.*s\n", mval.len, mval.s);
2893
+			return -1;
2894
+		}
2895
+	} else if(strncmp(mop.s, "sw", 2)==0) {
2896
+		vop = 2;
2897
+	} else if(strncmp(mop.s, "gt", 2)==0) {
2898
+		vop = 3;
2899
+	} else if(strncmp(mop.s, "lt", 2)==0) {
2900
+		vop = 4;
2901
+	} else {
2902
+		LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
2903
+		return -1;
2904
+	}
2905
+
2906
+	if (vkey == 4  && vop <= 2) {
2907
+		LM_ERR("Matching operator %.*s not supported with start_ts key\n", mop.len, mop.s);
2908
+		goto error;
2909
+	}
2910
+
2911
+	if (vkey != 4  && vop >= 3) {
2912
+		LM_ERR("Matching operator %.*s not supported with key %.*s\n", mop.len, mop.s, mkey.len, mkey.s);
2913
+		return -1;
2914
+	}
2915
+
2916
+	for(i=0; i<d_table->size; i++) {
2917
+		dlg_lock(d_table, &(d_table->entries[i]));
2918
+		for(dlg=d_table->entries[i].first; dlg!=NULL; dlg=dlg->next) {
2919
+			matched = 0;
2920
+			switch(vkey) {
2921
+				case 0:
2922
+					sval = dlg->req_uri;
2923
+					break;
2924
+				case 1:
2925
+					sval = dlg->from_uri;
2926
+					break;
2927
+				case 2:
2928
+					sval = dlg->to_uri;
2929
+					break;
2930
+				case 3:
2931
+					sval = dlg->callid;
2932
+					break;
2933
+				case 4:
2934
+					ival = dlg->start_ts;
2935
+					break;
2936
+			}
2937
+			switch(vop) {
2938
+				case 0:
2939
+					/* string comparison */
2940
+					if(mval.len==sval.len
2941
+							&& strncmp(mval.s, sval.s, mval.len)==0) {
2942
+						matched = 1;
2943
+					}
2944
+					break;
2945
+				case 1:
2946
+					/* regexp matching */
2947
+					if(regexec(&mre, sval.s, 1, &pmatch, 0)==0) {
2948
+						matched = 1;
2949
+					}
2950
+					break;
2951
+				case 2:
2952
+					/* starts with */
2953
+					if(mval.len<=sval.len
2954
+							&& strncmp(mval.s, sval.s, mval.len)==0) {
2955
+						matched = 1;
2956
+					}
2957
+					break;
2958
+				case 3:
2959
+					/* greater than */
2960
+					if (str2int(&mval, &mival) == 0 && ival > mival) {
2961
+						matched = 1;
2962
+					}
2963
+					break;
2964
+				case 4:
2965
+					if (str2int(&mval, &mival) == 0 && ival < mival) {
2966
+						matched = 1;
2967
+					}
2968
+					break;
2969
+			}
2970
+			if (matched==1) {
2971
+				matches++;
2972
+				if (matches > arr_size) {
2973
+					arr_size = (arr_size == 0 ? 1 : arr_size * 2);
2974
+					if (arr_size == 1) {
2975
+						*list = (dlg_cell_match_t *)shm_malloc(arr_size * sizeof(dlg_cell_match_t));
2976
+					} else {
2977
+						*list = (dlg_cell_match_t *)shm_realloc(*list, arr_size * sizeof(dlg_cell_match_t));
2978
+					}
2979
+					if (*list == NULL) {
2980
+						LM_ERR("no more shm mem (%ld)\n", arr_size * sizeof(dlg_cell_match_t));
2981
+						dlg_unlock(d_table, &(d_table->entries[i]));
2982
+						goto error;
2983
+					}
2984
+					LM_DBG("Re-sized matches array in shm (%ld): %p\n", arr_size * sizeof(dlg_cell_match_t), *list);
2985
+				}
2986
+				LM_DBG("Adding dlg match[%d] at %p = dlg ptr %p with entry %u\n", matches-1, (*list + (matches - 1)), dlg, i);
2987
+				dlg_cell_match_t *dlg_match = (*list + (matches-1));
2988
+				dlg_match->dlg = dlg;
2989
+				dlg_match->entry = i;
2990
+
2991
+				if(max_results > 0 && matches == max_results) {
2992
+					break;
2993
+				}
2994
+			}
2995
+		}
2996
+		dlg_unlock(d_table, &(d_table->entries[i]));
2997
+		if(max_results > 0 && matches == max_results) {
2998
+			break;
2999
+		}
3000
+	}
3001
+	if(vop == 1) {
3002
+		regfree(&mre);
3003
+	}
3004
+
3005
+	return matches;
3006
+
3007
+error:
3008
+	if (vop == 1) {
3009
+		regfree(&mre);
3010
+	}
3011
+	return -1;
3012
+}
3013
+
3014
+
3015
+
3016
+
3017
+/*!
3018
+ * \brief Helper function that adds a given dialog's values to a given XAVP.
3019
+ *
3020
+ * \param xavp XAVP array to add dialog values
3021
+ * \param dlg Pointer to a dialog to get values from
3022
+ * \return Returns 1 on success or 0 on failure.
3023
+ */
3024
+static int dlg_get_matches_xavp_helper(sr_xavp_t **xavp, dlg_cell_t *dlg)
3025
+{
3026
+	str xname_h_entry = str_init("h_entry");
3027
+	str xname_h_id = str_init("h_id");
3028
+	str xname_ref = str_init("ref");
3029
+	str xname_callid = str_init("callid");
3030
+	str xname_from_uri = str_init("from_uri");
3031
+	str xname_to_uri = str_init("to_uri");
3032
+	str xname_state = str_init("state");
3033
+	str xname_start_ts = str_init("start_ts");
3034
+	str xname_init_ts = str_init("init_ts");
3035
+	str xname_end_ts = str_init("end_ts");
3036
+	str xname_duration = str_init("duration");
3037
+	str xname_timeout = str_init("timeout");
3038
+	str xname_lifetime = str_init("lifetime");
3039
+	str xname_dflags = str_init("dflags");
3040
+	str xname_sflags = str_init("sflags");
3041
+	str xname_iflags = str_init("iflags");
3042
+	str xname_caller_tag = str_init("caller_tag");
3043
+	str xname_caller_contact = str_init("caller_contact");
3044
+	str xname_caller_cseq = str_init("caller_cseq");
3045
+	str xname_caller_route_set = str_init("caller_route_set");
3046
+	str xname_caller_socket = str_init("caller_socket");
3047
+	str xname_callee_tag = str_init("callee_tag");
3048
+	str xname_callee_contact = str_init("callee_contact");
3049
+	str xname_callee_cseq = str_init("callee_cseq");
3050
+	str xname_callee_route_set = str_init("callee_route_set");
3051
+	str xname_callee_socket = str_init("callee_socket");
3052
+
3053
+	sr_xval_t xval;
3054
+	dlg_profile_link_t *pl;
3055
+	dlg_var_t *var;
3056
+
3057
+	if(dlg == NULL) {
3058
+		LM_ERR("Null dialog was passed.\n");
3059
+		return 0;
3060
+	}
3061
+
3062
+	time_t tnow;
3063
+	int tdur;
3064
+
3065
+	tnow = time(NULL);
3066
+	if(dlg->end_ts) {
3067
+		tdur = (int)(dlg->end_ts - dlg->start_ts);
3068
+	} else if(dlg->start_ts) {
3069
+		tdur = (int)(tnow - dlg->start_ts);
3070
+	} else {
3071
+		tdur = 0;
3072
+	}
3073
+
3074
+	//h_entry
3075
+	memset(&xval, 0, sizeof(sr_xval_t));
3076
+	xval.type = SR_XTYPE_INT;
3077
+	xval.v.i = dlg->h_entry;
3078
+	xavp_add_value(&xname_h_entry, &xval, xavp);
3079
+
3080
+	//h_id
3081
+	memset(&xval, 0, sizeof(sr_xval_t));
3082
+	xval.type = SR_XTYPE_INT;
3083
+	xval.v.i = dlg->h_id;
3084
+	xavp_add_value(&xname_h_id, &xval, xavp);
3085
+
3086
+	//ref
3087
+	memset(&xval, 0, sizeof(sr_xval_t));
3088
+	xval.type = SR_XTYPE_INT;
3089
+	xval.v.i = dlg->ref;
3090
+	xavp_add_value(&xname_ref, &xval, xavp);
3091
+
3092
+	//callid
3093
+	memset(&xval, 0, sizeof(sr_xval_t));
3094
+	xval.type = SR_XTYPE_STR;
3095
+	xval.v.s = dlg->callid;
3096
+	xavp_add_value(&xname_callid, &xval, xavp);
3097
+
3098
+	//from_uri
3099
+	memset(&xval, 0, sizeof(sr_xval_t));
3100
+	xval.type = SR_XTYPE_STR;
3101
+	xval.v.s = dlg->from_uri;
3102
+	xavp_add_value(&xname_from_uri, &xval, xavp);
3103
+
3104
+	//to_uri
3105
+	memset(&xval, 0, sizeof(sr_xval_t));
3106
+	xval.type = SR_XTYPE_STR;
3107
+	xval.v.s = dlg->to_uri;
3108
+	xavp_add_value(&xname_to_uri, &xval, xavp);
3109
+
3110
+	//state
3111
+	memset(&xval, 0, sizeof(sr_xval_t));
3112
+	xval.type = SR_XTYPE_INT;
3113
+	xval.v.i = dlg->state;
3114
+	xavp_add_value(&xname_state, &xval, xavp);
3115
+
3116
+	//start_ts
3117
+	memset(&xval, 0, sizeof(sr_xval_t));
3118
+	xval.type = SR_XTYPE_INT;
3119
+	xval.v.i = dlg->start_ts;
3120
+	xavp_add_value(&xname_start_ts, &xval, xavp);
3121
+
3122
+	//init_ts
3123
+	memset(&xval, 0, sizeof(sr_xval_t));
3124
+	xval.type = SR_XTYPE_INT;
3125
+	xval.v.i = dlg->init_ts;
3126
+	xavp_add_value(&xname_init_ts, &xval, xavp);
3127
+
3128
+	//end_ts
3129
+	memset(&xval, 0, sizeof(sr_xval_t));
3130
+	xval.type = SR_XTYPE_INT;
3131
+	xval.v.i = dlg->end_ts;
3132
+	xavp_add_value(&xname_end_ts, &xval, xavp);
3133
+
3134
+	//duration
3135
+	memset(&xval, 0, sizeof(sr_xval_t));
3136
+	xval.type = SR_XTYPE_INT;
3137
+	xval.v.i = tdur;
3138
+	xavp_add_value(&xname_duration, &xval, xavp);
3139
+
3140
+	//timeout
3141
+	memset(&xval, 0, sizeof(sr_xval_t));
3142
+	xval.type = SR_XTYPE_INT;
3143
+	xval.v.i = dlg->tl.timeout ? tnow + dlg->tl.timeout - get_ticks() : 0;
3144
+	xavp_add_value(&xname_timeout, &xval, xavp);
3145
+
3146
+	//lifetime
3147
+	memset(&xval, 0, sizeof(sr_xval_t));
3148
+	xval.type = SR_XTYPE_INT;
3149
+	xval.v.i = dlg->lifetime;
3150
+	xavp_add_value(&xname_lifetime, &xval, xavp);
3151
+
3152
+	//dflags
3153
+	memset(&xval, 0, sizeof(sr_xval_t));
3154
+	xval.type = SR_XTYPE_INT;
3155
+	xval.v.i = dlg->dflags;
3156
+	xavp_add_value(&xname_dflags, &xval, xavp);
3157
+
3158
+	//sflags
3159
+	memset(&xval, 0, sizeof(sr_xval_t));
3160
+	xval.type = SR_XTYPE_INT;
3161
+	xval.v.i = dlg->sflags;
3162
+	xavp_add_value(&xname_sflags, &xval, xavp);
3163
+
3164
+	//iflags
3165
+	memset(&xval, 0, sizeof(sr_xval_t));
3166
+	xval.type = SR_XTYPE_INT;
3167
+	xval.v.i = dlg->iflags;
3168
+	xavp_add_value(&xname_iflags, &xval, xavp);
3169
+
3170
+	//caller_tag
3171
+	memset(&xval, 0, sizeof(sr_xval_t));
3172
+	xval.type = SR_XTYPE_STR;
3173
+	xval.v.s = dlg->tag[DLG_CALLER_LEG];
3174
+	xavp_add_value(&xname_caller_tag, &xval, xavp);
3175
+
3176
+	//caller_contact
3177
+	memset(&xval, 0, sizeof(sr_xval_t));
3178
+	xval.type = SR_XTYPE_STR;
3179
+	xval.v.s = dlg->contact[DLG_CALLER_LEG];
3180
+	xavp_add_value(&xname_caller_contact, &xval, xavp);
3181
+
3182
+	//caller_cseq
3183
+	memset(&xval, 0, sizeof(sr_xval_t));
3184
+	xval.type = SR_XTYPE_STR;
3185
+	xval.v.s = dlg->cseq[DLG_CALLER_LEG];
3186
+	xavp_add_value(&xname_caller_cseq, &xval, xavp);
3187
+
3188
+	//caller_route_set
3189
+	memset(&xval, 0, sizeof(sr_xval_t));
3190
+	xval.type = SR_XTYPE_STR;
3191
+	xval.v.s = dlg->route_set[DLG_CALLER_LEG];
3192
+	xavp_add_value(&xname_caller_route_set, &xval, xavp);
3193
+
3194
+	//caller_socket
3195
+	memset(&xval, 0, sizeof(sr_xval_t));
3196
+	xval.type = SR_XTYPE_STR;
3197
+	xval.v.s = dlg->bind_addr[DLG_CALLER_LEG]
3198
+					   ? dlg->bind_addr[DLG_CALLER_LEG]->sock_str
3199
+					   : empty_str;
3200
+	xavp_add_value(&xname_caller_socket, &xval, xavp);
3201
+
3202
+	//callee_tag
3203
+	memset(&xval, 0, sizeof(sr_xval_t));
3204
+	xval.type = SR_XTYPE_STR;
3205
+	xval.v.s = dlg->tag[DLG_CALLEE_LEG];
3206
+	xavp_add_value(&xname_callee_tag, &xval, xavp);
3207
+
3208
+	//callee_contact
3209
+	memset(&xval, 0, sizeof(sr_xval_t));
3210
+	xval.type = SR_XTYPE_STR;
3211
+	xval.v.s = dlg->contact[DLG_CALLEE_LEG];
3212
+	xavp_add_value(&xname_callee_contact, &xval, xavp);
3213
+
3214
+	//callee_cseq
3215
+	memset(&xval, 0, sizeof(sr_xval_t));
3216
+	xval.type = SR_XTYPE_STR;
3217
+	xval.v.s = dlg->cseq[DLG_CALLEE_LEG];
3218
+	xavp_add_value(&xname_callee_cseq, &xval, xavp);
3219
+
3220
+	//callee_route_set
3221
+	memset(&xval, 0, sizeof(sr_xval_t));
3222
+	xval.type = SR_XTYPE_STR;
3223
+	xval.v.s = dlg->route_set[DLG_CALLEE_LEG];
3224
+	xavp_add_value(&xname_callee_route_set, &xval, xavp);
3225
+
3226
+	//callee_socket
3227
+	memset(&xval, 0, sizeof(sr_xval_t));
3228
+	xval.type = SR_XTYPE_STR;
3229
+	xval.v.s = dlg->bind_addr[DLG_CALLEE_LEG]
3230
+					   ? dlg->bind_addr[DLG_CALLEE_LEG]->sock_str
3231
+					   : empty_str;
3232
+	xavp_add_value(&xname_callee_socket, &xval, xavp);
3233
+
3234
+	for(pl = dlg->profile_links; pl && (dlg->state < DLG_STATE_DELETED); pl = pl->next) {
3235
+		//Prefix profile XAVPs with prf_
3236
+		//prefix + name + NULL
3237
+		int buflen = 4 + pl->profile->name.len + 1;
3238
+		char buf[buflen];
3239
+		snprintf(buf, buflen, "prf_%s", pl->profile->name.s);
3240
+		str s;
3241
+		s.s = buf;
3242
+		s.len = strlen(buf);
3243
+
3244
+		memset(&xval, 0, sizeof(sr_xval_t));
3245
+		xval.type = SR_XTYPE_STR;
3246
+
3247
+		if(pl->profile->has_value) {
3248
+			xval.v.s = pl->hash_linker.value;
3249
+		} else {
3250
+			xval.v.s = empty_str;
3251
+		}
3252
+		xavp_add_value(&s, &xval, xavp);
3253
+	}
3254
+
3255
+	for(var = dlg->vars; var && (dlg->state < DLG_STATE_DELETED); var = var->next) {
3256
+		//Prefix dlg var XAVPs with var_
3257
+		//prefix + key + NULL
3258
+		int buflen = 4 + var->key.len + 1;
3259
+		char buf[buflen];
3260
+		snprintf(buf, buflen, "var_%s", var->key.s);
3261
+		str s;
3262
+		s.s = buf;
3263
+		s.len = strlen(buf);
3264
+
3265
+		memset(&xval, 0, sizeof(sr_xval_t));
3266
+		xval.type = SR_XTYPE_STR;
3267
+		xval.v.s = var->value;
3268
+		xavp_add_value(&s, &xval, xavp);
3269
+	}
3270
+	return 1;
3271
+}
3272
+
3273
+
3274
+/*!
3275
+ * \brief Function matches against dialogs based on the provided mkey, mop and mval,
3276
+ * then stores results in an XAVP variable.
3277
+ *
3278
+ * \param msg SIP message
3279
+ * \param mkey Field of dialogs to match against
3280
+ * \param mop Type of matching to perform
3281
+ * \param mval String value to match against, can contain  a pvar.
3282
+ * \param xavp_name String name of an XAVP variable to store results in.
3283
+ * \param max_results Integer with max results to return, returns all if 0.
3284
+ * \return Count of matching dialogs, or -1 if no matches found.
3285
+ */
3286
+static int internal_dlg_get_matches(struct sip_msg *msg, char *mkey, char *mop,
3287
+		char *mval, char *xavp_name, int max_results)
3288
+{
3289
+	dlg_cell_match_t *dlg_matches = NULL; //Ptr for array to store dlg matches.
3290
+	int i = 0;
3291
+	int matches = 0;				//Count of matches returned.
3292
+	sr_xavp_t **xavp = NULL; //XAVP to store fields
3293
+	sr_xavp_t *list = NULL; //Ptr to existing XAVP with "xavp_name" if one exists.
3294
+	sr_xavp_t *new_xavp = NULL;
3295
+
3296
+	str mkey_s;
3297
+	mkey_s.s = mkey;
3298
+	mkey_s.len = strlen(mkey);
3299
+
3300
+	str mop_s;
3301
+	mop_s.s = mop;
3302
+	mop_s.len = strlen(mop);
3303
+
3304
+	str mval_sraw;
3305
+	mval_sraw.s = mval;
3306
+	mval_sraw.len = strlen(mval);
3307
+
3308
+	str xavp_name_s = {0, 0};
3309
+	str xavp_name_sraw;
3310
+	xavp_name_sraw.s = xavp_name;
3311
+	xavp_name_sraw.len = strlen(xavp_name);
3312
+
3313
+	LM_DBG("Looking for matches against: %s\n", mval_sraw.s);
3314
+	//Convert the mval with any PVs to a string.
3315
+	pv_elem_t *xmodel = NULL;
3316
+	str mval_s = {0, 0};
3317
+
3318
+	if(pv_parse_format(&mval_sraw, &xmodel) < 0) {
3319
+		LM_ERR("error in parsing evaluated mval parameter\n");
3320
+		return -1;
3321
+	}
3322
+
3323
+	if(pv_printf_s(msg, xmodel, &mval_s) != 0) {
3324
+		LM_ERR("cannot eval reparsed value of mval parameter\n");
3325
+		pv_elem_free_all(xmodel);
3326
+		return -1;
3327
+	}
3328
+	pv_elem_free_all(xmodel);
3329
+	LM_DBG("Evaluated mval to: %s\n", mval_s.s);
3330
+
3331
+	if(pv_parse_format(&xavp_name_sraw, &xmodel) < 0) {
3332
+		LM_ERR("error in parsing evaluated xavp_name parameter\n");
3333
+		return -1;
3334
+	}
3335
+
3336
+	if(pv_printf_s(msg, xmodel, &xavp_name_s) != 0) {
3337
+		LM_ERR("cannot eval reparsed value of xavp_name parameter\n");
3338
+		pv_elem_free_all(xmodel);
3339
+		return -1;
3340
+	}
3341
+	pv_elem_free_all(xmodel);
3342
+	LM_DBG("Evaluated xavp_name to: %s\n", xavp_name_s.s);
3343
+
3344
+	if(xavp_name_s.s == NULL || xavp_name_s.len <= 0) {
3345
+		LM_ERR("XAVP name not provided.\n");
3346
+		return -1;
3347
+	}
3348
+
3349
+	LM_DBG("Storing name for XAVP: %s\n", xavp_name_s.s);
3350
+	//Find existing XAVP for this xavp_name, if there is one.
3351
+	//Use the existing XAVP to append new XAVPs to the list.
3352
+	//If none exists, we'll add it to the root list later.
3353
+	list = xavp_get(&xavp_name_s, NULL);
3354
+	xavp = list ? &list->val.v.xavp : &new_xavp;
3355
+
3356
+	//Get list of matches
3357
+	matches = dlg_list_matches(&dlg_matches, mkey_s, mop_s, mval_s, max_results);
3358
+
3359
+	if (matches < 0) {
3360
+		LM_ERR("dlg_list_matches returned an error.\n");
3361
+		return -1;
3362
+	}
3363
+
3364
+	for (i = 0; i < matches; i++) {
3365
+		//Add fields to XAVP for this dialog.
3366
+		//The XAVP structure is such that multiple calls to this
3367
+		//will add each set of fields under their own index on
3368
+		//the XAVP list.
3369
+		unsigned int entry = dlg_matches[i].entry;
3370
+
3371
+		dlg_lock(d_table, &(d_table->entries[entry]));
3372
+		if (!dlg_get_matches_xavp_helper(xavp, dlg_matches[i].dlg)) {
3373
+			shm_free(dlg_matches);
3374
+			dlg_unlock(d_table, &(d_table->entries[entry]));
3375
+			LM_ERR("Failed to add matching dialog to XAVP.\n");
3376
+			return -1;
3377
+		}
3378
+		dlg_unlock(d_table, &(d_table->entries[entry]));
3379
+	}
3380
+
3381
+	shm_free(dlg_matches);
3382
+
3383
+	//Add to root list at the end, so the xavp points to last
3384
+	//field added before adding to root list.
3385
+	if(list == NULL && matches > 0) {
3386
+		// If list is null there was no xavp of name xavp_name in root list - add it
3387
+		LM_DBG("Adding new xavp to root list: %s\n", xavp_name_s.s);
3388
+		sr_xval_t xval;
3389
+		memset(&xval, 0, sizeof(sr_xval_t));
3390
+		xval.type = SR_XTYPE_XAVP;
3391
+		xval.v.xavp = *xavp;
3392
+		if(xavp_add_value(&xavp_name_s, &xval, NULL) == NULL) {
3393
+			LM_ERR("cannot add xavp to root list\n");
3394
+			xavp_destroy_list(xavp);
3395
+			return -1;
3396
+		}
3397
+	}
3398
+
3399
+	if(matches == 0) {
3400
+		LM_DBG("No matches found.\n");
3401
+		//Apparently returning 0 will stop execution of the calling script. So return -1.
3402
+		return -1;
3403
+	}
3404
+	return matches;
3405
+}
3406
+
3407
+static int w_dlg_get_matches1(
3408
+		struct sip_msg *msg, char *mkey, char *mop, char *mval, char *xavp_name)
3409
+{
3410
+	return internal_dlg_get_matches(msg, mkey, mop, mval, xavp_name, 0);
3411
+}
3412
+
3413
+static int w_dlg_get_matches2(struct sip_msg *msg, char *mkey, char *mop,
3414
+		char *mval, char *xavp_name, char *max_results)
3415
+{
3416
+	//Convert the max_results with any PVs to a string.
3417
+	pv_elem_t *xmodel = NULL;
3418
+	str max_results_s;
3419
+	max_results_s.s = max_results;
3420
+	max_results_s.len = strlen(max_results);
3421
+	str val = {0, 0};
3422
+
3423
+	if(pv_parse_format(&max_results_s, &xmodel) < 0) {
3424
+		LM_ERR("error in parsing evaluated max_results parameter\n");
3425
+		return -1;
3426
+	}
3427
+
3428
+	if(pv_printf_s(msg, xmodel, &val) != 0) {
3429
+		LM_ERR("cannot eval reparsed value of max_results parameter\n");
3430
+		pv_elem_free_all(xmodel);
3431
+		return -1;
3432
+	}
3433
+	pv_elem_free_all(xmodel);
3434
+	LM_DBG("Evaluated max_results to: %s\n", val.s);
3435
+
3436
+	int max = atoi(val.s);
3437
+
3438
+	return internal_dlg_get_matches(msg, mkey, mop, mval, xavp_name, max);
3439
+}
3440
+
2787 3441
 static const char *rpc_print_dlgs_doc[2] = {
2788 3442
 	"Print all dialogs", 0
2789 3443
 };
... ...
@@ -3143,21 +3797,13 @@ static void rpc_dlg_stats_active(rpc_t *rpc, void *c)
3143 3797
  */
3144 3798
 static void rpc_dlg_list_match_ex(rpc_t *rpc, void *c, int with_context)
3145 3799
 {
3146
-	dlg_cell_t *dlg = NULL;
3800
+	dlg_cell_match_t *dlg_matches = NULL;
3147 3801
 	int i = 0;
3148 3802
 	str mkey = {NULL, 0};
3149 3803
 	str mop = {NULL, 0};
3150 3804
 	str mval = {NULL, 0};
3151
-	str sval = {NULL, 0};
3152
-	unsigned int ival = 0;
3153
-	unsigned int mival = 0;
3154 3805
 	int n = 0;
3155 3806
 	int m = 0;
3156
-	int vkey = 0;
3157
-	int vop = 0;
3158
-	int matched = 0;
3159
-	regex_t mre;
3160
-	regmatch_t pmatch;
3161 3807
 
3162 3808
 	i = rpc->scan(c, "SSS", &mkey, &mop, &mval);
3163 3809
 	if (i < 3) {
... ...
@@ -3171,134 +3817,25 @@ static void rpc_dlg_list_match_ex(rpc_t *rpc, void *c, int with_context)
3171 3817
 		rpc->fault(c, 500, "Invalid parameters");
3172 3818
 		return;
3173 3819
 	}
3174
-	if(mkey.len==4 && strncmp(mkey.s, "ruri", mkey.len)==0) {
3175
-		vkey = 0;
3176
-	} else if(mkey.len==4 && strncmp(mkey.s, "furi", mkey.len)==0) {
3177
-		vkey = 1;
3178
-	} else if(mkey.len==4 && strncmp(mkey.s, "turi", mkey.len)==0) {
3179
-		vkey = 2;
3180
-	} else if(mkey.len==6 && strncmp(mkey.s, "callid", mkey.len)==0) {
3181
-		vkey = 3;
3182
-	} else if(mkey.len==8 && strncmp(mkey.s, "start_ts", mkey.len)==0) {
3183
-		vkey = 4;
3184
-	} else {
3185
-		LM_ERR("invalid key %.*s\n", mkey.len, mkey.s);
3186
-		rpc->fault(c, 500, "Invalid matching key parameter");
3187
-		return;
3188
-	}
3189
-	if(mop.len!=2) {
3190
-		LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
3191
-		rpc->fault(c, 500, "Invalid matching operator parameter");
3192
-		return;
3193
-
3194
-	}
3195
-	if(strncmp(mop.s, "eq", 2)==0) {
3196
-		vop = 0;
3197
-	} else if(strncmp(mop.s, "re", 2)==0) {
3198
-		vop = 1;
3199
-		memset(&mre, 0, sizeof(regex_t));
3200
-		if (regcomp(&mre, mval.s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)!=0) {
3201
-			LM_ERR("failed to compile regex: %.*s\n", mval.len, mval.s);
3202
-			rpc->fault(c, 500, "Invalid matching value parameter");
3203
-			return;
3204
-		}
3205
-	} else if(strncmp(mop.s, "sw", 2)==0) {
3206
-		vop = 2;
3207
-	} else if(strncmp(mop.s, "gt", 2)==0) {
3208
-		vop = 3;
3209
-	} else if(strncmp(mop.s, "lt", 2)==0) {
3210
-		vop = 4;
3211
-	} else {
3212
-		LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
3213
-		rpc->fault(c, 500, "Invalid matching operator parameter");
3214
-		return;
3215
-	}
3216 3820
 	if(rpc->scan(c, "*d", &n)<1) {
3217 3821
 		n = 0;
3218 3822
 	}
3219 3823
 
3220
-	if (vkey == 4  && vop <= 2) {
3221
-		LM_ERR("Matching operator %.*s not supported with start_ts key\n", mop.len, mop.s);
3222
-		rpc->fault(c, 500, "Matching operator not supported with start_ts key");
3223
-		return;
3224
-	}
3824
+	m = dlg_list_matches(&dlg_matches, mkey, mop, mval, n);
3225 3825
 
3226
-	if (vkey != 4  && vop >= 3) {
3227
-		LM_ERR("Matching operator %.*s not supported with key %.*s\n", mop.len, mop.s, mkey.len, mkey.s);
3228
-		rpc->fault(c, 500, "Matching operator not supported");
3826
+	if (m < 0) {
3827
+		LM_ERR("invalid parameters, see earlier log entry.\n");
3828
+		rpc->fault(c, 500, "Invalid parameters, see logs for details.");
3229 3829
 		return;
3230 3830
 	}
3231 3831
 
3232
-	for(i=0; i<d_table->size; i++) {
3233
-		dlg_lock(d_table, &(d_table->entries[i]));
3234
-		for(dlg=d_table->entries[i].first; dlg!=NULL; dlg=dlg->next) {
3235
-			matched = 0;
3236
-			switch(vkey) {
3237
-				case 0:
3238
-					sval = dlg->req_uri;
3239
-				break;
3240
-				case 1:
3241
-					sval = dlg->from_uri;
3242
-				break;
3243
-				case 2:
3244
-					sval = dlg->to_uri;
3245
-				break;
3246
-				case 3:
3247
-					sval = dlg->callid;
3248
-				break;
3249
-				case 4:
3250
-					ival = dlg->start_ts;
3251
-				break;
3252
-			}
3253
-			switch(vop) {
3254
-				case 0:
3255
-					/* string comparison */
3256
-					if(mval.len==sval.len
3257
-							&& strncmp(mval.s, sval.s, mval.len)==0) {
3258
-						matched = 1;
3259
-					}
3260
-				break;
3261
-				case 1:
3262
-					/* regexp matching */
3263
-					if(regexec(&mre, sval.s, 1, &pmatch, 0)==0) {
3264
-						matched = 1;
3265
-					}
3266
-				break;
3267
-				case 2:
3268
-					/* starts with */
3269
-					if(mval.len<=sval.len
3270
-							&& strncmp(mval.s, sval.s, mval.len)==0) {
3271
-						matched = 1;
3272
-					}
3273
-				break;
3274
-				case 3:		
3275
-					/* greater than */
3276
-					if (str2int(&mval, &mival) == 0 && ival > mival) {
3277
-						matched = 1;
3278
-					}
3279
-				break;
3280
-				case 4:
3281
-					if (str2int(&mval, &mival) == 0 && ival < mival) {
3282
-						matched = 1;
3283
-					}
3284
-				break;
3285
-			}
3286
-			if (matched==1) {
3287
-				m++;
3288
-				internal_rpc_print_dlg(rpc, c, dlg, with_context);
3289
-				if(n>0 && m==n) {
3290
-					break;
3291
-				}
3292
-			}
3293
-		}
3294
-		dlg_unlock(d_table, &(d_table->entries[i]));
3295
-		if(n>0 && m==n) {
3296
-			break;
3297
-		}
3298
-	}
3299
-	if(vop == 1) {
3300
-		regfree(&mre);
3832
+	for (i = 0; i < m; i++) {
3833
+		unsigned int entry = dlg_matches[i].entry;
3834
+		dlg_lock(d_table, &(d_table->entries[entry]));
3835
+		internal_rpc_print_dlg(rpc, c, dlg_matches[i].dlg, with_context);
3836
+		dlg_unlock(d_table, &(d_table->entries[entry]));
3301 3837
 	}
3838
+	shm_free(dlg_matches);
3302 3839
 
3303 3840
 	if(m==0) {
3304 3841
 		rpc->fault(c, 404, "Not found");
... ...
@@ -165,6 +165,11 @@ typedef struct dlg_ka {
165 165
 	struct dlg_ka *next;
166 166
 } dlg_ka_t;
167 167
 
168
+typedef struct dlg_cell_match {
169
+        struct dlg_cell *dlg;
170
+        unsigned int entry;
171
+} dlg_cell_match_t;
172
+
168 173
 /*! global dialog table */
169 174
 extern dlg_table_t *d_table;
170 175
 
... ...
@@ -2541,6 +2541,100 @@ dlg_reset_property("timeout-noreset");
2541 2541
 </programlisting>
2542 2542
 		</example>
2543 2543
 	</section>
2544
+
2545
+        <section id="dialog.f.dlg_get_matches">
2546
+                <title>
2547
+                <function moreinfo="none">dlg_get_matches(key, op, value, xavp_name[, max_results])</function>
2548
+                </title>
2549
+                <para>
2550
+			Returns a list of matching dialog entries into a given XAVP name. The return value of the function
2551
+			is -1 if there is an error, or otherwise the number of matches found.
2552
+
2553
+			Matches are based on the specified dialog field (key), match type (op) and matching value.
2554
+			Matches can optionally be limited to a specified value, or unlimited if the value is 0 or
2555
+			not specified.
2556
+                </para>
2557
+                <para>Meaning of the parameters is as follows:</para>
2558
+                <itemizedlist>
2559
+                <listitem>
2560
+                        <para>
2561
+				<emphasis>key</emphasis> - the name of the dialog field to match against.
2562
+				It can be:
2563
+					<itemizedlist>
2564
+						<listitem>
2565
+							'ruri' - R-URI of dialog
2566
+						</listitem>
2567
+						<listitem>
2568
+							'turi' - To Header of dialog
2569
+						</listitem>
2570
+						<listitem>
2571
+							'furi' - From Header of dialog
2572
+						</listitem>
2573
+						<listitem>
2574
+							'callid' - Call-Id of dialog
2575
+						</listitem>
2576
+						<listitem>
2577
+							'start_ts' - match against start timestamp of dialog. Only works with gt, lt.
2578
+						</listitem>
2579
+					</itemizedlist>
2580
+
2581
+                        </para>
2582
+                </listitem>
2583
+                <listitem>
2584
+                        <para>
2585
+				<emphasis>op</emphasis> - the type of match operation to use. It can be:
2586
+					<itemizedlist>
2587
+						<listitem>
2588
+							'eq' - Match if string comparison equals.
2589
+						</listitem>
2590
+						<listitem>
2591
+							're' - Match using regular expression.
2592
+						</listitem>
2593
+						<listitem>
2594
+							'sw' - Match using string starts with (prefix) comparison.
2595
+						</listitem>
2596
+						<listitem>
2597
+							'gt' - Match using integer greater than comparison. Only works with 'start_ts' key.
2598
+						</listitem>
2599
+                                                <listitem>
2600
+                                                        'lt' - Match using integer less than comparison. Only works with 'start_ts' key.
2601
+                                                </listitem>
2602
+					</itemizedlist>
2603
+                        </para>
2604
+                </listitem>
2605
+                <listitem>
2606
+                        <para>
2607
+                                <emphasis>value</emphasis> - value to match dialog against. 
2608
+                                This can be a pvar.
2609
+                        </para>
2610
+                </listitem>
2611
+                <listitem>
2612
+                        <para>
2613
+                                <emphasis>xavp_name</emphasis> - the name of the xavp to store
2614
+                                results in. This can be a pvar.
2615
+                        </para>
2616
+		</listitem>
2617
+		<listitem>
2618
+			<para>
2619
+				<emphasis>max_results</emphasis> - the max number of results to return
2620
+				in the xavp. If the value is 0 or not provided, there is no limit. This can be a pvar.
2621
+			</para>
2622
+		</listitem>
2623
+                </itemizedlist>
2624
+		<para>
2625
+                        This function can be used from ANY_ROUTE.
2626
+                </para>
2627
+                <example>
2628
+                <title><function>dlg_get_matches</function> usage</title>
2629
+                <programlisting format="linespecific">
2630
+...
2631
+dlg_get_matches("furi", "sw", "sip:$var(ext)@", "dlg_matches");
2632
+dlg_get_matches("furi", "sw", "sip:$var(ext)@", "$var(name)", 2);
2633
+...
2634
+
2635
+</programlisting>
2636
+                </example>
2637
+        </section>
2544 2638
 	</section>
2545 2639
 
2546 2640