imc: reserve last char in global buffer for ending zero
[sip-router] / src / modules / imc / imc_cmd.c
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
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
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
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  */
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  */
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  */
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
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) params++;
353         if (cmd->param[1].s) params++;
354
355         switch(params) {
356         case 0:
357                 /* With no parameter, use To for the room uri and create a public room */
358                 break;
359
360         case 1:
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)) {
365                         ps = cmd->param[0];
366                 } else {
367                         rs = cmd->param[0];
368                 }
369                 break;
370
371         case 2:
372                 /* With two parameters, the first parameter is room URI and
373                  * the second parameter must be "private". */
374                 rs = cmd->param[0];
375                 ps = cmd->param[1];
376                 break;
377
378         default:
379                 LM_ERR("Invalid number of parameters %d\n", params);
380                 goto error;
381         }
382
383         if (build_imc_uri(&room, rs.s ? rs : dst->parsed.user, &dst->parsed) != 0)
384                 goto error;
385
386         if (ps.s) {
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");
390                 } else {
391                         LM_ERR("Second argument to command 'create' must be string 'private'\n");
392                         goto error;
393                 }
394         }
395
396         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
397         if (rm == NULL) {
398                 LM_DBG("Creating new room [%.*s]\n", STR_FMT(&room.uri));
399
400                 rm = imc_add_room(&room.parsed.user, &room.parsed.host, flag_room);
401                 if (rm == NULL) {
402                         LM_ERR("Failed to add new room\n");
403                         goto error;
404                 }
405                 LM_DBG("Added room [%.*s]\n", STR_FMT(&rm->uri));
406
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));
412                         goto error;
413                 }
414                 LM_DBG("Added [%.*s] as the first member in room [%.*s]\n",
415                            STR_FMT(&member->uri), STR_FMT(&rm->uri));
416
417                 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created);
418                 goto done;
419         }
420
421         LM_DBG("Room [%.*s] already exists\n", STR_FMT(&rm->uri));
422
423         if (imc_check_on_create) {
424                 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists);
425                 goto done;
426         }
427
428         if (rm->flags & IMC_ROOM_PRIV) {
429                 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists_priv);
430                 goto done;
431         }
432
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);
435
436         if (member) {
437                 imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_exists_member);
438                 goto done;
439         }
440
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));
444                 goto error;
445         }
446         LM_DBG("Added [%.*s] as member to room [%.*s]\n", STR_FMT(&member->uri), STR_FMT(&rm->uri));
447
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)));
450
451         if (body.len < 0) {
452                 LM_ERR("Error while building response\n");
453                 goto error;
454         }
455
456         if (body.len > 0)
457                 imc_room_broadcast(rm, build_headers(msg), &body);
458
459         if (body.len >= sizeof(imc_body_buf))
460                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
461
462 done:
463         rv = 0;
464 error:
465         if (room.uri.s) pkg_free(room.uri.s);
466         if (rm != NULL) imc_release_room(rm);
467         return rv;
468 }
469
470
471 int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd,
472                 struct imc_uri *src, struct imc_uri *dst)
473 {
474         int rv = -1;
475         imc_room_p rm = 0;
476         imc_member_p member = 0;
477         int flag_room = 0;
478         int flag_member = 0;
479         str body;
480         struct imc_uri room;
481
482         memset(&room, '\0', sizeof(room));
483         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
484                 goto error;
485
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));
489
490                 if (!imc_create_on_join) {
491                         imc_send_message(&dst->uri, &src->uri, build_headers(msg), &msg_room_not_found);
492                         goto done;
493                 }
494
495                 LM_DBG("Creating room [%.*s]\n", STR_FMT(&room.uri));
496                 rm = imc_add_room(&room.parsed.user, &room.parsed.host, flag_room);
497                 if (rm == NULL) {
498                         LM_ERR("Failed to add new room [%.*s]\n", STR_FMT(&room.uri));
499                         goto error;
500                 }
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));
506                         goto error;
507                 }
508                 /* send info message */
509                 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_room_created);
510                 goto done;
511         }
512
513         LM_DBG("Found room [%.*s]\n", STR_FMT(&rm->uri));
514
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);
519                 goto done;
520         }
521
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));
528                         goto error;
529                 }
530
531                 body.len = snprintf(body.s, sizeof(imc_body_buf), msg_user_joined.s, STR_FMT(format_uri(src->uri)));
532         } else {
533                 LM_DBG("Attept to join private room [%.*s] by [%.*s]\n",
534                         STR_FMT(&rm->uri), STR_FMT(&src->uri));
535
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);
538         }
539
540         if (body.len < 0) {
541                 LM_ERR("Error while building response\n");
542                 goto error;
543         }
544
545         if (body.len > 0)
546                 imc_room_broadcast(rm, build_headers(msg), &body);
547
548         if (body.len >= sizeof(imc_body_buf))
549                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
550
551 done:
552         if (member != NULL && (member->flags & IMC_MEMBER_INVITED))
553                 member->flags &= ~IMC_MEMBER_INVITED;
554
555         rv = 0;
556 error:
557         if (room.uri.s) pkg_free(room.uri.s);
558         if (rm != NULL) imc_release_room(rm);
559         return rv;
560 }
561
562
563 int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd,
564                 struct imc_uri *src, struct imc_uri *dst)
565 {
566         int rv = -1;
567         imc_room_p rm = 0;
568         imc_member_p member = 0;
569         int flag_member = 0;
570         str body;
571         del_member_t *cback_param = NULL;
572         int result;
573         uac_req_t uac_r;
574         struct imc_uri user, room;
575
576         memset(&user, '\0', sizeof(user));
577         memset(&room, '\0', sizeof(room));
578
579         if (cmd->param[0].s == NULL) {
580                 LM_INFO("Invite command with missing argument from [%.*s]\n", STR_FMT(&src->uri));
581                 goto error;
582         }
583
584         if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
585                 goto error;
586
587         if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
588                 goto error;
589
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));
593                 goto error;
594         }
595         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
596
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));
600                 goto error;
601         }
602
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));
606                 goto error;
607         }
608
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));
612                 goto error;
613         }
614
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));
619                 goto error;
620         }
621
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));
625
626         if (body.len < 0) {
627                 LM_ERR("Error while building response\n");
628                 goto error;
629         }
630
631         LM_DBG("to=[%.*s]\nfrom=[%.*s]\nbody=[%.*s]\n",
632                STR_FMT(&member->uri), STR_FMT(&rm->uri), STR_FMT(&body));
633
634         if (body.len >= sizeof(imc_body_buf))
635                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
636
637         if ((cback_param = (del_member_t*)shm_malloc(sizeof(del_member_t))) == NULL) {
638                 LM_ERR("No shared memory left\n");
639                 goto error;
640         }
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' */
648
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 */
654                 &rm->uri,                                                               /* From */
655                 (outbound_proxy.s) ? &outbound_proxy : NULL/* outbound proxy*/
656                 );
657         if (result < 0) {
658                 LM_ERR("Error in tm send request\n");
659                 shm_free(cback_param);
660                 goto error;
661         }
662
663         rv = 0;
664 error:
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);
668         return rv;
669 }
670
671
672 int imc_handle_add(struct sip_msg* msg, imc_cmd_t *cmd,
673                 struct imc_uri *src, struct imc_uri *dst)
674 {
675         int rv = -1;
676         imc_room_p rm = 0;
677         imc_member_p member = 0;
678         str body;
679         struct imc_uri user, room;
680
681         memset(&user, '\0', sizeof(user));
682         memset(&room, '\0', sizeof(room));
683
684         if (cmd->param[0].s == NULL) {
685                 LM_INFO("Add command with missing argument from [%.*s]\n", STR_FMT(&src->uri));
686                 goto error;
687         }
688
689         if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
690                 goto error;
691
692         if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
693                 goto error;
694
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));
698                 goto error;
699         }
700         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
701
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));
705                 goto error;
706         }
707
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);
712                 goto done;
713         }
714
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));
718                 goto error;
719         }
720
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));
724                 goto error;
725         }
726
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)));
729
730         if (body.len < 0) {
731                 LM_ERR("Error while building response\n");
732                 goto error;
733         }
734
735         if (body.len > 0)
736                 imc_room_broadcast(rm, build_headers(msg), &body);
737
738         if (body.len >= sizeof(imc_body_buf))
739                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
740
741 done:
742         rv = 0;
743 error:
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);
747         return rv;
748 }
749
750
751 int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd,
752                 struct imc_uri *src, struct imc_uri *dst)
753 {
754         int rv = -1;
755         imc_room_p rm = 0;
756         imc_member_p member = 0;
757         str body;
758         struct imc_uri room;
759
760         memset(&room, '\0', sizeof(room));
761
762         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
763                 goto error;
764
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));
768                 goto error;
769         }
770
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));
775                 goto error;
776         }
777
778         member->flags &= ~IMC_MEMBER_INVITED;
779
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)));
782
783         if (body.len < 0) {
784                 LM_ERR("Error while building response\n");
785                 goto error;
786         }
787
788         if (body.len > 0)
789                 imc_room_broadcast(rm, build_headers(msg), &body);
790
791         if (body.len >= sizeof(imc_body_buf))
792                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
793
794         rv = 0;
795 error:
796         if (room.uri.s != NULL) pkg_free(room.uri.s);
797         if (rm != NULL) imc_release_room(rm);
798         return rv;
799 }
800
801
802 int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd,
803                 struct imc_uri *src, struct imc_uri *dst)
804 {
805         int rv = -1;
806         imc_room_p rm = 0;
807         imc_member_p member = 0;
808         str body;
809         struct imc_uri user, room;
810
811         memset(&user, '\0', sizeof(user));
812         memset(&room, '\0', sizeof(room));
813
814         if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
815                 goto error;
816
817         if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
818                 goto error;
819
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));
823                 goto error;
824         }
825
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));
832                 goto error;
833         }
834
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));
838                 goto error;
839         }
840
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));
846                 goto error;
847         }
848
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));
852                 goto error;
853         }
854
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);
859
860         member->flags |= IMC_MEMBER_DELETED;
861         imc_del_member(rm, &user.parsed.user, &user.parsed.host);
862
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)));
865
866         if (body.len < 0) {
867                 LM_ERR("Error while building response\n");
868                 goto error;
869         }
870
871         if (body.len > 0)
872                 imc_room_broadcast(rm, build_headers(msg), &body);
873
874         if (body.len >= sizeof(imc_body_buf))
875                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
876
877         rv = 0;
878 error:
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);
882         return rv;
883 }
884
885
886 int imc_handle_reject(struct sip_msg* msg, imc_cmd_t *cmd,
887                 struct imc_uri *src, struct imc_uri *dst)
888 {
889         int rv = -1;
890         imc_room_p rm = 0;
891         imc_member_p member = 0;
892         struct imc_uri room;
893
894         memset(&room, '\0', sizeof(room));
895         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
896                 goto error;
897
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));
901                 goto error;
902         }
903
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));
909                 goto error;
910         }
911
912 #if 0
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)));
915         if (body.len > 0)
916             imc_send_message(&rm->uri, &member->uri, build_headers(msg), &body);
917 #endif
918
919         LM_DBG("User [%.*s] rejected invitation to room [%.*s]!\n",
920                         STR_FMT(&src->uri), STR_FMT(&rm->uri));
921
922         imc_del_member(rm, &src->parsed.user, &src->parsed.host);
923
924         rv = 0;
925 error:
926         if (room.uri.s != NULL) pkg_free(room.uri.s);
927         if (rm != NULL) imc_release_room(rm);
928         return rv;
929 }
930
931
932 int imc_handle_members(struct sip_msg* msg, imc_cmd_t *cmd,
933                 struct imc_uri *src, struct imc_uri *dst)
934 {
935         int rv = -1;
936         imc_room_p rm = 0;
937         imc_member_p member = 0;
938         imc_member_p imp = 0;
939         str body, *name;
940         char *p;
941         size_t left;
942         struct imc_uri room;
943
944         memset(&room, '\0', sizeof(room));
945         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
946                 goto error;
947
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));
951                 goto error;
952         }
953
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));
959                 goto error;
960         }
961
962         p = imc_body_buf;
963         imc_body_buf[IMC_BUF_SIZE - 1] = '\0';
964         left = sizeof(imc_body_buf) - 1;
965
966         memcpy(p, MEMBERS, sizeof(MEMBERS) - 1);
967         p += sizeof(MEMBERS) - 1;
968         left -= sizeof(MEMBERS) - 1;
969
970         imp = rm->members;
971         while (imp) {
972                 if ((imp->flags & IMC_MEMBER_INVITED) || (imp->flags & IMC_MEMBER_DELETED)
973                         || (imp->flags & IMC_MEMBER_SKIP)) {
974                         imp = imp->next;
975                         continue;
976                 }
977
978                 if (imp->flags & IMC_MEMBER_OWNER) {
979                         if (left < 2) goto overrun;
980                         *p++ = '*';
981                         left--;
982                 } else if (imp->flags & IMC_MEMBER_ADMIN) {
983                         if (left < 2) goto overrun;
984                         *p++ = '~';
985                         left--;
986                 }
987
988                 name = format_uri(imp->uri);
989                 if (left < name->len + 1) goto overrun;
990                 strncpy(p, name->s, name->len);
991                 p += name->len;
992                 left -= name->len;
993
994                 if (left < 2) goto overrun;
995                 *p++ = '\n';
996                 left--;
997
998                 imp = imp->next;
999         }
1000
1001         /* write over last '\n' */
1002         *(--p) = 0;
1003         body.s   = imc_body_buf;
1004         body.len = p - body.s;
1005
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);
1009
1010         rv = 0;
1011 overrun:
1012         LM_ERR("Buffer too small for member list message\n");
1013 error:
1014         if (room.uri.s != NULL) pkg_free(room.uri.s);
1015         if (rm != NULL) imc_release_room(rm);
1016         return rv;
1017 }
1018
1019
1020 int imc_handle_rooms(struct sip_msg* msg, imc_cmd_t *cmd,
1021                 struct imc_uri *src, struct imc_uri *dst)
1022 {
1023         int i, rv = -1;
1024         imc_room_p room;
1025         str body, *name;
1026         char *p;
1027         size_t left;
1028
1029         p = imc_body_buf;
1030         left = sizeof(imc_body_buf);
1031
1032         memcpy(p, ROOMS, sizeof(ROOMS) - 1);
1033         p += sizeof(ROOMS) - 1;
1034         left -= sizeof(ROOMS) - 1;
1035
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;
1040
1041                         name = format_uri(room->uri);
1042                         if (left < name->len) {
1043                                 lock_release(&_imc_htable[i].lock);
1044                                 goto error;
1045                         }
1046                         strncpy(p, name->s, name->len);
1047                         p += name->len;
1048                         left -= name->len;
1049
1050                         if (left < 1) {
1051                                 lock_release(&_imc_htable[i].lock);
1052                                 goto error;
1053                         }
1054                         *p++ = '\n';
1055                         left--;
1056                 }
1057                 lock_release(&_imc_htable[i].lock);
1058         }
1059
1060         /* write over last '\n' */
1061         *(--p) = 0;
1062         body.s   = imc_body_buf;
1063         body.len = p - body.s;
1064
1065         LM_DBG("rooms = '%.*s'\n", STR_FMT(&body));
1066         imc_send_message(&dst->uri, &src->uri, build_headers(msg), &body);
1067
1068         rv = 0;
1069 error:
1070         LM_ERR("Buffer too small for member list message\n");
1071         return rv;
1072 }
1073
1074
1075 int imc_handle_leave(struct sip_msg* msg, imc_cmd_t *cmd,
1076                 struct imc_uri *src, struct imc_uri *dst)
1077 {
1078         int rv = -1;
1079         imc_room_p rm = 0;
1080         imc_member_p member = 0;
1081         str body;
1082         struct imc_uri room;
1083
1084         memset(&room, '\0', sizeof(room));
1085         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
1086                 goto error;
1087
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));
1091                 goto error;
1092         }
1093
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));
1099                 goto error;
1100         }
1101
1102         if (member->flags & IMC_MEMBER_OWNER) {
1103                 imc_send_message(&rm->uri, &member->uri, build_headers(msg), &msg_leave_error);
1104         goto done;
1105     }
1106
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)));
1109
1110         if (body.len < 0) {
1111                 LM_ERR("Error while building response\n");
1112                 goto error;
1113         }
1114
1115         if (body.len > 0)
1116                 imc_room_broadcast(rm, build_headers(msg), &body);
1117
1118         if (body.len >= sizeof(imc_body_buf))
1119                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
1120
1121         member->flags |= IMC_MEMBER_DELETED;
1122         imc_del_member(rm, &src->parsed.user, &src->parsed.host);
1123
1124 done:
1125         rv = 0;
1126 error:
1127         if (room.uri.s != NULL) pkg_free(room.uri.s);
1128         if (rm != NULL) imc_release_room(rm);
1129         return rv;
1130 }
1131
1132
1133 int imc_handle_destroy(struct sip_msg* msg, imc_cmd_t *cmd,
1134                 struct imc_uri *src, struct imc_uri *dst)
1135 {
1136         int rv = -1;
1137         imc_room_p rm = 0;
1138         imc_member_p member = 0;
1139         struct imc_uri room;
1140
1141         memset(&room, '\0', sizeof(room));
1142         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
1143                 goto error;
1144
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));
1148                 goto error;
1149         }
1150
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));
1156                 goto error;
1157         }
1158
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));
1162                 goto error;
1163         }
1164         rm->flags |= IMC_ROOM_DELETED;
1165
1166         /* braodcast message */
1167         imc_room_broadcast(rm, build_headers(msg), &msg_room_destroyed);
1168
1169         imc_release_room(rm);
1170         rm = NULL;
1171
1172         LM_DBG("Deleting room [%.*s]\n", STR_FMT(&room.uri));
1173         imc_del_room(&room.parsed.user, &room.parsed.host);
1174
1175         rv = 0;
1176 error:
1177         if (room.uri.s != NULL) pkg_free(room.uri.s);
1178         if (rm != NULL) imc_release_room(rm);
1179         return rv;
1180 }
1181
1182
1183 int imc_handle_help(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
1184 {
1185         str body;
1186         uac_req_t uac_r;
1187
1188         body.s   = IMC_HELP_MSG;
1189         body.len = IMC_HELP_MSG_LEN;
1190
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 */
1195                                 &src->uri,                                                              /* To */
1196                                 &dst->uri,                                                              /* From */
1197                                 (outbound_proxy.s)?&outbound_proxy:NULL/* outbound proxy */
1198                                 );
1199         return 0;
1200 }
1201
1202
1203 int imc_handle_unknown(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
1204 {
1205         str body;
1206         uac_req_t uac_r;
1207
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));
1211
1212         if (body.len < 0 || body.len >= sizeof(imc_body_buf)) {
1213                 LM_ERR("Unable to print message\n");
1214                 return -1;
1215         }
1216
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 */
1221                                 &src->uri,                                                              /* To */
1222                                 &dst->uri,                                                              /* From */
1223                                 (outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy */
1224                         );
1225         return 0;
1226 }
1227
1228
1229 int imc_handle_message(struct sip_msg* msg, str *msgbody,
1230                 struct imc_uri *src, struct imc_uri *dst)
1231 {
1232         int rv = -1;
1233         imc_room_p room = 0;
1234         imc_member_p member = 0;
1235         str body, *user;
1236
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));
1240                 goto error;
1241         }
1242
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));
1247                 goto error;
1248         }
1249
1250         LM_DBG("Broadcast to room [%.*s]\n", STR_FMT(&room->uri));
1251
1252         user = format_uri(member->uri);
1253
1254         body.s = imc_body_buf;
1255         body.len = snprintf(body.s, sizeof(imc_body_buf), "%.*s: %.*s", STR_FMT(user), STR_FMT(msgbody));
1256
1257         if (body.len < 0) {
1258                 LM_ERR("Error while printing message\n");
1259                 goto error;
1260         }
1261
1262         if (body.len >= sizeof(imc_body_buf)) {
1263                 LM_ERR("Buffer too small for message '%.*s'\n", STR_FMT(&body));
1264                 goto error;
1265         }
1266
1267         member->flags |= IMC_MEMBER_SKIP;
1268         imc_room_broadcast(room, build_headers(msg), &body);
1269         member->flags &= ~IMC_MEMBER_SKIP;
1270
1271         rv = 0;
1272 error:
1273         if (room != NULL) imc_release_room(room);
1274         return rv;
1275 }
1276
1277
1278 int imc_room_broadcast(imc_room_p room, str *ctype, str *body)
1279 {
1280         imc_member_p imp;
1281
1282         if (room == NULL || body == NULL)
1283                 return -1;
1284
1285         imp = room->members;
1286
1287         LM_DBG("nr = %d\n", room->nr_of_members);
1288
1289         while(imp) {
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)) {
1293                         imp = imp->next;
1294                         continue;
1295                 }
1296
1297                 /* to-do: callback to remove user if delivery fails */
1298                 imc_send_message(&room->uri, &imp->uri, ctype, body);
1299
1300                 imp = imp->next;
1301         }
1302         return 0;
1303 }
1304
1305
1306 int imc_send_message(str *src, str *dst, str *headers, str *body)
1307 {
1308         uac_req_t uac_r;
1309
1310         if (src == NULL || dst == NULL || body == NULL)
1311                 return -1;
1312
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 */
1317                         dst,                                                                            /* To */
1318                         src,                                                                            /* From */
1319                         (outbound_proxy.s)?&outbound_proxy:NULL         /* outbound proxy */
1320                 );
1321         return 0;
1322 }
1323
1324
1325 void imc_inv_callback(struct cell *t, int type, struct tmcb_params *ps)
1326 {
1327         str body_final;
1328         char from_uri_buf[256];
1329         char to_uri_buf[256];
1330         char body_buf[256];
1331         str from_uri_s, to_uri_s;
1332         imc_member_p member= NULL;
1333         imc_room_p room = NULL;
1334         uac_req_t uac_r;
1335
1336         if (ps->param == NULL || *ps->param == NULL ||
1337                 (del_member_t*)(*ps->param) == NULL) {
1338                 LM_DBG("member not received\n");
1339                 return;
1340         }
1341
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) {
1347                 return;
1348         } else {
1349                 room = imc_get_room(&((del_member_t *)(*ps->param))->room_name,
1350                                                 &((del_member_t *)(*ps->param))->room_domain);
1351                 if (room ==NULL) {
1352                         LM_ERR("The room does not exist!\n");
1353                         goto error;
1354                 }
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);
1360
1361                 if( member == NULL) {
1362                         LM_ERR("The user is not a member of the room!\n");
1363                         goto error;
1364                 }
1365                 imc_del_member(room,
1366                                 &((del_member_t *)(*ps->param))->member_name,
1367                                 &((del_member_t *)(*ps->param))->member_domain);
1368                 goto build_inform;
1369         }
1370
1371 build_inform:
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);
1376
1377         goto send_message;
1378
1379 send_message:
1380
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);
1384
1385         LM_DBG("sending message\n");
1386
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);
1391
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 */
1397                                         &to_uri_s,                                                              /* To */
1398                                         &from_uri_s,                                                    /* From */
1399                                         (outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy*/
1400                                 );
1401
1402 error:
1403         if (room != NULL) imc_release_room(room);
1404         if ((del_member_t *)(*ps->param)) shm_free(*ps->param);
1405 }