Browse code

speeddial: allow search uri of speed dial by group

This new feature provides a way to have multiple users sharing the same speed dial number, if they belong to the same group.

Fabricio Santolin da Silva authored on 28/09/2022 07:32:50
Showing 11 changed files
... ...
@@ -11,6 +11,7 @@
11 11
 <!ENTITY xcap_uri_len "255">
12 12
 <!ENTITY id_len "64">
13 13
 <!ENTITY table_id_len "10">
14
+<!ENTITY group_len "128">
14 15
 <!ENTITY hf_len "255">
15 16
 <!ENTITY contact_len "512">
16 17
 <!ENTITY long_hf_len "512">
... ...
@@ -9,7 +9,7 @@
9 9
 
10 10
 <table id="speed_dial" xmlns:db="http://docbook.org/ns/docbook">
11 11
     <name>speed_dial</name>
12
-    <version>2</version>
12
+    <version>3</version>
13 13
     <type db="mysql">&MYSQL_TABLE_TYPE;</type>
14 14
     <description>
15 15
 		<db:para>
... ...
@@ -100,6 +100,14 @@
100 100
         <description>Description</description>
101 101
     </column>
102 102
 
103
+    <column>
104
+        <name>group_id</name>
105
+        <type>string</type>
106
+        <size>&group_len;</size>
107
+        <default/>
108
+        <description>Group ID</description>
109
+    </column>
110
+
103 111
     <index>
104 112
         <name>speed_dial_idx</name>
105 113
         <colref linkend="username"/>
... ...
@@ -249,6 +249,41 @@ if(uri=~"sip:[0-9]{2}@.*")
249 249
 if(uri=~"sip:[0-9]{2}@.*")
250 250
 	sd_lookup("speed_dial", "sip:$au@$fd");
251 251
 ...
252
+</programlisting>
253
+		</example>
254
+	</section>
255
+	<section>
256
+		<title>
257
+		<function moreinfo="none">sd_lookup_group(table , group)</function>
258
+		</title>
259
+		<para>
260
+		The function lookups the short dial number from the group defined in the 'table' and replaces the R-URI with associated address.
261
+		</para>
262
+		<para>Meaning of the parameters is as follows:</para>
263
+		<itemizedlist>
264
+		<listitem>
265
+			<para><emphasis>table</emphasis> - The name of the table storing the
266
+			speed dial records.
267
+			</para>
268
+		</listitem>
269
+		<listitem>
270
+			<para><emphasis>group</emphasis> - The group that has the
271
+			short dialing codes.
272
+			</para>
273
+		</listitem>
274
+		</itemizedlist>
275
+		<para>
276
+		This function can be used from REQUEST_ROUTE.
277
+		</para>
278
+		<example>
279
+		<title><function>sd_lookup_group</function> usage</title>
280
+		<programlisting format="linespecific">
281
+...
282
+# 'speed_dial' is the default table name created by kamailio db script
283
+# Using 3 digits to differentiate from the simple lookup 
284
+if(uri=~"sip:[0-9]{3}@.*")
285
+	sd_lookup_group("speed_dial", "group_id");
286
+...
252 287
 </programlisting>
253 288
 		</example>
254 289
 	</section>
... ...
@@ -58,6 +58,47 @@ static inline int rewrite_ruri(struct sip_msg* _m, char* _s)
58 58
 	return 0;
59 59
 }
60 60
 
61
+/**
62
+ *
63
+ */
64
+int process_result(db1_res_t* db_res, str *ret, char *buffer)
65
+{
66
+	ret->s=buffer+4;
67
+	if (RES_ROW_N(db_res) > 1)
68
+	{
69
+		LM_WARN("too many similar results, returning first result\n");
70
+	}
71
+	switch(RES_ROWS(db_res)[0].values[0].type)
72
+	{
73
+		case DB1_STRING:
74
+			strcpy(ret->s,
75
+				(char*)RES_ROWS(db_res)[0].values[0].val.string_val);
76
+			ret->len = strlen(ret->s);
77
+		break;
78
+		case DB1_STR:
79
+			strncpy(ret->s,
80
+				(char*)RES_ROWS(db_res)[0].values[0].val.str_val.s,
81
+				RES_ROWS(db_res)[0].values[0].val.str_val.len);
82
+			ret->len = RES_ROWS(db_res)[0].values[0].val.str_val.len;
83
+			ret->s[ret->len] = '\0';
84
+		break;
85
+		case DB1_BLOB:
86
+			strncpy(ret->s,
87
+				(char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s,
88
+				RES_ROWS(db_res)[0].values[0].val.blob_val.len);
89
+			ret->len = RES_ROWS(db_res)[0].values[0].val.blob_val.len;
90
+			ret->s[ret->len] = '\0';
91
+		break;
92
+		default:
93
+			LM_ERR("unknown type of DB new_uri column\n");
94
+			if (db_funcs.free_result(db_handle, db_res) < 0) {
95
+				LM_DBG("failed to free result of query\n");
96
+			}
97
+			return -1;
98
+	}
99
+	return 1;
100
+}
101
+
61 102
 /**
62 103
  *
63 104
  */
... ...
@@ -175,34 +216,129 @@ int sd_lookup_owner(sip_msg_t* _msg, str* stable, str* sowner)
175 216
 		return -1;
176 217
 	}
177 218
 
178
-	user_s.s = useruri_buf+4;
179
-	switch(RES_ROWS(db_res)[0].values[0].type)
219
+	if(process_result(db_res, &user_s, useruri_buf) < 0)
180 220
 	{
181
-		case DB1_STRING:
182
-			strcpy(user_s.s,
183
-				(char*)RES_ROWS(db_res)[0].values[0].val.string_val);
184
-			user_s.len = strlen(user_s.s);
185
-		break;
186
-		case DB1_STR:
187
-			strncpy(user_s.s,
188
-				(char*)RES_ROWS(db_res)[0].values[0].val.str_val.s,
189
-				RES_ROWS(db_res)[0].values[0].val.str_val.len);
190
-			user_s.len = RES_ROWS(db_res)[0].values[0].val.str_val.len;
191
-			user_s.s[user_s.len] = '\0';
192
-		break;
193
-		case DB1_BLOB:
194
-			strncpy(user_s.s,
195
-				(char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s,
196
-				RES_ROWS(db_res)[0].values[0].val.blob_val.len);
197
-			user_s.len = RES_ROWS(db_res)[0].values[0].val.blob_val.len;
198
-			user_s.s[user_s.len] = '\0';
199
-		break;
200
-		default:
201
-			LM_ERR("unknown type of DB new_uri column\n");
202
-			if (db_funcs.free_result(db_handle, db_res) < 0) {
203
-				LM_DBG("failed to free result of query\n");
204
-			}
205
-			goto err_server;
221
+		LM_DBG("failed to process result\n");
222
+		return -1;
223
+	}
224
+
225
+	/* check 'sip:' */
226
+	if(user_s.len<4 || strncmp(user_s.s, "sip:", 4))
227
+	{
228
+		memcpy(useruri_buf, "sip:", 4);
229
+		user_s.s -= 4;
230
+		user_s.len += 4;
231
+	}
232
+
233
+	/**
234
+	 * Free the result because we don't need it anymore
235
+	 */
236
+	if (db_funcs.free_result(db_handle, db_res) < 0) {
237
+		LM_DBG("failed to free result of query\n");
238
+	}
239
+
240
+	/* set the URI */
241
+	LM_DBG("URI of sd from R-URI [%s]\n", user_s.s);
242
+	if(rewrite_ruri(_msg, user_s.s)<0)
243
+	{
244
+		LM_ERR("failed to replace the R-URI\n");
245
+		goto err_server;
246
+	}
247
+
248
+	return 1;
249
+
250
+err_server:
251
+	return -1;
252
+}
253
+
254
+/**
255
+ * 
256
+ */
257
+int sd_lookup_group(sip_msg_t* _msg, str* stable, str* sgroup)
258
+{
259
+	str user_s, table_s;
260
+	int nr_keys;
261
+	db_key_t db_keys[3];
262
+	db_val_t db_vals[3];
263
+	db_key_t db_cols[1];
264
+	db1_res_t* db_res = NULL;
265
+
266
+	if(stable==NULL || stable->s==NULL || stable->len<=0)
267
+	{
268
+		LM_ERR("invalid table parameter");
269
+		goto err_server;
270
+	}
271
+	table_s = *stable;
272
+
273
+	if(sgroup==NULL || sgroup->s==NULL || sgroup->len<=0)
274
+	{
275
+		LM_ERR("invalid group parameter");
276
+		goto err_server;
277
+	}
278
+
279
+	/* init */
280
+	nr_keys = 0;
281
+	db_cols[0]=&new_uri_column;
282
+
283
+	/* take sd from r-uri */
284
+	if (parse_sip_msg_uri(_msg) < 0)
285
+	{
286
+		LM_ERR("failed to parsing Request-URI\n");
287
+		goto err_server;
288
+	}
289
+
290
+	db_keys[nr_keys]=&sd_user_column;
291
+	db_vals[nr_keys].type = DB1_STR;
292
+	db_vals[nr_keys].nul = 0;
293
+	db_vals[nr_keys].val.str_val.s = _msg->parsed_uri.user.s;
294
+	db_vals[nr_keys].val.str_val.len = _msg->parsed_uri.user.len;
295
+	nr_keys++;
296
+
297
+	if(use_domain>=2)
298
+	{
299
+		db_keys[nr_keys]=&sd_domain_column;
300
+		db_vals[nr_keys].type = DB1_STR;
301
+		db_vals[nr_keys].nul = 0;
302
+		db_vals[nr_keys].val.str_val.s = _msg->parsed_uri.host.s;
303
+		db_vals[nr_keys].val.str_val.len = _msg->parsed_uri.host.len;
304
+
305
+		if (dstrip_s.s!=NULL && dstrip_s.len>0
306
+			&& dstrip_s.len<_msg->parsed_uri.host.len
307
+			&& strncasecmp(_msg->parsed_uri.host.s,dstrip_s.s,dstrip_s.len)==0)
308
+		{
309
+			db_vals[nr_keys].val.str_val.s   += dstrip_s.len;
310
+			db_vals[nr_keys].val.str_val.len -= dstrip_s.len;
311
+		}
312
+		nr_keys++;
313
+	}
314
+
315
+
316
+	db_keys[nr_keys]=&group_column;
317
+	db_vals[nr_keys].type = DB1_STR;
318
+	db_vals[nr_keys].nul = 0;
319
+	db_vals[nr_keys].val.str_val = *sgroup;
320
+	nr_keys++;
321
+
322
+	db_funcs.use_table(db_handle, &table_s);
323
+	if(db_funcs.query(db_handle, db_keys, NULL, db_vals, db_cols,
324
+		nr_keys /*no keys*/, 1 /*no cols*/, NULL, &db_res)!=0 || db_res==NULL)
325
+	{
326
+		LM_ERR("failed to query database\n");
327
+		goto err_server;
328
+	}
329
+
330
+	if(RES_ROW_N(db_res) <= 0 || RES_ROWS(db_res)[0].values[0].nul != 0) {
331
+		LM_DBG("no sip address found for R-URI\n");
332
+		if(db_funcs.free_result(db_handle, db_res) < 0) {
333
+			LM_DBG("failed to free result of query\n");
334
+		}
335
+		goto err_server;
336
+	}
337
+
338
+	if(process_result(db_res, &user_s, useruri_buf) < 0)
339
+	{
340
+		LM_DBG("failed to process result\n");
341
+		goto err_server;
206 342
 	}
207 343
 
208 344
 	/* check 'sip:' */
... ...
@@ -259,3 +395,24 @@ int w_sd_lookup(struct sip_msg* _msg, char* _table, char* _owner)
259 395
 
260 396
 	return sd_lookup_owner(_msg, &table_s, NULL);
261 397
 }
398
+
399
+/**
400
+ *
401
+ */
402
+int w_sd_lookup_group(struct sip_msg* _msg, char* _table, char* _group)
403
+{
404
+	str table_s, group_s;
405
+
406
+	if(_table==NULL || fixup_get_svalue(_msg, (gparam_p)_table, &table_s)!=0)
407
+	{
408
+		LM_ERR("invalid table parameter");
409
+		return -1;
410
+	}
411
+
412
+	if(_group==NULL ||fixup_get_svalue(_msg, (gparam_p)_group, &group_s)!=0)
413
+	{
414
+		LM_ERR("invalid group parameter");
415
+		return -1;
416
+	}
417
+	return sd_lookup_group(_msg, &table_s, &group_s);
418
+}
... ...
@@ -27,6 +27,8 @@
27 27
 #include "../../core/parser/msg_parser.h"
28 28
 
29 29
 int w_sd_lookup(struct sip_msg* _msg, char* _table, char* _owner);
30
+int w_sd_lookup_group(struct sip_msg* _msg, char* _table, char* _group);
30 31
 int sd_lookup_owner(struct sip_msg* _msg, str* _stable, str* _sowner);
32
+int sd_lookup_group(struct sip_msg* _msg, str* _stable, str* _sgroup);
31 33
 
32 34
 #endif /* _SDLOOKUP_H_ */
... ...
@@ -54,6 +54,7 @@ str domain_column    = str_init("domain");
54 54
 str sd_user_column   = str_init("sd_username");
55 55
 str sd_domain_column = str_init("sd_domain");
56 56
 str new_uri_column   = str_init("new_uri");
57
+str group_column     = str_init("group_id");
57 58
 int use_domain       = 0;
58 59
 static str domain_prefix    = {NULL, 0};
59 60
 
... ...
@@ -70,6 +71,8 @@ static cmd_export_t cmds[] = {
70 71
 		REQUEST_ROUTE},
71 72
 	{"sd_lookup", (cmd_function)w_sd_lookup, 2, fixup_spve_spve, 0,
72 73
 		REQUEST_ROUTE},
74
+	{"sd_lookup_group", (cmd_function)w_sd_lookup_group, 2, fixup_spve_spve, 0,
75
+		REQUEST_ROUTE},
73 76
 	{0, 0, 0, 0, 0, 0}
74 77
 };
75 78
 
... ...
@@ -180,6 +183,11 @@ static sr_kemi_t sr_kemi_speeddial_exports[] = {
180 183
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
181 184
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
182 185
 	},
186
+	{ str_init("speeddial"), str_init("lookup_group"),
187
+		SR_KEMIP_INT, sd_lookup_group,
188
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
189
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
190
+	},
183 191
 
184 192
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
185 193
 };
... ...
@@ -30,13 +30,14 @@
30 30
 
31 31
 /* Module parameters variables */
32 32
 
33
-extern str user_column;     /* 'username' column name */
34
-extern str domain_column;   /* 'domain' column name */
35
-extern str sd_user_column;     /* 'sd_username' column name */
36
-extern str sd_domain_column;   /* 'sd_domain' column name */
37
-extern str new_uri_column;   /* 'new_uri' column name */
38
-extern int   use_domain;      /* use or not the domain for sd lookup */
39
-extern str   dstrip_s;
33
+extern str user_column;       /* 'username' column name */
34
+extern str domain_column;     /* 'domain' column name */
35
+extern str sd_user_column;    /* 'sd_username' column name */
36
+extern str sd_domain_column;  /* 'sd_domain' column name */
37
+extern str new_uri_column;    /* 'new_uri' column name */
38
+extern str group_column;      /* 'group' column name */
39
+extern int use_domain;        /* use or not the domain for sd lookup */
40
+extern str dstrip_s;
40 41
 
41 42
 extern db_func_t db_funcs;    /* Database functions */
42 43
 extern db1_con_t* db_handle;   /* Database connection handle */
... ...
@@ -11,5 +11,5 @@ CREATE TABLE speed_dial (
11 11
     CONSTRAINT speed_dial_speed_dial_idx UNIQUE (username, domain, sd_domain, sd_username)
12 12
 );
13 13
 
14
-INSERT INTO version (table_name, table_version) values ('speed_dial','2');
14
+INSERT INTO version (table_name, table_version) values ('speed_dial','3');
15 15
 
... ...
@@ -11,5 +11,5 @@ CREATE TABLE `speed_dial` (
11 11
     CONSTRAINT speed_dial_idx UNIQUE (`username`, `domain`, `sd_domain`, `sd_username`)
12 12
 );
13 13
 
14
-INSERT INTO version (table_name, table_version) values ('speed_dial','2');
14
+INSERT INTO version (table_name, table_version) values ('speed_dial','3');
15 15
 
... ...
@@ -19,5 +19,5 @@ END speed_dial_tr;
19 19
 /
20 20
 BEGIN map2users('speed_dial'); END;
21 21
 /
22
-INSERT INTO version (table_name, table_version) values ('speed_dial','2');
22
+INSERT INTO version (table_name, table_version) values ('speed_dial','3');
23 23
 
... ...
@@ -11,5 +11,5 @@ CREATE TABLE speed_dial (
11 11
     CONSTRAINT speed_dial_speed_dial_idx UNIQUE (username, domain, sd_domain, sd_username)
12 12
 );
13 13
 
14
-INSERT INTO version (table_name, table_version) values ('speed_dial','2');
14
+INSERT INTO version (table_name, table_version) values ('speed_dial','3');
15 15