1 /*
2  * imc module - instant messaging conferencing implementation
3  *
4  * Copyright (C) 2006 Voice Sistem S.R.L.
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <strings.h>
29 
30 #include <sys/types.h>
31 #include "../../core/mem/shm_mem.h"
32 #include "../../core/mem/mem.h"
33 #include "../../core/sr_module.h"
34 #include "../../core/dprint.h"
35 #include "../../core/parser/parse_uri.h"
36 #include "../../core/parser/msg_parser.h"
37 
38 #include "imc.h"
39 #include "imc_cmd.h"
40 
41 #define ROOMS "Rooms:\n"
42 #define MEMBERS "Members:\n"
43 
44 #define PREFIX "*** "
45 
46 #define IMC_BUF_SIZE 32768
47 static char imc_body_buf[IMC_BUF_SIZE];
48 
49 static str imc_msg_type = { "MESSAGE", 7 };
50 
51 static str msg_room_created       = STR_STATIC_INIT(PREFIX "Room was created");
52 static str msg_room_destroyed     = STR_STATIC_INIT(PREFIX "Room has been destroyed");
53 static str msg_room_not_found     = STR_STATIC_INIT(PREFIX "Room not found");
54 static str msg_room_exists        = STR_STATIC_INIT(PREFIX "Room already exists");
55 static str msg_leave_error        = STR_STATIC_INIT(PREFIX "You are the room's owner and cannot leave. Use #destroy if you wish to destroy the room.");
56 static str msg_room_exists_priv   = STR_STATIC_INIT(PREFIX "A private room with the same name already exists");
57 static str msg_room_exists_member = STR_STATIC_INIT(PREFIX "Room already exists and you are a member");
58 static str msg_user_joined        = STR_STATIC_INIT(PREFIX "%.*s has joined the room");
59 static str msg_already_joined     = STR_STATIC_INIT(PREFIX "You are in the room already");
60 static str msg_user_left          = STR_STATIC_INIT(PREFIX "%.*s has left the room");
61 static str msg_join_attempt_bcast = STR_STATIC_INIT(PREFIX "%.*s attempted to join the room");
62 static str msg_join_attempt_ucast = STR_STATIC_INIT(PREFIX "Private rooms are by invitation only. Room owners have been notified.");
63 static str msg_invite             = STR_STATIC_INIT(PREFIX "%.*s invites you to join the room (send '%.*saccept' or '%.*sreject')");
64 static str msg_add_reject         = STR_STATIC_INIT(PREFIX "You don't have the permmission to add members to this room");
65 #if 0
66 static str msg_rejected           = STR_STATIC_INIT(PREFIX "%.*s has rejected invitation");
67 #endif
68 static str msg_user_removed       = STR_STATIC_INIT(PREFIX "You have been removed from the room");
69 static str msg_invalid_command    = STR_STATIC_INIT(PREFIX "Invalid command '%.*s' (send '%.*shelp' for help)");
70 
71 int imc_send_message(str *src, str *dst, str *headers, str *body);
72 int imc_room_broadcast(imc_room_p room, str *ctype, str *body);
73 void imc_inv_callback( struct cell *t, int type, struct tmcb_params *ps);
74 
75 
76 extern imc_hentry_p _imc_htable;
77 extern int imc_hash_size;
78 
79 
get_callid(struct sip_msg * msg)80 static str *get_callid(struct sip_msg *msg)
81 {
82 	if ((parse_headers(msg, HDR_CALLID_F, 0) != -1)
83 		&& msg->callid) {
84 		return &msg->callid->body;
85 	}
86 	return NULL;
87 }
88 
89 
build_headers(struct sip_msg * msg)90 static str *build_headers(struct sip_msg *msg)
91 {
92 	static str name = STR_STATIC_INIT("In-Reply-To: ");
93 	static char buf[1024];
94 	static str rv;
95 	str *callid;
96 
97 	if ((callid = get_callid(msg)) == NULL)
98 		return &all_hdrs;
99 
100 	rv.s = buf;
101 	rv.len = all_hdrs.len + name.len + callid->len;
102 
103 	if (rv.len > sizeof(buf)) {
104 		LM_ERR("Header buffer too small for In-Reply-To header\n");
105 		return &all_hdrs;
106 	}
107 
108 	memcpy(buf, all_hdrs.s, all_hdrs.len);
109 	memcpy(buf + all_hdrs.len, name.s, name.len);
110 	memcpy(buf + all_hdrs.len + name.len, callid->s, callid->len);
111 	return &rv;
112 }
113 
114 
format_uri(str uri)115 static str *format_uri(str uri)
116 {
117 	static char buf[512];
118 	static str rv;
119 	struct sip_uri parsed;
120 
121 	rv.s = NULL;
122 	rv.len = 0;
123 
124 	if (parse_uri(uri.s, uri.len, &parsed) != 0) {
125 		LM_ERR("bad uri [%.*s]!\n", STR_FMT(&uri));
126 	} else {
127 		rv.s = buf;
128 		rv.len = snprintf(buf, sizeof(buf), "[%.*s]", STR_FMT(&parsed.user));
129 		if (rv.len >= sizeof(buf)) {
130 			LM_ERR("Buffer too small\n");
131 			rv.len = 0;
132 		}
133 	}
134 	return &rv;
135 }
136 
137 
138 /*
139  * Given string in value and a parsed URI in template, build a full
140  * URI as follows:
141  * 1) If value has no URI scheme, add sip:
142  * 2) If value has no domain, add domain from template
143  * 3) Use the string in value for the username portion
144  *
145  * This function is intended for converting a URI or number provided
146  * by the user in a command to a full SIP URI. The caller is
147  * responsible for freeing the buffer in res->s which will be
148  * allocated with pkg_malloc.
149  */
build_uri(str * res,str value,struct sip_uri * template)150 static int build_uri(str *res, str value, struct sip_uri *template)
151 {
152 	int len = value.len, add_domain = 0, add_scheme = 0;
153 
154 	if (memchr(value.s, ':', value.len) == NULL) {
155 		add_scheme = 1;
156 		len += 4; /* sip: */
157 	}
158 
159 	if (memchr(value.s, '@', value.len) == NULL) {
160 		add_domain = 1;
161 		len += 1 + template->host.len;
162 	}
163 
164 	if ((res->s = (char*)pkg_malloc(len)) == NULL) {
165 		LM_ERR("No memory left\n");
166 		return -1;
167 	}
168 	res->len = len;
169 	len = 0;
170 
171 	if (add_scheme) {
172 		strcpy(res->
173 			   s, "sip:");
174 		len += 4;
175 	}
176 
177 	memcpy(res->s + len, value.s, value.len);
178 	len += value.len;
179 
180 	if (add_domain) {
181 		res->s[len++] = '@';
182 		memcpy(res->s + len, template->host.s, template->host.len);
183 	}
184 	return 0;
185 }
186 
187 
188 /*
189  * Return a struct imc_uri which contains a SIP URI both in string
190  * form and parsed to components. Calls build_uri internally and then
191  * parses the resulting URI with parse_uri. See the description of
192  * build_uri for more detail on arguments.
193  *
194  * The caller is responsible for pkg_freeing res->uri.s
195  */
build_imc_uri(struct imc_uri * res,str value,struct sip_uri * template)196 static int build_imc_uri(struct imc_uri *res, str value, struct sip_uri *template)
197 {
198 	int rc;
199 
200 	rc = build_uri(&res->uri, value, template);
201 	if (rc != 0) return rc;
202 
203 	if (parse_uri(res->uri.s, res->uri.len, &res->parsed) != 0) {
204 		LM_ERR("bad uri [%.*s]!\n", STR_FMT(&res->uri));
205 		pkg_free(res->uri.s);
206 		res->uri.s = NULL;
207 		res->uri.len = 0;
208 		return -1;
209 	}
210 	return 0;
211 }
212 
213 
214 /**
215  * parse cmd
216  */
imc_parse_cmd(char * buf,int len,imc_cmd_p cmd)217 int imc_parse_cmd(char *buf, int len, imc_cmd_p cmd)
218 {
219 	char *p;
220 	int i;
221 	if(buf==NULL || len<=0 || cmd==NULL)
222 	{
223 		LM_ERR("invalid parameters\n");
224 		return -1;
225 	}
226 
227 	memset(cmd, 0, sizeof(imc_cmd_t));
228 	if(buf[0]!=imc_cmd_start_char)
229 	{
230 		LM_ERR("invalid command [%.*s]\n", len, buf);
231 		return -1;
232 	}
233 	p = &buf[1];
234 	cmd->name.s = p;
235 	while(*p && p<buf+len)
236 	{
237 		if(*p==' ' || *p=='\t' || *p=='\r' || *p=='\n')
238 			break;
239 		p++;
240 	}
241 	if(cmd->name.s == p)
242 	{
243 		LM_ERR("no command in [%.*s]\n", len, buf);
244 		return -1;
245 	}
246 	cmd->name.len = p - cmd->name.s;
247 
248 	/* identify the command */
249 	if(cmd->name.len==(sizeof("create")-1)
250 			&& !strncasecmp(cmd->name.s, "create", cmd->name.len))
251 	{
252 		cmd->type = IMC_CMDID_CREATE;
253 	} else if(cmd->name.len==(sizeof("join")-1)
254 				&& !strncasecmp(cmd->name.s, "join", cmd->name.len)) {
255 		cmd->type = IMC_CMDID_JOIN;
256 	} else if(cmd->name.len==(sizeof("invite")-1)
257 				&& !strncasecmp(cmd->name.s, "invite", cmd->name.len)) {
258 		cmd->type = IMC_CMDID_INVITE;
259 	} else if(cmd->name.len==(sizeof("add")-1)
260 				&& !strncasecmp(cmd->name.s, "add", cmd->name.len)) {
261 		cmd->type = IMC_CMDID_ADD;
262 	} else if(cmd->name.len==(sizeof("accept")-1)
263 				&& !strncasecmp(cmd->name.s, "accept", cmd->name.len)) {
264 		cmd->type = IMC_CMDID_ACCEPT;
265 	} else if(cmd->name.len==(sizeof("reject")-1)
266 				&& !strncasecmp(cmd->name.s, "reject", cmd->name.len)) {
267 		cmd->type = IMC_CMDID_REJECT;
268 	} else if(cmd->name.len==(sizeof("deny")-1)
269 				&& !strncasecmp(cmd->name.s, "deny", cmd->name.len)) {
270 		cmd->type = IMC_CMDID_REJECT;
271 	} else if(cmd->name.len==(sizeof("remove")-1)
272 				&& !strncasecmp(cmd->name.s, "remove", cmd->name.len)) {
273 		cmd->type = IMC_CMDID_REMOVE;
274 	} else if(cmd->name.len==(sizeof("leave")-1)
275 				&& !strncasecmp(cmd->name.s, "leave", cmd->name.len)) {
276 		cmd->type = IMC_CMDID_LEAVE;
277 	} else if(cmd->name.len==(sizeof("exit")-1)
278 				&& !strncasecmp(cmd->name.s, "exit", cmd->name.len)) {
279 		cmd->type = IMC_CMDID_LEAVE;
280 	} else if(cmd->name.len==(sizeof("members")-1)
281 				&& !strncasecmp(cmd->name.s, "members", cmd->name.len)) {
282 		cmd->type = IMC_CMDID_MEMBERS;
283 	} else if(cmd->name.len==(sizeof("rooms")-1)
284 				&& !strncasecmp(cmd->name.s, "rooms", cmd->name.len)) {
285 		cmd->type = IMC_CMDID_ROOMS;
286 	} else if(cmd->name.len==(sizeof("list")-1)
287 				&& !strncasecmp(cmd->name.s, "list", cmd->name.len)) {
288 		cmd->type = IMC_CMDID_MEMBERS;
289 	} else if(cmd->name.len==(sizeof("destroy")-1)
290 				&& !strncasecmp(cmd->name.s, "destroy", cmd->name.len)) {
291 		cmd->type = IMC_CMDID_DESTROY;
292 	} else if(cmd->name.len==(sizeof("help")-1)
293 				&& !strncasecmp(cmd->name.s, "help", cmd->name.len)) {
294 		cmd->type = IMC_CMDID_HELP;
295 		goto done;
296 	} else {
297 		cmd->type = IMC_CMDID_UNKNOWN;
298 		goto done;
299 	}
300 
301 
302 	if(*p=='\0' || p>=buf+len)
303 		goto done;
304 
305 	i=0;
306 	do {
307 		while(p<buf+len && (*p==' ' || *p=='\t'))
308 			p++;
309 		if(p>=buf+len || *p=='\0' || *p=='\r' || *p=='\n')
310 			goto done;
311 		cmd->param[i].s = p;
312 		while(p<buf+len)
313 		{
314 			if(*p=='\0' || *p==' ' || *p=='\t' || *p=='\r' || *p=='\n')
315 				break;
316 			p++;
317 		}
318 		cmd->param[i].len =  p - cmd->param[i].s;
319 		i++;
320 		if(i>=IMC_CMD_MAX_PARAM)
321 			break;
322 	} while(1);
323 
324 done:
325 	LM_DBG("command: [%.*s]\n", STR_FMT(&cmd->name));
326 	for(i=0; i<IMC_CMD_MAX_PARAM; i++)
327 	{
328 		if(cmd->param[i].len<=0)
329 			break;
330 		LM_DBG("parameter %d=[%.*s]\n", i, STR_FMT(&cmd->param[i]));
331 	}
332 	return 0;
333 }
334 
335 
336 
imc_handle_create(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)337 int imc_handle_create(struct sip_msg* msg, imc_cmd_t *cmd,
338 					  struct imc_uri *src, struct imc_uri *dst)
339 {
340 	int rv = -1;
341 	imc_room_p rm = 0;
342 	imc_member_p member = 0;
343 	int flag_room = 0;
344 	int flag_member = 0;
345 	str body;
346 	struct imc_uri room;
347 	int params = 0;
348 	str rs = STR_NULL, ps = STR_NULL;
349 
350 	memset(&room, '\0', sizeof(room));
351 
352 	if (cmd->param[0].s) {
353 		params++;
354 		if (cmd->param[1].s) {
355 			params++;
356 		}
357 	}
358 
359 	switch(params) {
360 	case 0:
361 		/* With no parameter, use To for the room uri and create a public room */
362 		break;
363 
364 	case 1:
365 		/* With one parameter, if the value is "private", it indicates
366 		 * a private room, otherwise it is the URI of the room and we
367 		 * create a public room. */
368 		if (cmd->param[0].len == IMC_ROOM_PRIVATE_LEN
369 				&& !strncasecmp(cmd->param[0].s, IMC_ROOM_PRIVATE,
370 					cmd->param[0].len)) {
371 			ps = cmd->param[0];
372 		} else {
373 			rs = cmd->param[0];
374 		}
375 		break;
376 
377 	case 2:
378 		/* With two parameters, the first parameter is room URI and
379 		 * the second parameter must be "private". */
380 		rs = cmd->param[0];
381 		ps = cmd->param[1];
382 		break;
383 
384 	default:
385 		LM_ERR("Invalid number of parameters %d\n", params);
386 		goto error;
387 	}
388 
389 	if (build_imc_uri(&room, rs.s ? rs : dst->parsed.user, &dst->parsed) != 0)
390 		goto error;
391 
392 	if (ps.s) {
393 		if (ps.len == IMC_ROOM_PRIVATE_LEN
394 				&& !strncasecmp(ps.s, IMC_ROOM_PRIVATE, ps.len)) {
395 			flag_room |= IMC_ROOM_PRIV;
396 			LM_DBG("Room with private flag on\n");
397 		} else {
398 			LM_ERR("Second argument to command 'create' must be string 'private'\n");
399 			goto error;
400 		}
401 	}
402 
403 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
404 	if (rm == NULL) {
405 		LM_DBG("Creating new room [%.*s]\n", STR_FMT(&room.uri));
406 
407 		rm = imc_add_room(&room.parsed.user, &room.parsed.host, flag_room);
408 		if (rm == NULL) {
409 			LM_ERR("Failed to add new room\n");
410 			goto error;
411 		}
412 		LM_DBG("Added room [%.*s]\n", STR_FMT(&rm->uri));
413 
414 		flag_member |= IMC_MEMBER_OWNER;
415 		/* adding the owner as the first member*/
416 		member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
417 		if (member == NULL) {
418 			LM_ERR("failed to add owner [%.*s]\n", STR_FMT(&src->uri));
419 			goto error;
420 		}
421 		LM_DBG("Added [%.*s] as the first member in room [%.*s]\n",
422 			   STR_FMT(&member->uri), STR_FMT(&rm->uri));
423 
424 		imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created);
425 		goto done;
426 	}
427 
428 	LM_DBG("Room [%.*s] already exists\n", STR_FMT(&rm->uri));
429 
430 	if (imc_check_on_create) {
431 		imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists);
432 		goto done;
433 	}
434 
435 	if (rm->flags & IMC_ROOM_PRIV) {
436 		imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists_priv);
437 		goto done;
438 	}
439 
440 	LM_DBG("Checking if user [%.*s] is a member\n", STR_FMT(&src->uri));
441 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
442 
443 	if (member) {
444 		imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists_member);
445 		goto done;
446 	}
447 
448 	member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
449 	if (member == NULL) {
450 		LM_ERR("Failed to add member [%.*s]\n", STR_FMT(&src->uri));
451 		goto error;
452 	}
453 	LM_DBG("Added [%.*s] as member to room [%.*s]\n", STR_FMT(&member->uri),
454 			STR_FMT(&rm->uri));
455 
456 	body.s = imc_body_buf;
457 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s,
458 			STR_FMT(format_uri(member->uri)));
459 
460 	if (body.len < 0) {
461 		LM_ERR("Error while building response\n");
462 		goto error;
463 	}
464 
465 	if (body.len > 0)
466 		imc_room_broadcast(rm, build_headers(msg), &body);
467 
468 	if (body.len >= sizeof(imc_body_buf))
469 		LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
470 
471 done:
472 	rv = 0;
473 error:
474 	if (room.uri.s) pkg_free(room.uri.s);
475 	if (rm != NULL) imc_release_room(rm);
476 	return rv;
477 }
478 
479 
imc_handle_join(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)480 int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd,
481 		struct imc_uri *src, struct imc_uri *dst)
482 {
483 	int rv = -1;
484 	imc_room_p rm = 0;
485 	imc_member_p member = 0;
486 	int flag_room = 0;
487 	int flag_member = 0;
488 	str body;
489 	struct imc_uri room;
490 
491 	if(cmd==NULL || src==NULL || dst==NULL) {
492 		return -1;
493 	}
494 
495 	memset(&room, '\0', sizeof(room));
496 	if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
497 		goto error;
498 
499 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
500 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
501 		LM_DBG("Room [%.*s] not found\n", STR_FMT(&room.uri));
502 
503 		if (!imc_create_on_join) {
504 			imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_not_found);
505 			goto done;
506 		}
507 
508 		LM_DBG("Creating room [%.*s]\n", STR_FMT(&room.uri));
509 		rm = imc_add_room(&room.parsed.user, &room.parsed.host, flag_room);
510 		if (rm == NULL) {
511 			LM_ERR("Failed to add new room [%.*s]\n", STR_FMT(&room.uri));
512 			goto error;
513 		}
514 		LM_DBG("Created a new room [%.*s]\n", STR_FMT(&rm->uri));
515 		flag_member |= IMC_MEMBER_OWNER;
516 		member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
517 		if (member == NULL) {
518 			LM_ERR("Failed to add new member [%.*s]\n", STR_FMT(&src->uri));
519 			goto error;
520 		}
521 		/* send info message */
522 		imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created);
523 		goto done;
524 	}
525 
526 	LM_DBG("Found room [%.*s]\n", STR_FMT(&rm->uri));
527 
528 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
529 	if (member && !(member->flags & IMC_MEMBER_DELETED)) {
530 		LM_DBG("User [%.*s] is already in the room\n", STR_FMT(&member->uri));
531 		imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_already_joined);
532 		goto done;
533 	}
534 
535 	body.s = imc_body_buf;
536 	if (!(rm->flags & IMC_ROOM_PRIV)) {
537 		LM_DBG("adding new member [%.*s]\n", STR_FMT(&src->uri));
538 		member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
539 		if (member == NULL) {
540 			LM_ERR("Failed to add new user [%.*s]\n", STR_FMT(&src->uri));
541 			goto error;
542 		}
543 
544 		body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s,
545 				STR_FMT(format_uri(src->uri)));
546 	} else {
547 		LM_DBG("Attept to join private room [%.*s] by [%.*s]\n",
548 			STR_FMT(&rm->uri), STR_FMT(&src->uri));
549 
550 		body.len = snprintf(body.s, sizeof(imc_body_buf), msg_join_attempt_bcast.s,
551 				STR_FMT(format_uri(src->uri)));
552 		imc_send_message(&rm->uri, &src->uri, build_headers(msg), &msg_join_attempt_ucast);
553 	}
554 
555 	if (body.len < 0) {
556 		LM_ERR("Error while building response\n");
557 		goto error;
558 	}
559 
560 	if (body.len > 0)
561 		imc_room_broadcast(rm, build_headers(msg), &body);
562 
563 	if (body.len >= sizeof(imc_body_buf))
564 		LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
565 
566 done:
567 	if (member != NULL && (member->flags & IMC_MEMBER_INVITED))
568 		member->flags &= ~IMC_MEMBER_INVITED;
569 
570 	rv = 0;
571 error:
572 	if (room.uri.s != NULL) pkg_free(room.uri.s);
573 	if (rm != NULL) imc_release_room(rm);
574 	return rv;
575 }
576 
577 
imc_handle_invite(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)578 int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd,
579 		struct imc_uri *src, struct imc_uri *dst)
580 {
581 	int rv = -1;
582 	imc_room_p rm = 0;
583 	imc_member_p member = 0;
584 	int flag_member = 0;
585 	str body;
586 	del_member_t *cback_param = NULL;
587 	int result;
588 	uac_req_t uac_r;
589 	struct imc_uri user, room;
590 
591 	memset(&user, '\0', sizeof(user));
592 	memset(&room, '\0', sizeof(room));
593 
594 	if (cmd->param[0].s == NULL) {
595 		LM_INFO("Invite command with missing argument from [%.*s]\n", STR_FMT(&src->uri));
596 		goto error;
597 	}
598 
599 	if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
600 		goto error;
601 
602 	if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
603 		goto error;
604 
605 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
606 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
607 		LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
608 		goto error;
609 	}
610 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
611 
612 	if (member == NULL) {
613 		LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
614 			STR_FMT(&src->uri), STR_FMT(&room.uri));
615 		goto error;
616 	}
617 
618 	if (!(member->flags & IMC_MEMBER_OWNER) &&
619 			!(member->flags & IMC_MEMBER_ADMIN)) {
620 		LM_ERR("User [%.*s] has no right to invite others!\n", STR_FMT(&member->uri));
621 		goto error;
622 	}
623 
624 	member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
625 	if (member != NULL) {
626 		LM_ERR("User [%.*s] is already in room [%.*s]!\n", STR_FMT(&member->uri), STR_FMT(&rm->uri));
627 		goto error;
628 	}
629 
630 	flag_member |= IMC_MEMBER_INVITED;
631 	member = imc_add_member(rm, &user.parsed.user, &user.parsed.host, flag_member);
632 	if (member == NULL) {
633 		LM_ERR("Adding member [%.*s] failed\n", STR_FMT(&user.uri));
634 		goto error;
635 	}
636 
637 	body.s = imc_body_buf;
638 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_invite.s, STR_FMT(format_uri(src->uri)),
639 		STR_FMT(&imc_cmd_start_str), STR_FMT(&imc_cmd_start_str));
640 
641 	if (body.len < 0) {
642 		LM_ERR("Error while building response\n");
643 		goto error;
644 	}
645 
646 	LM_DBG("to=[%.*s]\nfrom=[%.*s]\nbody=[%.*s]\n",
647 	       STR_FMT(&member->uri), STR_FMT(&rm->uri), STR_FMT(&body));
648 
649 	if (body.len >= sizeof(imc_body_buf))
650 		LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
651 
652 	if ((cback_param = (del_member_t*)shm_malloc(sizeof(del_member_t))) == NULL) {
653 		LM_ERR("No shared memory left\n");
654 		goto error;
655 	}
656 	memset(cback_param, 0, sizeof(del_member_t));
657 	cback_param->room_name = rm->name;
658 	cback_param->room_domain = rm->domain;
659 	cback_param->member_name = member->user;
660 	cback_param->member_domain = member->domain;
661 	cback_param->inv_uri = member->uri;
662 	/*?!?! possible race with 'remove user' */
663 
664 	set_uac_req(&uac_r, &imc_msg_type, build_headers(msg), &body, 0, TMCB_LOCAL_COMPLETED,
665 				imc_inv_callback, (void*)(cback_param));
666 	result = tmb.t_request(&uac_r,
667 		&member->uri,							/* Request-URI */
668 		&member->uri,							/* To */
669 		&rm->uri,								/* From */
670 		(outbound_proxy.s) ? &outbound_proxy : NULL/* outbound proxy*/
671 		);
672 	if (result < 0) {
673 		LM_ERR("Error in tm send request\n");
674 		shm_free(cback_param);
675 		goto error;
676 	}
677 
678 	rv = 0;
679 error:
680 	if (user.uri.s != NULL) pkg_free(user.uri.s);
681 	if (room.uri.s != NULL) pkg_free(room.uri.s);
682 	if (rm != NULL) imc_release_room(rm);
683 	return rv;
684 }
685 
686 
imc_handle_add(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)687 int imc_handle_add(struct sip_msg* msg, imc_cmd_t *cmd,
688 		struct imc_uri *src, struct imc_uri *dst)
689 {
690 	int rv = -1;
691 	imc_room_p rm = 0;
692 	imc_member_p member = 0;
693 	str body;
694 	struct imc_uri user, room;
695 
696 	memset(&user, '\0', sizeof(user));
697 	memset(&room, '\0', sizeof(room));
698 
699 	if (cmd->param[0].s == NULL) {
700 		LM_INFO("Add command with missing argument from [%.*s]\n", STR_FMT(&src->uri));
701 		goto error;
702 	}
703 
704 	if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
705 		goto error;
706 
707 	if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
708 		goto error;
709 
710 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
711 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
712 		LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
713 		goto error;
714 	}
715 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
716 
717 	if (member == NULL) {
718 		LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
719 			STR_FMT(&src->uri), STR_FMT(&room.uri));
720 		goto error;
721 	}
722 
723 	if (!(member->flags & IMC_MEMBER_OWNER) &&
724 			!(member->flags & IMC_MEMBER_ADMIN)) {
725 		LM_ERR("User [%.*s] has no right to add others!\n", STR_FMT(&member->uri));
726 		imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_add_reject);
727 		goto done;
728 	}
729 
730 	member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
731 	if (member != NULL) {
732 		LM_ERR("User [%.*s] is already in room [%.*s]!\n", STR_FMT(&member->uri), STR_FMT(&rm->uri));
733 		goto error;
734 	}
735 
736 	member = imc_add_member(rm, &user.parsed.user, &user.parsed.host, 0);
737 	if (member == NULL) {
738 		LM_ERR("Adding member [%.*s] failed\n", STR_FMT(&user.uri));
739 		goto error;
740 	}
741 
742 	body.s = imc_body_buf;
743 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri)));
744 
745 	if (body.len < 0) {
746 		LM_ERR("Error while building response\n");
747 		goto error;
748 	}
749 
750 	if (body.len > 0)
751 		imc_room_broadcast(rm, build_headers(msg), &body);
752 
753 	if (body.len >= sizeof(imc_body_buf))
754 		LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
755 
756 done:
757 	rv = 0;
758 error:
759 	if (user.uri.s != NULL) pkg_free(user.uri.s);
760 	if (room.uri.s != NULL) pkg_free(room.uri.s);
761 	if (rm != NULL) imc_release_room(rm);
762 	return rv;
763 }
764 
765 
imc_handle_accept(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)766 int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd,
767 		struct imc_uri *src, struct imc_uri *dst)
768 {
769 	int rv = -1;
770 	imc_room_p rm = 0;
771 	imc_member_p member = 0;
772 	str body;
773 	struct imc_uri room;
774 
775 	memset(&room, '\0', sizeof(room));
776 
777 	if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
778 		goto error;
779 
780 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
781 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
782 		LM_ERR("Room [%.*s] does not exist!\n",	STR_FMT(&room.uri));
783 		goto error;
784 	}
785 
786 	/* if aready invited add as a member */
787 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
788 	if (member == NULL || !(member->flags & IMC_MEMBER_INVITED)) {
789 		LM_ERR("User [%.*s] not invited to the room!\n", STR_FMT(&src->uri));
790 		goto error;
791 	}
792 
793 	member->flags &= ~IMC_MEMBER_INVITED;
794 
795 	body.s = imc_body_buf;
796 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri)));
797 
798 	if (body.len < 0) {
799 		LM_ERR("Error while building response\n");
800 		goto error;
801 	}
802 
803 	if (body.len > 0)
804 		imc_room_broadcast(rm, build_headers(msg), &body);
805 
806 	if (body.len >= sizeof(imc_body_buf))
807 		LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
808 
809 	rv = 0;
810 error:
811 	if (room.uri.s != NULL) pkg_free(room.uri.s);
812 	if (rm != NULL) imc_release_room(rm);
813 	return rv;
814 }
815 
816 
imc_handle_remove(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)817 int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd,
818 		struct imc_uri *src, struct imc_uri *dst)
819 {
820 	int rv = -1;
821 	imc_room_p rm = 0;
822 	imc_member_p member = 0;
823 	str body;
824 	struct imc_uri user, room;
825 
826 	memset(&user, '\0', sizeof(user));
827 	memset(&room, '\0', sizeof(room));
828 
829 	if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
830 		goto error;
831 
832 	if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
833 		goto error;
834 
835 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
836 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
837 		LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
838 		goto error;
839 	}
840 
841 	/* verify if the user who sent the request is a member in the room
842 	 * and has the right to remove other users */
843 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
844 	if (member == NULL) {
845 		LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
846 				STR_FMT(&src->uri), STR_FMT(&rm->uri));
847 		goto error;
848 	}
849 
850 	if (!(member->flags & IMC_MEMBER_OWNER) && !(member->flags & IMC_MEMBER_ADMIN)) {
851 		LM_ERR("User [%.*s] has no right to remove from room [%.*s]!\n",
852 			   STR_FMT(&src->uri), STR_FMT(&rm->uri));
853 		goto error;
854 	}
855 
856 	/* verify if the user that is to be removed is a member of the room */
857 	member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
858 	if (member == NULL) {
859 		LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
860 				STR_FMT(&user.uri), STR_FMT(&rm->uri));
861 		goto error;
862 	}
863 
864 	if (member->flags & IMC_MEMBER_OWNER) {
865 		LM_ERR("User [%.*s] is owner of room [%.*s] and cannot be removed!\n",
866 			   STR_FMT(&member->uri), STR_FMT(&rm->uri));
867 		goto error;
868 	}
869 
870 	LM_DBG("to: [%.*s]\nfrom: [%.*s]\nbody: [%.*s]\n",
871 			STR_FMT(&member->uri) , STR_FMT(&rm->uri),
872 			STR_FMT(&msg_user_removed));
873 	imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_user_removed);
874 
875 	member->flags |= IMC_MEMBER_DELETED;
876 	imc_del_member(rm, &user.parsed.user, &user.parsed.host);
877 
878 	body.s = imc_body_buf;
879 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_left.s, STR_FMT(format_uri(member->uri)));
880 
881 	if (body.len < 0) {
882 		LM_ERR("Error while building response\n");
883 		goto error;
884 	}
885 
886 	if (body.len > 0)
887 		imc_room_broadcast(rm, build_headers(msg), &body);
888 
889 	if (body.len >= sizeof(imc_body_buf))
890 		LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
891 
892 	rv = 0;
893 error:
894 	if (user.uri.s != NULL) pkg_free(user.uri.s);
895 	if (room.uri.s != NULL) pkg_free(room.uri.s);
896 	if (rm != NULL) imc_release_room(rm);
897 	return rv;
898 }
899 
900 
imc_handle_reject(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)901 int imc_handle_reject(struct sip_msg* msg, imc_cmd_t *cmd,
902 		struct imc_uri *src, struct imc_uri *dst)
903 {
904 	int rv = -1;
905 	imc_room_p rm = 0;
906 	imc_member_p member = 0;
907 	struct imc_uri room;
908 
909 	memset(&room, '\0', sizeof(room));
910 	if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
911 		goto error;
912 
913 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
914 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
915 		LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
916 		goto error;
917 	}
918 
919 	/* If the user is an invited member, delete it from the list */
920 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
921 	if (member == NULL || !(member->flags & IMC_MEMBER_INVITED)) {
922 		LM_ERR("User [%.*s] was not invited to room [%.*s]!\n",
923 				STR_FMT(&src->uri), STR_FMT(&rm->uri));
924 		goto error;
925 	}
926 
927 #if 0
928 	body.s = imc_body_buf;
929 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_rejected.s, STR_FMT(format_uri(src->uri)));
930 	if (body.len > 0)
931 	    imc_send_message(&rm->uri, &member->uri, build_headers(msg), &body);
932 #endif
933 
934 	LM_DBG("User [%.*s] rejected invitation to room [%.*s]!\n",
935 			STR_FMT(&src->uri), STR_FMT(&rm->uri));
936 
937 	imc_del_member(rm, &src->parsed.user, &src->parsed.host);
938 
939 	rv = 0;
940 error:
941 	if (room.uri.s != NULL) pkg_free(room.uri.s);
942 	if (rm != NULL) imc_release_room(rm);
943 	return rv;
944 }
945 
946 
imc_handle_members(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)947 int imc_handle_members(struct sip_msg* msg, imc_cmd_t *cmd,
948 		struct imc_uri *src, struct imc_uri *dst)
949 {
950 	int rv = -1;
951 	imc_room_p rm = 0;
952 	imc_member_p member = 0;
953 	imc_member_p imp = 0;
954 	str body, *name;
955 	char *p;
956 	size_t left;
957 	struct imc_uri room;
958 
959 	memset(&room, '\0', sizeof(room));
960 	if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user,
961 				&dst->parsed)) {
962 		goto done;
963 	}
964 
965 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
966 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
967 		LM_ERR("Room [%.*s] does not exist!\n",	STR_FMT(&room.uri));
968 		goto done;
969 	}
970 
971 	/* verify if the user is a member of the room */
972 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
973 	if (member == NULL) {
974 		LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
975 				STR_FMT(&src->uri), STR_FMT(&rm->uri));
976 		goto done;
977 	}
978 
979 	p = imc_body_buf;
980 	imc_body_buf[IMC_BUF_SIZE - 1] = '\0';
981 	left = sizeof(imc_body_buf) - 1;
982 
983 	memcpy(p, MEMBERS, sizeof(MEMBERS) - 1);
984 	p += sizeof(MEMBERS) - 1;
985 	left -= sizeof(MEMBERS) - 1;
986 
987 	imp = rm->members;
988 	while (imp) {
989 		if ((imp->flags & IMC_MEMBER_INVITED) || (imp->flags & IMC_MEMBER_DELETED)
990 			|| (imp->flags & IMC_MEMBER_SKIP)) {
991 			imp = imp->next;
992 			continue;
993 		}
994 
995 		if (imp->flags & IMC_MEMBER_OWNER) {
996 			if (left < 2) goto overrun;
997 			*p++ = '*';
998 			left--;
999 		} else if (imp->flags & IMC_MEMBER_ADMIN) {
1000 			if (left < 2) goto overrun;
1001 			*p++ = '~';
1002 			left--;
1003 		}
1004 
1005 		name = format_uri(imp->uri);
1006 		if (left < name->len + 1) goto overrun;
1007 		strncpy(p, name->s, name->len);
1008 		p += name->len;
1009 		left -= name->len;
1010 
1011 		if (left < 2) goto overrun;
1012 		*p++ = '\n';
1013 		left--;
1014 
1015 		imp = imp->next;
1016 	}
1017 
1018 	/* write over last '\n' */
1019 	*(--p) = 0;
1020 	body.s   = imc_body_buf;
1021 	body.len = p - body.s;
1022 
1023 	LM_DBG("members = '%.*s'\n", STR_FMT(&body));
1024 	LM_DBG("Message-ID: '%.*s'\n", STR_FMT(get_callid(msg)));
1025 	imc_send_message(&rm->uri, &member->uri, build_headers(msg), &body);
1026 
1027 	rv = 0;
1028 	goto done;
1029 
1030 overrun:
1031 	LM_ERR("Buffer too small for member list message\n");
1032 
1033 done:
1034 	if (room.uri.s != NULL) pkg_free(room.uri.s);
1035 	if (rm != NULL) imc_release_room(rm);
1036 	return rv;
1037 }
1038 
1039 
imc_handle_rooms(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)1040 int imc_handle_rooms(struct sip_msg* msg, imc_cmd_t *cmd,
1041 		struct imc_uri *src, struct imc_uri *dst)
1042 {
1043 	int i, rv = -1;
1044 	imc_room_p room;
1045 	str body, *name;
1046 	char *p;
1047 	size_t left;
1048 
1049 	p = imc_body_buf;
1050 	left = sizeof(imc_body_buf) - 2;
1051 
1052 	memcpy(p, ROOMS, sizeof(ROOMS) - 1);
1053 	p += sizeof(ROOMS) - 1;
1054 	left -= sizeof(ROOMS) - 1;
1055 
1056 	for (i = 0; i < imc_hash_size; i++) {
1057 		lock_get(&_imc_htable[i].lock);
1058 		for (room = _imc_htable[i].rooms; room != NULL ; room = room->next) {
1059 			if (room->flags & IMC_ROOM_DELETED) continue;
1060 
1061 			name = format_uri(room->uri);
1062 			if (left < name->len) {
1063 				lock_release(&_imc_htable[i].lock);
1064 				goto error;
1065 			}
1066 			strncpy(p, name->s, name->len);
1067 			p += name->len;
1068 			left -= name->len;
1069 
1070 			if (left < 1) {
1071 				lock_release(&_imc_htable[i].lock);
1072 				goto error;
1073 			}
1074 			*p++ = '\n';
1075 			left--;
1076 		}
1077 		lock_release(&_imc_htable[i].lock);
1078 	}
1079 
1080 	/* write over last '\n' */
1081 	*(--p) = 0;
1082 	body.s   = imc_body_buf;
1083 	body.len = p - body.s;
1084 
1085 	LM_DBG("rooms = '%.*s'\n", STR_FMT(&body));
1086 	imc_send_message(&dst->uri, &src->uri, build_headers(msg), &body);
1087 
1088 	return 0;
1089 
1090 error:
1091 	LM_ERR("Buffer too small for member list message\n");
1092 	return rv;
1093 }
1094 
1095 
imc_handle_leave(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)1096 int imc_handle_leave(struct sip_msg* msg, imc_cmd_t *cmd,
1097 		struct imc_uri *src, struct imc_uri *dst)
1098 {
1099 	int rv = -1;
1100 	imc_room_p rm = 0;
1101 	imc_member_p member = 0;
1102 	str body;
1103 	struct imc_uri room;
1104 
1105 	memset(&room, '\0', sizeof(room));
1106 	if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
1107 		goto error;
1108 
1109 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
1110 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
1111 		LM_ERR("Room [%.*s] does not exist!\n",	STR_FMT(&room.uri));
1112 		goto error;
1113 	}
1114 
1115 	/* verify if the user is a member of the room */
1116 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
1117 	if (member == NULL) {
1118 		LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
1119 				STR_FMT(&src->uri), STR_FMT(&rm->uri));
1120 		goto error;
1121 	}
1122 
1123 	if (member->flags & IMC_MEMBER_OWNER) {
1124 		imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_leave_error);
1125         goto done;
1126     }
1127 
1128 	body.s = imc_body_buf;
1129 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_left.s, STR_FMT(format_uri(member->uri)));
1130 
1131 	if (body.len < 0) {
1132 		LM_ERR("Error while building response\n");
1133 		goto error;
1134 	}
1135 
1136 	if (body.len > 0)
1137 		imc_room_broadcast(rm, build_headers(msg), &body);
1138 
1139 	if (body.len >= sizeof(imc_body_buf))
1140 		LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
1141 
1142 	member->flags |= IMC_MEMBER_DELETED;
1143 	imc_del_member(rm, &src->parsed.user, &src->parsed.host);
1144 
1145 done:
1146 	rv = 0;
1147 error:
1148 	if (room.uri.s != NULL) pkg_free(room.uri.s);
1149 	if (rm != NULL) imc_release_room(rm);
1150 	return rv;
1151 }
1152 
1153 
imc_handle_destroy(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)1154 int imc_handle_destroy(struct sip_msg* msg, imc_cmd_t *cmd,
1155 		struct imc_uri *src, struct imc_uri *dst)
1156 {
1157 	int rv = -1;
1158 	imc_room_p rm = 0;
1159 	imc_member_p member = 0;
1160 	struct imc_uri room;
1161 
1162 	memset(&room, '\0', sizeof(room));
1163 	if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
1164 		goto error;
1165 
1166 	rm = imc_get_room(&room.parsed.user, &room.parsed.host);
1167 	if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
1168 		LM_ERR("Room [%.*s] does not exist!\n",	STR_FMT(&room.uri));
1169 		goto error;
1170 	}
1171 
1172 	/* verify is the user is a member of the room*/
1173 	member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
1174 	if (member == NULL) {
1175 		LM_ERR("User [%.*s] is not a member of room [%.*s]!\n",
1176 				STR_FMT(&src->uri), STR_FMT(&rm->uri));
1177 		goto error;
1178 	}
1179 
1180 	if (!(member->flags & IMC_MEMBER_OWNER)) {
1181 		LM_ERR("User [%.*s] is not owner of room [%.*s] and cannot destroy it!\n",
1182 			   STR_FMT(&src->uri), STR_FMT(&rm->uri));
1183 		goto error;
1184 	}
1185 	rm->flags |= IMC_ROOM_DELETED;
1186 
1187 	/* braodcast message */
1188 	imc_room_broadcast(rm, build_headers(msg), &msg_room_destroyed);
1189 
1190 	imc_release_room(rm);
1191 	rm = NULL;
1192 
1193 	LM_DBG("Deleting room [%.*s]\n", STR_FMT(&room.uri));
1194 	imc_del_room(&room.parsed.user, &room.parsed.host);
1195 
1196 	rv = 0;
1197 error:
1198 	if (room.uri.s != NULL) pkg_free(room.uri.s);
1199 	if (rm != NULL) imc_release_room(rm);
1200 	return rv;
1201 }
1202 
1203 
imc_handle_help(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)1204 int imc_handle_help(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
1205 {
1206 	str body;
1207 	uac_req_t uac_r;
1208 
1209 	body.s   = IMC_HELP_MSG;
1210 	body.len = IMC_HELP_MSG_LEN;
1211 
1212 	LM_DBG("to: [%.*s] from: [%.*s]\n", STR_FMT(&src->uri), STR_FMT(&dst->uri));
1213 	set_uac_req(&uac_r, &imc_msg_type, build_headers(msg), &body, 0, 0, 0, 0);
1214 	tmb.t_request(&uac_r,
1215 				NULL,									/* Request-URI */
1216 				&src->uri,								/* To */
1217 				&dst->uri,								/* From */
1218 				(outbound_proxy.s)?&outbound_proxy:NULL/* outbound proxy */
1219 				);
1220 	return 0;
1221 }
1222 
1223 
imc_handle_unknown(struct sip_msg * msg,imc_cmd_t * cmd,struct imc_uri * src,struct imc_uri * dst)1224 int imc_handle_unknown(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
1225 {
1226 	str body;
1227 	uac_req_t uac_r;
1228 
1229 	body.s   = imc_body_buf;
1230 	body.len = snprintf(body.s, sizeof(imc_body_buf), msg_invalid_command.s,
1231 		STR_FMT(&cmd->name), STR_FMT(&imc_cmd_start_str));
1232 
1233 	if (body.len < 0 || body.len >= sizeof(imc_body_buf)) {
1234 		LM_ERR("Unable to print message\n");
1235 		return -1;
1236 	}
1237 
1238 	LM_DBG("to: [%.*s] from: [%.*s]\n", STR_FMT(&src->uri), STR_FMT(&dst->uri));
1239 	set_uac_req(&uac_r, &imc_msg_type, build_headers(msg), &body, 0, 0, 0, 0);
1240 	tmb.t_request(&uac_r,
1241 				NULL,									/* Request-URI */
1242 				&src->uri,								/* To */
1243 				&dst->uri,								/* From */
1244 				(outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy */
1245 			);
1246 	return 0;
1247 }
1248 
1249 
imc_handle_message(struct sip_msg * msg,str * msgbody,struct imc_uri * src,struct imc_uri * dst)1250 int imc_handle_message(struct sip_msg* msg, str *msgbody,
1251 		struct imc_uri *src, struct imc_uri *dst)
1252 {
1253 	int rv = -1;
1254 	imc_room_p room = 0;
1255 	imc_member_p member = 0;
1256 	str body, *user;
1257 
1258 	room = imc_get_room(&dst->parsed.user, &dst->parsed.host);
1259 	if (room == NULL || (room->flags & IMC_ROOM_DELETED)) {
1260 		LM_DBG("Room [%.*s] does not exist!\n",	STR_FMT(&dst->uri));
1261 		goto error;
1262 	}
1263 
1264 	member = imc_get_member(room, &src->parsed.user, &src->parsed.host);
1265 	if (member == NULL || (member->flags & IMC_MEMBER_INVITED)) {
1266 		LM_ERR("User [%.*s] has no right to send messages to room [%.*s]!\n",
1267 				STR_FMT(&src->uri), STR_FMT(&room->uri));
1268 		goto error;
1269 	}
1270 
1271 	LM_DBG("Broadcast to room [%.*s]\n", STR_FMT(&room->uri));
1272 
1273 	user = format_uri(member->uri);
1274 
1275 	body.s = imc_body_buf;
1276 	body.len = snprintf(body.s, sizeof(imc_body_buf), "%.*s: %.*s", STR_FMT(user), STR_FMT(msgbody));
1277 
1278 	if (body.len < 0) {
1279 		LM_ERR("Error while printing message\n");
1280 		goto error;
1281 	}
1282 
1283 	if (body.len >= sizeof(imc_body_buf)) {
1284 		LM_ERR("Buffer too small for message '%.*s'\n", STR_FMT(&body));
1285 		goto error;
1286 	}
1287 
1288 	member->flags |= IMC_MEMBER_SKIP;
1289 	imc_room_broadcast(room, build_headers(msg), &body);
1290 	member->flags &= ~IMC_MEMBER_SKIP;
1291 
1292 	rv = 0;
1293 error:
1294 	if (room != NULL) imc_release_room(room);
1295 	return rv;
1296 }
1297 
1298 
imc_room_broadcast(imc_room_p room,str * ctype,str * body)1299 int imc_room_broadcast(imc_room_p room, str *ctype, str *body)
1300 {
1301 	imc_member_p imp;
1302 
1303 	if (room == NULL || body == NULL)
1304 		return -1;
1305 
1306 	imp = room->members;
1307 
1308 	LM_DBG("nr = %d\n", room->nr_of_members);
1309 
1310 	while(imp) {
1311 		LM_DBG("to uri = %.*s\n", STR_FMT(&imp->uri));
1312 		if ((imp->flags & IMC_MEMBER_INVITED) || (imp->flags & IMC_MEMBER_DELETED)
1313 				|| (imp->flags & IMC_MEMBER_SKIP)) {
1314 			imp = imp->next;
1315 			continue;
1316 		}
1317 
1318 		/* to-do: callback to remove user if delivery fails */
1319 		imc_send_message(&room->uri, &imp->uri, ctype, body);
1320 
1321 		imp = imp->next;
1322 	}
1323 	return 0;
1324 }
1325 
1326 
imc_send_message(str * src,str * dst,str * headers,str * body)1327 int imc_send_message(str *src, str *dst, str *headers, str *body)
1328 {
1329 	uac_req_t uac_r;
1330 
1331 	if (src == NULL || dst == NULL || body == NULL)
1332 		return -1;
1333 
1334 	/* to-do: callback to remove user if delivery fails */
1335 	set_uac_req(&uac_r, &imc_msg_type, headers, body, 0, 0, 0, 0);
1336 	tmb.t_request(&uac_r,
1337 			NULL,										/* Request-URI */
1338 			dst,										/* To */
1339 			src,										/* From */
1340 			(outbound_proxy.s)?&outbound_proxy:NULL  	/* outbound proxy */
1341 		);
1342 	return 0;
1343 }
1344 
1345 
imc_inv_callback(struct cell * t,int type,struct tmcb_params * ps)1346 void imc_inv_callback(struct cell *t, int type, struct tmcb_params *ps)
1347 {
1348 	str body_final;
1349 	char from_uri_buf[256];
1350 	char to_uri_buf[256];
1351 	char body_buf[256];
1352 	str from_uri_s, to_uri_s;
1353 	imc_member_p member= NULL;
1354 	imc_room_p room = NULL;
1355 	uac_req_t uac_r;
1356 
1357 	if (ps->param == NULL || *ps->param == NULL ||
1358 		(del_member_t*)(*ps->param) == NULL) {
1359 		LM_DBG("member not received\n");
1360 		return;
1361 	}
1362 
1363 	LM_DBG("completed with status %d [member name domain:"
1364 			"%p/%.*s/%.*s]\n",ps->code, ps->param,
1365 			STR_FMT(&((del_member_t *)(*ps->param))->member_name),
1366 			STR_FMT(&((del_member_t *)(*ps->param))->member_domain));
1367 	if (ps->code < 300) {
1368 		return;
1369 	} else {
1370 		room = imc_get_room(&((del_member_t *)(*ps->param))->room_name,
1371 						&((del_member_t *)(*ps->param))->room_domain);
1372 		if (room ==NULL) {
1373 			LM_ERR("The room does not exist!\n");
1374 			goto error;
1375 		}
1376 		/*verify if the user who sent the request is a member in the room
1377 		 * and has the right to remove other users */
1378 		member = imc_get_member(room,
1379 				&((del_member_t *)(*ps->param))->member_name,
1380 				&((del_member_t *)(*ps->param))->member_domain);
1381 
1382 		if( member == NULL) {
1383 			LM_ERR("The user is not a member of the room!\n");
1384 			goto error;
1385 		}
1386 		imc_del_member(room,
1387 				&((del_member_t *)(*ps->param))->member_name,
1388 				&((del_member_t *)(*ps->param))->member_domain);
1389 		goto build_inform;
1390 	}
1391 
1392 build_inform:
1393 	body_final.s = body_buf;
1394 	body_final.len = member->uri.len - 4 /* sip: part of URI */ + 20;
1395 	memcpy(body_final.s, member->uri.s + 4, member->uri.len - 4);
1396 	memcpy(body_final.s + member->uri.len - 4," is not registered.  ", 21);
1397 
1398 	goto send_message;
1399 
1400 send_message:
1401 
1402 	from_uri_s.s = from_uri_buf;
1403 	from_uri_s.len = room->uri.len;
1404 	strncpy(from_uri_s.s, room->uri.s, room->uri.len);
1405 
1406 	LM_DBG("sending message\n");
1407 
1408 	to_uri_s.s = to_uri_buf;
1409 	to_uri_s.len = ((del_member_t *)(*ps->param))->inv_uri.len;
1410 	strncpy(to_uri_s.s, ((del_member_t *)(*ps->param))->inv_uri.s,
1411 			((del_member_t *)(*ps->param))->inv_uri.len);
1412 
1413 	LM_DBG("to: %.*s\nfrom: %.*s\nbody: %.*s\n", STR_FMT(&to_uri_s),
1414 			STR_FMT(&from_uri_s), STR_FMT(&body_final));
1415 	set_uac_req(&uac_r, &imc_msg_type, &extra_hdrs, &body_final, 0, 0, 0, 0);
1416 	tmb.t_request(&uac_r,
1417 					NULL,									/* Request-URI */
1418 					&to_uri_s,								/* To */
1419 					&from_uri_s,							/* From */
1420 					(outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy*/
1421 				);
1422 
1423 error:
1424 	if (room != NULL) imc_release_room(room);
1425 	if ((del_member_t *)(*ps->param)) shm_free(*ps->param);
1426 }
1427