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