2 * imc module - instant messaging conferencing implementation
4 * Copyright (C) 2006 Voice Sistem S.R.L.
6 * This file is part of Kamailio, a free SIP server.
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
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.
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
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"
41 #define ROOMS "Rooms:\n"
42 #define MEMBERS "Members:\n"
46 #define IMC_BUF_SIZE 32768
47 static char imc_body_buf[IMC_BUF_SIZE];
49 static str imc_msg_type = { "MESSAGE", 7 };
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");
66 static str msg_rejected = STR_STATIC_INIT(PREFIX "%.*s has rejected invitation");
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)");
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);
76 extern imc_hentry_p _imc_htable;
77 extern int imc_hash_size;
80 static str *get_callid(struct sip_msg *msg)
82 if ((parse_headers(msg, HDR_CALLID_F, 0) != -1)
84 return &msg->callid->body;
90 static str *build_headers(struct sip_msg *msg)
92 static str name = STR_STATIC_INIT("In-Reply-To: ");
93 static char buf[1024];
97 if ((callid = get_callid(msg)) == NULL)
101 rv.len = all_hdrs.len + name.len + callid->len;
103 if (rv.len > sizeof(buf)) {
104 LM_ERR("Header buffer too small for In-Reply-To header\n");
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);
115 static str *format_uri(str uri)
117 static char buf[512];
119 struct sip_uri parsed;
124 if (parse_uri(uri.s, uri.len, &parsed) != 0) {
125 LM_ERR("bad uri [%.*s]!\n", STR_FMT(&uri));
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");
139 * Given string in value and a parsed URI in template, build a full
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
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.
150 static int build_uri(str *res, str value, struct sip_uri *template)
152 int len = value.len, add_domain = 0, add_scheme = 0;
154 if (memchr(value.s, ':', value.len) == NULL) {
159 if (memchr(value.s, '@', value.len) == NULL) {
161 len += 1 + template->host.len;
164 if ((res->s = (char*)pkg_malloc(len)) == NULL) {
165 LM_ERR("No memory left\n");
177 memcpy(res->s + len, value.s, value.len);
182 memcpy(res->s + len, template->host.s, template->host.len);
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.
194 * The caller is responsible for pkg_freeing res->uri.s
196 static int build_imc_uri(struct imc_uri *res, str value, struct sip_uri *template)
200 rc = build_uri(&res->uri, value, template);
201 if (rc != 0) return rc;
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);
217 int imc_parse_cmd(char *buf, int len, imc_cmd_p cmd)
221 if(buf==NULL || len<=0 || cmd==NULL)
223 LM_ERR("invalid parameters\n");
227 memset(cmd, 0, sizeof(imc_cmd_t));
228 if(buf[0]!=imc_cmd_start_char)
230 LM_ERR("invalid command [%.*s]\n", len, buf);
235 while(*p && p<buf+len)
237 if(*p==' ' || *p=='\t' || *p=='\r' || *p=='\n')
243 LM_ERR("no command in [%.*s]\n", len, buf);
246 cmd->name.len = p - cmd->name.s;
248 /* identify the command */
249 if(cmd->name.len==(sizeof("create")-1)
250 && !strncasecmp(cmd->name.s, "create", cmd->name.len))
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;
297 cmd->type = IMC_CMDID_UNKNOWN;
302 if(*p=='\0' || p>=buf+len)
307 while(p<buf+len && (*p==' ' || *p=='\t'))
309 if(p>=buf+len || *p=='\0' || *p=='\r' || *p=='\n')
314 if(*p=='\0' || *p==' ' || *p=='\t' || *p=='\r' || *p=='\n')
318 cmd->param[i].len = p - cmd->param[i].s;
320 if(i>=IMC_CMD_MAX_PARAM)
325 LM_DBG("command: [%.*s]\n", STR_FMT(&cmd->name));
326 for(i=0; i<IMC_CMD_MAX_PARAM; i++)
328 if(cmd->param[i].len<=0)
330 LM_DBG("parameter %d=[%.*s]\n", i, STR_FMT(&cmd->param[i]));
337 int imc_handle_create(struct sip_msg* msg, imc_cmd_t *cmd,
338 struct imc_uri *src, struct imc_uri *dst)
342 imc_member_p member = 0;
348 str rs = STR_NULL, ps = STR_NULL;
350 memset(&room, '\0', sizeof(room));
352 if (cmd->param[0].s) params++;
353 if (cmd->param[1].s) params++;
357 /* With no parameter, use To for the room uri and create a public room */
361 /* With one parameter, if the value is "private", it indicates
362 * a private room, otherwise it is the URI of the room and we
363 * create a public room. */
364 if (cmd->param[0].len == IMC_ROOM_PRIVATE_LEN && !strncasecmp(cmd->param[0].s, IMC_ROOM_PRIVATE, cmd->param[0].len)) {
372 /* With two parameters, the first parameter is room URI and
373 * the second parameter must be "private". */
379 LM_ERR("Invalid number of parameters %d\n", params);
383 if (build_imc_uri(&room, rs.s ? rs : dst->parsed.user, &dst->parsed) != 0)
387 if (ps.len == IMC_ROOM_PRIVATE_LEN && !strncasecmp(ps.s, IMC_ROOM_PRIVATE, ps.len)) {
388 flag_room |= IMC_ROOM_PRIV;
389 LM_DBG("Room with private flag on\n");
391 LM_ERR("Second argument to command 'create' must be string 'private'\n");
396 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
398 LM_DBG("Creating new room [%.*s]\n", STR_FMT(&room.uri));
400 rm = imc_add_room(&room.parsed.user, &room.parsed.host, flag_room);
402 LM_ERR("Failed to add new room\n");
405 LM_DBG("Added room [%.*s]\n", STR_FMT(&rm->uri));
407 flag_member |= IMC_MEMBER_OWNER;
408 /* adding the owner as the first member*/
409 member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
410 if (member == NULL) {
411 LM_ERR("failed to add owner [%.*s]\n", STR_FMT(&src->uri));
414 LM_DBG("Added [%.*s] as the first member in room [%.*s]\n",
415 STR_FMT(&member->uri), STR_FMT(&rm->uri));
417 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created);
421 LM_DBG("Room [%.*s] already exists\n", STR_FMT(&rm->uri));
423 if (imc_check_on_create) {
424 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists);
428 if (rm->flags & IMC_ROOM_PRIV) {
429 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists_priv);
433 LM_DBG("Checking if user [%.*s] is a member\n", STR_FMT(&src->uri));
434 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
437 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists_member);
441 member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
442 if (member == NULL) {
443 LM_ERR("Failed to add member [%.*s]\n", STR_FMT(&src->uri));
446 LM_DBG("Added [%.*s] as member to room [%.*s]\n", STR_FMT(&member->uri), STR_FMT(&rm->uri));
448 body.s = imc_body_buf;
449 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri)));
452 LM_ERR("Error while building response\n");
457 imc_room_broadcast(rm, build_headers(msg), &body);
459 if (body.len >= sizeof(imc_body_buf))
460 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
465 if (room.uri.s) pkg_free(room.uri.s);
466 if (rm != NULL) imc_release_room(rm);
471 int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd,
472 struct imc_uri *src, struct imc_uri *dst)
476 imc_member_p member = 0;
482 memset(&room, '\0', sizeof(room));
483 if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
486 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
487 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
488 LM_DBG("Room [%.*s] not found\n", STR_FMT(&room.uri));
490 if (!imc_create_on_join) {
491 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_not_found);
495 LM_DBG("Creating room [%.*s]\n", STR_FMT(&room.uri));
496 rm = imc_add_room(&room.parsed.user, &room.parsed.host, flag_room);
498 LM_ERR("Failed to add new room [%.*s]\n", STR_FMT(&room.uri));
501 LM_DBG("Created a new room [%.*s]\n", STR_FMT(&rm->uri));
502 flag_member |= IMC_MEMBER_OWNER;
503 member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
504 if (member == NULL) {
505 LM_ERR("Failed to add new member [%.*s]\n", STR_FMT(&src->uri));
508 /* send info message */
509 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created);
513 LM_DBG("Found room [%.*s]\n", STR_FMT(&rm->uri));
515 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
516 if (member && !(member->flags & IMC_MEMBER_DELETED)) {
517 LM_DBG("User [%.*s] is already in the room\n", STR_FMT(&member->uri));
518 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_already_joined);
522 body.s = imc_body_buf;
523 if (!(rm->flags & IMC_ROOM_PRIV)) {
524 LM_DBG("adding new member [%.*s]\n", STR_FMT(&src->uri));
525 member = imc_add_member(rm, &src->parsed.user, &src->parsed.host, flag_member);
526 if (member == NULL) {
527 LM_ERR("Failed to add new user [%.*s]\n", STR_FMT(&src->uri));
531 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(src->uri)));
533 LM_DBG("Attept to join private room [%.*s] by [%.*s]\n",
534 STR_FMT(&rm->uri), STR_FMT(&src->uri));
536 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_join_attempt_bcast.s, STR_FMT(format_uri(src->uri)));
537 imc_send_message(&rm->uri, &src->uri, build_headers(msg), &msg_join_attempt_ucast);
541 LM_ERR("Error while building response\n");
546 imc_room_broadcast(rm, build_headers(msg), &body);
548 if (body.len >= sizeof(imc_body_buf))
549 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
552 if (member != NULL && (member->flags & IMC_MEMBER_INVITED))
553 member->flags &= ~IMC_MEMBER_INVITED;
557 if (room.uri.s) pkg_free(room.uri.s);
558 if (rm != NULL) imc_release_room(rm);
563 int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd,
564 struct imc_uri *src, struct imc_uri *dst)
568 imc_member_p member = 0;
571 del_member_t *cback_param = NULL;
574 struct imc_uri user, room;
576 memset(&user, '\0', sizeof(user));
577 memset(&room, '\0', sizeof(room));
579 if (cmd->param[0].s == NULL) {
580 LM_INFO("Invite command with missing argument from [%.*s]\n", STR_FMT(&src->uri));
584 if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
587 if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
590 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
591 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
592 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
595 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
597 if (member == NULL) {
598 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
599 STR_FMT(&src->uri), STR_FMT(&room.uri));
603 if (!(member->flags & IMC_MEMBER_OWNER) &&
604 !(member->flags & IMC_MEMBER_ADMIN)) {
605 LM_ERR("User [%.*s] has no right to invite others!\n", STR_FMT(&member->uri));
609 member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
610 if (member != NULL) {
611 LM_ERR("User [%.*s] is already in room [%.*s]!\n", STR_FMT(&member->uri), STR_FMT(&rm->uri));
615 flag_member |= IMC_MEMBER_INVITED;
616 member = imc_add_member(rm, &user.parsed.user, &user.parsed.host, flag_member);
617 if (member == NULL) {
618 LM_ERR("Adding member [%.*s] failed\n", STR_FMT(&user.uri));
622 body.s = imc_body_buf;
623 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_invite.s, STR_FMT(format_uri(src->uri)),
624 STR_FMT(&imc_cmd_start_str), STR_FMT(&imc_cmd_start_str));
627 LM_ERR("Error while building response\n");
631 LM_DBG("to=[%.*s]\nfrom=[%.*s]\nbody=[%.*s]\n",
632 STR_FMT(&member->uri), STR_FMT(&rm->uri), STR_FMT(&body));
634 if (body.len >= sizeof(imc_body_buf))
635 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
637 if ((cback_param = (del_member_t*)shm_malloc(sizeof(del_member_t))) == NULL) {
638 LM_ERR("No shared memory left\n");
641 memset(cback_param, 0, sizeof(del_member_t));
642 cback_param->room_name = rm->name;
643 cback_param->room_domain = rm->domain;
644 cback_param->member_name = member->user;
645 cback_param->member_domain = member->domain;
646 cback_param->inv_uri = member->uri;
647 /*?!?! possible race with 'remove user' */
649 set_uac_req(&uac_r, &imc_msg_type, build_headers(msg), &body, 0, TMCB_LOCAL_COMPLETED,
650 imc_inv_callback, (void*)(cback_param));
651 result = tmb.t_request(&uac_r,
652 &member->uri, /* Request-URI */
653 &member->uri, /* To */
655 (outbound_proxy.s) ? &outbound_proxy : NULL/* outbound proxy*/
658 LM_ERR("Error in tm send request\n");
659 shm_free(cback_param);
665 if (user.uri.s != NULL) pkg_free(user.uri.s);
666 if (room.uri.s != NULL) pkg_free(room.uri.s);
667 if (rm != NULL) imc_release_room(rm);
672 int imc_handle_add(struct sip_msg* msg, imc_cmd_t *cmd,
673 struct imc_uri *src, struct imc_uri *dst)
677 imc_member_p member = 0;
679 struct imc_uri user, room;
681 memset(&user, '\0', sizeof(user));
682 memset(&room, '\0', sizeof(room));
684 if (cmd->param[0].s == NULL) {
685 LM_INFO("Add command with missing argument from [%.*s]\n", STR_FMT(&src->uri));
689 if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
692 if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
695 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
696 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
697 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
700 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
702 if (member == NULL) {
703 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
704 STR_FMT(&src->uri), STR_FMT(&room.uri));
708 if (!(member->flags & IMC_MEMBER_OWNER) &&
709 !(member->flags & IMC_MEMBER_ADMIN)) {
710 LM_ERR("User [%.*s] has no right to add others!\n", STR_FMT(&member->uri));
711 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_add_reject);
715 member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
716 if (member != NULL) {
717 LM_ERR("User [%.*s] is already in room [%.*s]!\n", STR_FMT(&member->uri), STR_FMT(&rm->uri));
721 member = imc_add_member(rm, &user.parsed.user, &user.parsed.host, 0);
722 if (member == NULL) {
723 LM_ERR("Adding member [%.*s] failed\n", STR_FMT(&user.uri));
727 body.s = imc_body_buf;
728 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri)));
731 LM_ERR("Error while building response\n");
736 imc_room_broadcast(rm, build_headers(msg), &body);
738 if (body.len >= sizeof(imc_body_buf))
739 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
744 if (user.uri.s != NULL) pkg_free(user.uri.s);
745 if (room.uri.s != NULL) pkg_free(room.uri.s);
746 if (rm != NULL) imc_release_room(rm);
751 int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd,
752 struct imc_uri *src, struct imc_uri *dst)
756 imc_member_p member = 0;
760 memset(&room, '\0', sizeof(room));
762 if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
765 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
766 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
767 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
771 /* if aready invited add as a member */
772 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
773 if (member == NULL || !(member->flags & IMC_MEMBER_INVITED)) {
774 LM_ERR("User [%.*s] not invited to the room!\n", STR_FMT(&src->uri));
778 member->flags &= ~IMC_MEMBER_INVITED;
780 body.s = imc_body_buf;
781 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(member->uri)));
784 LM_ERR("Error while building response\n");
789 imc_room_broadcast(rm, build_headers(msg), &body);
791 if (body.len >= sizeof(imc_body_buf))
792 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
796 if (room.uri.s != NULL) pkg_free(room.uri.s);
797 if (rm != NULL) imc_release_room(rm);
802 int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd,
803 struct imc_uri *src, struct imc_uri *dst)
807 imc_member_p member = 0;
809 struct imc_uri user, room;
811 memset(&user, '\0', sizeof(user));
812 memset(&room, '\0', sizeof(room));
814 if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
817 if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
820 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
821 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
822 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
826 /* verify if the user who sent the request is a member in the room
827 * and has the right to remove other users */
828 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
829 if (member == NULL) {
830 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
831 STR_FMT(&src->uri), STR_FMT(&rm->uri));
835 if (!(member->flags & IMC_MEMBER_OWNER) && !(member->flags & IMC_MEMBER_ADMIN)) {
836 LM_ERR("User [%.*s] has no right to remove from room [%.*s]!\n",
837 STR_FMT(&src->uri), STR_FMT(&rm->uri));
841 /* verify if the user that is to be removed is a member of the room */
842 member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
843 if (member == NULL) {
844 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
845 STR_FMT(&user.uri), STR_FMT(&rm->uri));
849 if (member->flags & IMC_MEMBER_OWNER) {
850 LM_ERR("User [%.*s] is owner of room [%.*s] and cannot be removed!\n",
851 STR_FMT(&member->uri), STR_FMT(&rm->uri));
855 LM_DBG("to: [%.*s]\nfrom: [%.*s]\nbody: [%.*s]\n",
856 STR_FMT(&member->uri) , STR_FMT(&rm->uri),
857 STR_FMT(&msg_user_removed));
858 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_user_removed);
860 member->flags |= IMC_MEMBER_DELETED;
861 imc_del_member(rm, &user.parsed.user, &user.parsed.host);
863 body.s = imc_body_buf;
864 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_left.s, STR_FMT(format_uri(member->uri)));
867 LM_ERR("Error while building response\n");
872 imc_room_broadcast(rm, build_headers(msg), &body);
874 if (body.len >= sizeof(imc_body_buf))
875 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
879 if (user.uri.s != NULL) pkg_free(user.uri.s);
880 if (room.uri.s != NULL) pkg_free(room.uri.s);
881 if (rm != NULL) imc_release_room(rm);
886 int imc_handle_reject(struct sip_msg* msg, imc_cmd_t *cmd,
887 struct imc_uri *src, struct imc_uri *dst)
891 imc_member_p member = 0;
894 memset(&room, '\0', sizeof(room));
895 if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
898 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
899 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
900 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
904 /* If the user is an invited member, delete it from the list */
905 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
906 if (member == NULL || !(member->flags & IMC_MEMBER_INVITED)) {
907 LM_ERR("User [%.*s] was not invited to room [%.*s]!\n",
908 STR_FMT(&src->uri), STR_FMT(&rm->uri));
913 body.s = imc_body_buf;
914 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_rejected.s, STR_FMT(format_uri(src->uri)));
916 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &body);
919 LM_DBG("User [%.*s] rejected invitation to room [%.*s]!\n",
920 STR_FMT(&src->uri), STR_FMT(&rm->uri));
922 imc_del_member(rm, &src->parsed.user, &src->parsed.host);
926 if (room.uri.s != NULL) pkg_free(room.uri.s);
927 if (rm != NULL) imc_release_room(rm);
932 int imc_handle_members(struct sip_msg* msg, imc_cmd_t *cmd,
933 struct imc_uri *src, struct imc_uri *dst)
937 imc_member_p member = 0;
938 imc_member_p imp = 0;
944 memset(&room, '\0', sizeof(room));
945 if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
948 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
949 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
950 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
954 /* verify if the user is a member of the room */
955 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
956 if (member == NULL) {
957 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
958 STR_FMT(&src->uri), STR_FMT(&rm->uri));
963 imc_body_buf[IMC_BUF_SIZE - 1] = '\0';
964 left = sizeof(imc_body_buf) - 1;
966 memcpy(p, MEMBERS, sizeof(MEMBERS) - 1);
967 p += sizeof(MEMBERS) - 1;
968 left -= sizeof(MEMBERS) - 1;
972 if ((imp->flags & IMC_MEMBER_INVITED) || (imp->flags & IMC_MEMBER_DELETED)
973 || (imp->flags & IMC_MEMBER_SKIP)) {
978 if (imp->flags & IMC_MEMBER_OWNER) {
979 if (left < 2) goto overrun;
982 } else if (imp->flags & IMC_MEMBER_ADMIN) {
983 if (left < 2) goto overrun;
988 name = format_uri(imp->uri);
989 if (left < name->len + 1) goto overrun;
990 strncpy(p, name->s, name->len);
994 if (left < 2) goto overrun;
1001 /* write over last '\n' */
1003 body.s = imc_body_buf;
1004 body.len = p - body.s;
1006 LM_DBG("members = '%.*s'\n", STR_FMT(&body));
1007 LM_ERR("Message-ID: '%.*s'\n", STR_FMT(get_callid(msg)));
1008 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &body);
1012 LM_ERR("Buffer too small for member list message\n");
1014 if (room.uri.s != NULL) pkg_free(room.uri.s);
1015 if (rm != NULL) imc_release_room(rm);
1020 int imc_handle_rooms(struct sip_msg* msg, imc_cmd_t *cmd,
1021 struct imc_uri *src, struct imc_uri *dst)
1030 left = sizeof(imc_body_buf);
1032 memcpy(p, ROOMS, sizeof(ROOMS) - 1);
1033 p += sizeof(ROOMS) - 1;
1034 left -= sizeof(ROOMS) - 1;
1036 for (i = 0; i < imc_hash_size; i++) {
1037 lock_get(&_imc_htable[i].lock);
1038 for (room = _imc_htable[i].rooms; room != NULL ; room = room->next) {
1039 if (room->flags & IMC_ROOM_DELETED) continue;
1041 name = format_uri(room->uri);
1042 if (left < name->len) {
1043 lock_release(&_imc_htable[i].lock);
1046 strncpy(p, name->s, name->len);
1051 lock_release(&_imc_htable[i].lock);
1057 lock_release(&_imc_htable[i].lock);
1060 /* write over last '\n' */
1062 body.s = imc_body_buf;
1063 body.len = p - body.s;
1065 LM_DBG("rooms = '%.*s'\n", STR_FMT(&body));
1066 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &body);
1070 LM_ERR("Buffer too small for member list message\n");
1075 int imc_handle_leave(struct sip_msg* msg, imc_cmd_t *cmd,
1076 struct imc_uri *src, struct imc_uri *dst)
1080 imc_member_p member = 0;
1082 struct imc_uri room;
1084 memset(&room, '\0', sizeof(room));
1085 if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
1088 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
1089 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
1090 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
1094 /* verify if the user is a member of the room */
1095 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
1096 if (member == NULL) {
1097 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
1098 STR_FMT(&src->uri), STR_FMT(&rm->uri));
1102 if (member->flags & IMC_MEMBER_OWNER) {
1103 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_leave_error);
1107 body.s = imc_body_buf;
1108 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_left.s, STR_FMT(format_uri(member->uri)));
1111 LM_ERR("Error while building response\n");
1116 imc_room_broadcast(rm, build_headers(msg), &body);
1118 if (body.len >= sizeof(imc_body_buf))
1119 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
1121 member->flags |= IMC_MEMBER_DELETED;
1122 imc_del_member(rm, &src->parsed.user, &src->parsed.host);
1127 if (room.uri.s != NULL) pkg_free(room.uri.s);
1128 if (rm != NULL) imc_release_room(rm);
1133 int imc_handle_destroy(struct sip_msg* msg, imc_cmd_t *cmd,
1134 struct imc_uri *src, struct imc_uri *dst)
1138 imc_member_p member = 0;
1139 struct imc_uri room;
1141 memset(&room, '\0', sizeof(room));
1142 if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
1145 rm = imc_get_room(&room.parsed.user, &room.parsed.host);
1146 if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
1147 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
1151 /* verify is the user is a member of the room*/
1152 member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
1153 if (member == NULL) {
1154 LM_ERR("User [%.*s] is not a member of room [%.*s]!\n",
1155 STR_FMT(&src->uri), STR_FMT(&rm->uri));
1159 if (!(member->flags & IMC_MEMBER_OWNER)) {
1160 LM_ERR("User [%.*s] is not owner of room [%.*s] and cannot destroy it!\n",
1161 STR_FMT(&src->uri), STR_FMT(&rm->uri));
1164 rm->flags |= IMC_ROOM_DELETED;
1166 /* braodcast message */
1167 imc_room_broadcast(rm, build_headers(msg), &msg_room_destroyed);
1169 imc_release_room(rm);
1172 LM_DBG("Deleting room [%.*s]\n", STR_FMT(&room.uri));
1173 imc_del_room(&room.parsed.user, &room.parsed.host);
1177 if (room.uri.s != NULL) pkg_free(room.uri.s);
1178 if (rm != NULL) imc_release_room(rm);
1183 int imc_handle_help(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
1188 body.s = IMC_HELP_MSG;
1189 body.len = IMC_HELP_MSG_LEN;
1191 LM_DBG("to: [%.*s] from: [%.*s]\n", STR_FMT(&src->uri), STR_FMT(&dst->uri));
1192 set_uac_req(&uac_r, &imc_msg_type, build_headers(msg), &body, 0, 0, 0, 0);
1193 tmb.t_request(&uac_r,
1194 NULL, /* Request-URI */
1196 &dst->uri, /* From */
1197 (outbound_proxy.s)?&outbound_proxy:NULL/* outbound proxy */
1203 int imc_handle_unknown(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
1208 body.s = imc_body_buf;
1209 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_invalid_command.s,
1210 STR_FMT(&cmd->name), STR_FMT(&imc_cmd_start_str));
1212 if (body.len < 0 || body.len >= sizeof(imc_body_buf)) {
1213 LM_ERR("Unable to print message\n");
1217 LM_DBG("to: [%.*s] from: [%.*s]\n", STR_FMT(&src->uri), STR_FMT(&dst->uri));
1218 set_uac_req(&uac_r, &imc_msg_type, build_headers(msg), &body, 0, 0, 0, 0);
1219 tmb.t_request(&uac_r,
1220 NULL, /* Request-URI */
1222 &dst->uri, /* From */
1223 (outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy */
1229 int imc_handle_message(struct sip_msg* msg, str *msgbody,
1230 struct imc_uri *src, struct imc_uri *dst)
1233 imc_room_p room = 0;
1234 imc_member_p member = 0;
1237 room = imc_get_room(&dst->parsed.user, &dst->parsed.host);
1238 if (room == NULL || (room->flags & IMC_ROOM_DELETED)) {
1239 LM_DBG("Room [%.*s] does not exist!\n", STR_FMT(&dst->uri));
1243 member = imc_get_member(room, &src->parsed.user, &src->parsed.host);
1244 if (member == NULL || (member->flags & IMC_MEMBER_INVITED)) {
1245 LM_ERR("User [%.*s] has no right to send messages to room [%.*s]!\n",
1246 STR_FMT(&src->uri), STR_FMT(&room->uri));
1250 LM_DBG("Broadcast to room [%.*s]\n", STR_FMT(&room->uri));
1252 user = format_uri(member->uri);
1254 body.s = imc_body_buf;
1255 body.len = snprintf(body.s, sizeof(imc_body_buf), "%.*s: %.*s", STR_FMT(user), STR_FMT(msgbody));
1258 LM_ERR("Error while printing message\n");
1262 if (body.len >= sizeof(imc_body_buf)) {
1263 LM_ERR("Buffer too small for message '%.*s'\n", STR_FMT(&body));
1267 member->flags |= IMC_MEMBER_SKIP;
1268 imc_room_broadcast(room, build_headers(msg), &body);
1269 member->flags &= ~IMC_MEMBER_SKIP;
1273 if (room != NULL) imc_release_room(room);
1278 int imc_room_broadcast(imc_room_p room, str *ctype, str *body)
1282 if (room == NULL || body == NULL)
1285 imp = room->members;
1287 LM_DBG("nr = %d\n", room->nr_of_members);
1290 LM_DBG("to uri = %.*s\n", STR_FMT(&imp->uri));
1291 if ((imp->flags & IMC_MEMBER_INVITED) || (imp->flags & IMC_MEMBER_DELETED)
1292 || (imp->flags & IMC_MEMBER_SKIP)) {
1297 /* to-do: callback to remove user if delivery fails */
1298 imc_send_message(&room->uri, &imp->uri, ctype, body);
1306 int imc_send_message(str *src, str *dst, str *headers, str *body)
1310 if (src == NULL || dst == NULL || body == NULL)
1313 /* to-do: callback to remove user if delivery fails */
1314 set_uac_req(&uac_r, &imc_msg_type, headers, body, 0, 0, 0, 0);
1315 tmb.t_request(&uac_r,
1316 NULL, /* Request-URI */
1319 (outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy */
1325 void imc_inv_callback(struct cell *t, int type, struct tmcb_params *ps)
1328 char from_uri_buf[256];
1329 char to_uri_buf[256];
1331 str from_uri_s, to_uri_s;
1332 imc_member_p member= NULL;
1333 imc_room_p room = NULL;
1336 if (ps->param == NULL || *ps->param == NULL ||
1337 (del_member_t*)(*ps->param) == NULL) {
1338 LM_DBG("member not received\n");
1342 LM_DBG("completed with status %d [member name domain:"
1343 "%p/%.*s/%.*s]\n",ps->code, ps->param,
1344 STR_FMT(&((del_member_t *)(*ps->param))->member_name),
1345 STR_FMT(&((del_member_t *)(*ps->param))->member_domain));
1346 if (ps->code < 300) {
1349 room = imc_get_room(&((del_member_t *)(*ps->param))->room_name,
1350 &((del_member_t *)(*ps->param))->room_domain);
1352 LM_ERR("The room does not exist!\n");
1355 /*verify if the user who sent the request is a member in the room
1356 * and has the right to remove other users */
1357 member = imc_get_member(room,
1358 &((del_member_t *)(*ps->param))->member_name,
1359 &((del_member_t *)(*ps->param))->member_domain);
1361 if( member == NULL) {
1362 LM_ERR("The user is not a member of the room!\n");
1365 imc_del_member(room,
1366 &((del_member_t *)(*ps->param))->member_name,
1367 &((del_member_t *)(*ps->param))->member_domain);
1372 body_final.s = body_buf;
1373 body_final.len = member->uri.len - 4 /* sip: part of URI */ + 20;
1374 memcpy(body_final.s, member->uri.s + 4, member->uri.len - 4);
1375 memcpy(body_final.s + member->uri.len - 4," is not registered. ", 21);
1381 from_uri_s.s = from_uri_buf;
1382 from_uri_s.len = room->uri.len;
1383 strncpy(from_uri_s.s, room->uri.s, room->uri.len);
1385 LM_DBG("sending message\n");
1387 to_uri_s.s = to_uri_buf;
1388 to_uri_s.len = ((del_member_t *)(*ps->param))->inv_uri.len;
1389 strncpy(to_uri_s.s, ((del_member_t *)(*ps->param))->inv_uri.s,
1390 ((del_member_t *)(*ps->param))->inv_uri.len);
1392 LM_DBG("to: %.*s\nfrom: %.*s\nbody: %.*s\n", STR_FMT(&to_uri_s),
1393 STR_FMT(&from_uri_s), STR_FMT(&body_final));
1394 set_uac_req(&uac_r, &imc_msg_type, &extra_hdrs, &body_final, 0, 0, 0, 0);
1395 tmb.t_request(&uac_r,
1396 NULL, /* Request-URI */
1398 &from_uri_s, /* From */
1399 (outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy*/
1403 if (room != NULL) imc_release_room(room);
1404 if ((del_member_t *)(*ps->param)) shm_free(*ps->param);