imc: check arguments in #invite
[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 (cmd->param[0].s == NULL) {
516                 LM_INFO("Invite command with missing argument from [%.*s]\n", STR_FMT(&src->uri));
517                 goto error;
518         }
519
520         if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
521                 goto error;
522
523         if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
524                 goto error;
525
526         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
527         if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
528                 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
529                 goto error;
530         }
531         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
532
533         if (member == NULL) {
534                 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
535                         STR_FMT(&src->uri), STR_FMT(&room.uri));
536                 goto error;
537         }
538
539         if (!(member->flags & IMC_MEMBER_OWNER) &&
540                         !(member->flags & IMC_MEMBER_ADMIN)) {
541                 LM_ERR("User [%.*s] has no right to invite others!\n", STR_FMT(&member->uri));
542                 goto error;
543         }
544
545         member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
546         if (member != NULL) {
547                 LM_ERR("User [%.*s] is already in room [%.*s]!\n", STR_FMT(&member->uri), STR_FMT(&rm->uri));
548                 goto error;
549         }
550
551         flag_member |= IMC_MEMBER_INVITED;
552         member = imc_add_member(rm, &user.parsed.user, &user.parsed.host, flag_member);
553         if (member == NULL) {
554                 LM_ERR("Adding member [%.*s]\n", STR_FMT(&user.uri));
555                 goto error;
556         }
557
558         body.s = imc_body_buf;
559         body.len = snprintf(body.s, IMC_BUF_SIZE, msg_invite.s, STR_FMT(format_uri(src->uri)),
560                 STR_FMT(&imc_cmd_start_str), STR_FMT(&imc_cmd_start_str));
561
562         LM_DBG("to=[%.*s]\nfrom=[%.*s]\nbody=[%.*s]\n",
563                STR_FMT(&member->uri), STR_FMT(&rm->uri), STR_FMT(&body));
564
565         if (body.len >= IMC_BUF_SIZE)
566                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
567
568         if ((cback_param = (del_member_t*)shm_malloc(sizeof(del_member_t))) == NULL) {
569                 LM_ERR("No shared memory left\n");
570                 goto error;
571         }
572         memset(cback_param, 0, sizeof(del_member_t));
573         cback_param->room_name = rm->name;
574         cback_param->room_domain = rm->domain;
575         cback_param->member_name = member->user;
576         cback_param->member_domain = member->domain;
577         cback_param->inv_uri = member->uri;
578         /*?!?! possible race with 'remove user' */
579
580         set_uac_req(&uac_r, &imc_msg_type, &all_hdrs, &body, 0, TMCB_LOCAL_COMPLETED,
581                                 imc_inv_callback, (void*)(cback_param));
582         result = tmb.t_request(&uac_r,
583                 &member->uri,                                                   /* Request-URI */
584                 &member->uri,                                                   /* To */
585                 &rm->uri,                                                               /* From */
586                 (outbound_proxy.s) ? &outbound_proxy : NULL/* outbound proxy*/
587                 );
588         if (result < 0) {
589                 LM_ERR("Error in tm send request\n");
590                 shm_free(cback_param);
591                 goto error;
592         }
593
594         rv = 0;
595 error:
596         if (user.uri.s != NULL) pkg_free(user.uri.s);
597         if (room.uri.s != NULL) pkg_free(room.uri.s);
598         if (rm != NULL) imc_release_room(rm);
599         return rv;
600 }
601
602
603 int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd,
604                 struct imc_uri *src, struct imc_uri *dst)
605 {
606         int rv = -1;
607         imc_room_p rm = 0;
608         imc_member_p member = 0;
609         str body;
610         struct imc_uri room;
611
612         memset(&room, '\0', sizeof(room));
613
614         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
615                 goto error;
616
617         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
618         if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
619                 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
620                 goto error;
621         }
622
623         /* if aready invited add as a member */
624         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
625         if (member == NULL || !(member->flags & IMC_MEMBER_INVITED)) {
626                 LM_ERR("User [%.*s] not invited to the room!\n", STR_FMT(&src->uri));
627                 goto error;
628         }
629
630         member->flags &= ~IMC_MEMBER_INVITED;
631
632         body.s = imc_body_buf;
633         body.len = snprintf(body.s, IMC_BUF_SIZE, msg_user_joined.s, STR_FMT(format_uri(member->uri)));
634         if (body.len > 0)
635                 imc_room_broadcast(rm, &all_hdrs, &body);
636
637         if (body.len >= IMC_BUF_SIZE)
638                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
639
640         rv = 0;
641 error:
642         if (room.uri.s != NULL) pkg_free(room.uri.s);
643         if (rm != NULL) imc_release_room(rm);
644         return rv;
645 }
646
647
648 int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd,
649                 struct imc_uri *src, struct imc_uri *dst)
650 {
651         int rv = -1;
652         imc_room_p rm = 0;
653         imc_member_p member = 0;
654         str body;
655         struct imc_uri user, room;
656
657         memset(&user, '\0', sizeof(user));
658         memset(&room, '\0', sizeof(room));
659
660         if (build_imc_uri(&user, cmd->param[0], &dst->parsed))
661                 goto error;
662
663         if (build_imc_uri(&room, cmd->param[1].s ? cmd->param[1] : dst->parsed.user, &dst->parsed))
664                 goto error;
665
666         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
667         if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
668                 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
669                 goto error;
670         }
671
672         /* verify if the user who sent the request is a member in the room
673          * and has the right to remove other users */
674         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
675         if (member == NULL) {
676                 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
677                                 STR_FMT(&src->uri), STR_FMT(&rm->uri));
678                 goto error;
679         }
680
681         if (!(member->flags & IMC_MEMBER_OWNER) && !(member->flags & IMC_MEMBER_ADMIN)) {
682                 LM_ERR("User [%.*s] has no right to remove from room [%.*s]!\n",
683                            STR_FMT(&src->uri), STR_FMT(&rm->uri));
684                 goto error;
685         }
686
687         /* verify if the user that is to be removed is a member of the room */
688         member = imc_get_member(rm, &user.parsed.user, &user.parsed.host);
689         if (member == NULL) {
690                 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
691                                 STR_FMT(&user.uri), STR_FMT(&rm->uri));
692                 goto error;
693         }
694
695         if (member->flags & IMC_MEMBER_OWNER) {
696                 LM_ERR("User [%.*s] is owner of room [%.*s] and cannot be removed!\n",
697                            STR_FMT(&member->uri), STR_FMT(&rm->uri));
698                 goto error;
699         }
700
701         LM_DBG("to: [%.*s]\nfrom: [%.*s]\nbody: [%.*s]\n",
702                         STR_FMT(&member->uri) , STR_FMT(&rm->uri),
703                         STR_FMT(&msg_user_removed));
704         imc_send_message(&rm->uri, &member->uri, &all_hdrs, &msg_user_removed);
705
706         member->flags |= IMC_MEMBER_DELETED;
707         imc_del_member(rm, &user.parsed.user, &user.parsed.host);
708
709         body.s = imc_body_buf;
710         body.len = snprintf(body.s, IMC_BUF_SIZE, msg_user_left.s, STR_FMT(format_uri(member->uri)));
711         if (body.len > 0)
712                 imc_room_broadcast(rm, &all_hdrs, &body);
713
714         if (body.len >= IMC_BUF_SIZE)
715                 LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
716
717         rv = 0;
718 error:
719         if (user.uri.s != NULL) pkg_free(user.uri.s);
720         if (room.uri.s != NULL) pkg_free(room.uri.s);
721         if (rm != NULL) imc_release_room(rm);
722         return rv;
723 }
724
725
726 int imc_handle_reject(struct sip_msg* msg, imc_cmd_t *cmd,
727                 struct imc_uri *src, struct imc_uri *dst)
728 {
729         int rv = -1;
730         imc_room_p rm = 0;
731         imc_member_p member = 0;
732         struct imc_uri room;
733
734         memset(&room, '\0', sizeof(room));
735         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
736                 goto error;
737
738         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
739         if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
740                 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
741                 goto error;
742         }
743
744         /* If the user is an invited member, delete it from the list */
745         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
746         if (member == NULL || !(member->flags & IMC_MEMBER_INVITED)) {
747                 LM_ERR("User [%.*s] was not invited to room [%.*s]!\n",
748                                 STR_FMT(&src->uri), STR_FMT(&rm->uri));
749                 goto error;
750         }
751
752 #if 0
753         body.s = imc_body_buf;
754         body.len = snprintf(body.s, IMC_BUF_SIZE, msg_rejected.s, STR_FMT(format_uri(src->uri)));
755         if (body.len > 0)
756             imc_send_message(&rm->uri, &member->uri, &all_hdrs, &body);
757 #endif
758
759         LM_DBG("User [%.*s] rejected invitation to room [%.*s]!\n",
760                         STR_FMT(&src->uri), STR_FMT(&rm->uri));
761
762         imc_del_member(rm, &src->parsed.user, &src->parsed.host);
763
764         rv = 0;
765 error:
766         if (room.uri.s != NULL) pkg_free(room.uri.s);
767         if (rm != NULL) imc_release_room(rm);
768         return rv;
769 }
770
771
772 int imc_handle_members(struct sip_msg* msg, imc_cmd_t *cmd,
773                 struct imc_uri *src, struct imc_uri *dst)
774 {
775         int rv = -1;
776         imc_room_p rm = 0;
777         imc_member_p member = 0;
778         imc_member_p imp = 0;
779         str body, *name;
780         char *p;
781         size_t left;
782         struct imc_uri room;
783
784         memset(&room, '\0', sizeof(room));
785         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
786                 goto error;
787
788         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
789         if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
790                 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
791                 goto error;
792         }
793
794         /* verify if the user is a member of the room */
795         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
796         if (member == NULL) {
797                 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
798                                 STR_FMT(&src->uri), STR_FMT(&rm->uri));
799                 goto error;
800         }
801
802         p = imc_body_buf;
803         left = IMC_BUF_SIZE;
804
805         memcpy(p, "Members:\n", 9);
806         p += 9;
807         left -= 9;
808
809         imp = rm->members;
810         while (imp) {
811                 if ((imp->flags & IMC_MEMBER_INVITED) || (imp->flags & IMC_MEMBER_DELETED)
812                         || (imp->flags & IMC_MEMBER_SKIP)) {
813                         imp = imp->next;
814                         continue;
815                 }
816
817                 if (imp->flags & IMC_MEMBER_OWNER) {
818                         if (left < 1) goto overrun;
819                         *p++ = '*';
820                         left--;
821                 } else if (imp->flags & IMC_MEMBER_ADMIN) {
822                         if (left < 1) goto overrun;
823                         *p++ = '~';
824                         left--;
825                 }
826
827                 name = format_uri(imp->uri);
828                 if (left < name->len) goto overrun;
829                 strncpy(p, name->s, name->len);
830                 p += name->len;
831                 left -= name->len;
832
833                 if (left < 1) goto overrun;
834                 *p++ = '\n';
835                 left--;
836
837                 imp = imp->next;
838         }
839
840         /* write over last '\n' */
841         *(--p) = 0;
842         body.s   = imc_body_buf;
843         body.len = p - body.s;
844
845         LM_DBG("members = '%.*s'\n", STR_FMT(&body));
846         imc_send_message(&rm->uri, &member->uri, &all_hdrs, &body);
847
848         rv = 0;
849 overrun:
850         LM_ERR("Buffer too small for member list message\n");
851 error:
852         if (room.uri.s != NULL) pkg_free(room.uri.s);
853         if (rm != NULL) imc_release_room(rm);
854         return rv;
855 }
856
857
858 int imc_handle_leave(struct sip_msg* msg, imc_cmd_t *cmd,
859                 struct imc_uri *src, struct imc_uri *dst)
860 {
861         int rv = -1;
862         imc_room_p rm = 0;
863         imc_member_p member = 0;
864         str body;
865         struct imc_uri room;
866
867         memset(&room, '\0', sizeof(room));
868         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
869                 goto error;
870
871         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
872         if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
873                 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
874                 goto error;
875         }
876
877         /* verify if the user is a member of the room */
878         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
879         if (member == NULL) {
880                 LM_ERR("User [%.*s] is not member of room [%.*s]!\n",
881                                 STR_FMT(&src->uri), STR_FMT(&rm->uri));
882                 goto error;
883         }
884
885         if (member->flags & IMC_MEMBER_OWNER) {
886                 /*If the user is the owner of the room, the room is destroyed */
887                 rm->flags |= IMC_ROOM_DELETED;
888                 imc_room_broadcast(rm, &all_hdrs, &msg_room_destroyed);
889
890                 imc_release_room(rm);
891                 rm = NULL;
892
893                 imc_del_room(&room.parsed.user, &room.parsed.host);
894         } else {
895                 body.s = imc_body_buf;
896                 body.len = snprintf(body.s, IMC_BUF_SIZE, msg_user_left.s, STR_FMT(format_uri(member->uri)));
897                 if (body.len > 0)
898                         imc_room_broadcast(rm, &all_hdrs, &body);
899                 if (body.len >= IMC_BUF_SIZE)
900                         LM_ERR("Truncated message '%.*s'\n", STR_FMT(&body));
901
902                 member->flags |= IMC_MEMBER_DELETED;
903                 imc_del_member(rm, &src->parsed.user, &src->parsed.host);
904         }
905
906         rv = 0;
907 error:
908         if (room.uri.s != NULL) pkg_free(room.uri.s);
909         if (rm != NULL) imc_release_room(rm);
910         return rv;
911 }
912
913
914 int imc_handle_destroy(struct sip_msg* msg, imc_cmd_t *cmd,
915                 struct imc_uri *src, struct imc_uri *dst)
916 {
917         int rv = -1;
918         imc_room_p rm = 0;
919         imc_member_p member = 0;
920         struct imc_uri room;
921
922         memset(&room, '\0', sizeof(room));
923         if (build_imc_uri(&room, cmd->param[0].s ? cmd->param[0] : dst->parsed.user, &dst->parsed))
924                 goto error;
925
926         rm = imc_get_room(&room.parsed.user, &room.parsed.host);
927         if (rm == NULL || (rm->flags & IMC_ROOM_DELETED)) {
928                 LM_ERR("Room [%.*s] does not exist!\n", STR_FMT(&room.uri));
929                 goto error;
930         }
931
932         /* verify is the user is a member of the room*/
933         member = imc_get_member(rm, &src->parsed.user, &src->parsed.host);
934         if (member == NULL) {
935                 LM_ERR("User [%.*s] is not a member of room [%.*s]!\n",
936                                 STR_FMT(&src->uri), STR_FMT(&rm->uri));
937                 goto error;
938         }
939
940         if (!(member->flags & IMC_MEMBER_OWNER)) {
941                 LM_ERR("User [%.*s] is not owner of room [%.*s] and cannot destroy it!\n",
942                            STR_FMT(&src->uri), STR_FMT(&rm->uri));
943                 goto error;
944         }
945         rm->flags |= IMC_ROOM_DELETED;
946
947         /* braodcast message */
948         imc_room_broadcast(rm, &all_hdrs, &msg_room_destroyed);
949
950         imc_release_room(rm);
951         rm = NULL;
952
953         LM_DBG("Deleting room [%.*s]\n", STR_FMT(&room.uri));
954         imc_del_room(&room.parsed.user, &room.parsed.host);
955
956         rv = 0;
957 error:
958         if (room.uri.s != NULL) pkg_free(room.uri.s);
959         if (rm != NULL) imc_release_room(rm);
960         return rv;
961 }
962
963
964 int imc_handle_help(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
965 {
966         str body;
967         uac_req_t uac_r;
968
969         body.s   = IMC_HELP_MSG;
970         body.len = IMC_HELP_MSG_LEN;
971
972         LM_DBG("to: [%.*s] from: [%.*s]\n", STR_FMT(&src->uri), STR_FMT(&dst->uri));
973         set_uac_req(&uac_r, &imc_msg_type, &all_hdrs, &body, 0, 0, 0, 0);
974         tmb.t_request(&uac_r,
975                                 NULL,                                                                   /* Request-URI */
976                                 &src->uri,                                                              /* To */
977                                 &dst->uri,                                                              /* From */
978                                 (outbound_proxy.s)?&outbound_proxy:NULL/* outbound proxy */
979                                 );
980         return 0;
981 }
982
983
984 int imc_handle_unknown(struct sip_msg* msg, imc_cmd_t *cmd, struct imc_uri *src, struct imc_uri *dst)
985 {
986         str body;
987         uac_req_t uac_r;
988
989         body.s   = imc_body_buf;
990         body.len = snprintf(body.s, IMC_BUF_SIZE, msg_invalid_command.s,
991                 STR_FMT(&cmd->name), STR_FMT(&imc_cmd_start_str));
992
993         if (body.len < 0 || body.len >= IMC_BUF_SIZE) {
994                 LM_ERR("Unable to print message\n");
995                 return -1;
996         }
997
998         LM_DBG("to: [%.*s] from: [%.*s]\n", STR_FMT(&src->uri), STR_FMT(&dst->uri));
999         set_uac_req(&uac_r, &imc_msg_type, &all_hdrs, &body, 0, 0, 0, 0);
1000         tmb.t_request(&uac_r,
1001                                 NULL,                                                                   /* Request-URI */
1002                                 &src->uri,                                                              /* To */
1003                                 &dst->uri,                                                              /* From */
1004                                 (outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy */
1005                         );
1006         return 0;
1007 }
1008
1009
1010 int imc_handle_message(struct sip_msg* msg, str *msgbody,
1011                 struct imc_uri *src, struct imc_uri *dst)
1012 {
1013         int rv = -1;
1014         imc_room_p room = 0;
1015         imc_member_p member = 0;
1016         str body, *user;
1017
1018         room = imc_get_room(&dst->parsed.user, &dst->parsed.host);
1019         if (room == NULL || (room->flags & IMC_ROOM_DELETED)) {
1020                 LM_DBG("Room [%.*s] does not exist!\n", STR_FMT(&dst->uri));
1021                 goto error;
1022         }
1023
1024         member = imc_get_member(room, &src->parsed.user, &src->parsed.host);
1025         if (member == NULL || (member->flags & IMC_MEMBER_INVITED)) {
1026                 LM_ERR("User [%.*s] has no right to send messages to room [%.*s]!\n",
1027                                 STR_FMT(&src->uri), STR_FMT(&room->uri));
1028                 goto error;
1029         }
1030
1031         LM_DBG("Broadcast to room [%.*s]\n", STR_FMT(&room->uri));
1032
1033         user = format_uri(member->uri);
1034
1035         body.s = imc_body_buf;
1036         body.len = snprintf(body.s, IMC_BUF_SIZE, "%.*s: %.*s", STR_FMT(user), STR_FMT(msgbody));
1037         if (body.len >= IMC_BUF_SIZE) {
1038                 LM_ERR("Buffer too small for message '%.*s'\n", STR_FMT(&body));
1039                 goto error;
1040         }
1041
1042         member->flags |= IMC_MEMBER_SKIP;
1043         imc_room_broadcast(room, &all_hdrs, &body);
1044         member->flags &= ~IMC_MEMBER_SKIP;
1045
1046         rv = 0;
1047 error:
1048         if (room != NULL) imc_release_room(room);
1049         return rv;
1050 }
1051
1052
1053 int imc_room_broadcast(imc_room_p room, str *ctype, str *body)
1054 {
1055         imc_member_p imp;
1056
1057         if (room == NULL || body == NULL)
1058                 return -1;
1059
1060         imp = room->members;
1061
1062         LM_DBG("nr = %d\n", room->nr_of_members);
1063
1064         while(imp) {
1065                 LM_DBG("to uri = %.*s\n", STR_FMT(&imp->uri));
1066                 if ((imp->flags & IMC_MEMBER_INVITED) || (imp->flags & IMC_MEMBER_DELETED)
1067                                 || (imp->flags & IMC_MEMBER_SKIP)) {
1068                         imp = imp->next;
1069                         continue;
1070                 }
1071
1072                 /* to-do: callback to remove user if delivery fails */
1073                 imc_send_message(&room->uri, &imp->uri, ctype, body);
1074
1075                 imp = imp->next;
1076         }
1077         return 0;
1078 }
1079
1080
1081 int imc_send_message(str *src, str *dst, str *headers, str *body)
1082 {
1083         uac_req_t uac_r;
1084
1085         if (src == NULL || dst == NULL || body == NULL)
1086                 return -1;
1087
1088         /* to-do: callback to remove user if delivery fails */
1089         set_uac_req(&uac_r, &imc_msg_type, headers, body, 0, 0, 0, 0);
1090         tmb.t_request(&uac_r,
1091                         NULL,                                                                           /* Request-URI */
1092                         dst,                                                                            /* To */
1093                         src,                                                                            /* From */
1094                         (outbound_proxy.s)?&outbound_proxy:NULL         /* outbound proxy */
1095                 );
1096         return 0;
1097 }
1098
1099
1100 void imc_inv_callback(struct cell *t, int type, struct tmcb_params *ps)
1101 {
1102         str body_final;
1103         char from_uri_buf[256];
1104         char to_uri_buf[256];
1105         char body_buf[256];
1106         str from_uri_s, to_uri_s;
1107         imc_member_p member= NULL;
1108         imc_room_p room = NULL;
1109         uac_req_t uac_r;
1110
1111         if (ps->param == NULL || *ps->param == NULL ||
1112                 (del_member_t*)(*ps->param) == NULL) {
1113                 LM_DBG("member not received\n");
1114                 return;
1115         }
1116
1117         LM_DBG("completed with status %d [member name domain:"
1118                         "%p/%.*s/%.*s]\n",ps->code, ps->param,
1119                         STR_FMT(&((del_member_t *)(*ps->param))->member_name),
1120                         STR_FMT(&((del_member_t *)(*ps->param))->member_domain));
1121         if (ps->code < 300) {
1122                 return;
1123         } else {
1124                 room = imc_get_room(&((del_member_t *)(*ps->param))->room_name,
1125                                                 &((del_member_t *)(*ps->param))->room_domain);
1126                 if (room ==NULL) {
1127                         LM_ERR("The room does not exist!\n");
1128                         goto error;
1129                 }
1130                 /*verify if the user who sent the request is a member in the room
1131                  * and has the right to remove other users */
1132                 member = imc_get_member(room,
1133                                 &((del_member_t *)(*ps->param))->member_name,
1134                                 &((del_member_t *)(*ps->param))->member_domain);
1135
1136                 if( member == NULL) {
1137                         LM_ERR("The user is not a member of the room!\n");
1138                         goto error;
1139                 }
1140                 imc_del_member(room,
1141                                 &((del_member_t *)(*ps->param))->member_name,
1142                                 &((del_member_t *)(*ps->param))->member_domain);
1143                 goto build_inform;
1144         }
1145
1146 build_inform:
1147         body_final.s = body_buf;
1148         body_final.len = member->uri.len - 4 /* sip: part of URI */ + 20;
1149         memcpy(body_final.s, member->uri.s + 4, member->uri.len - 4);
1150         memcpy(body_final.s + member->uri.len - 4," is not registered.  ", 21);
1151
1152         goto send_message;
1153
1154 send_message:
1155
1156         from_uri_s.s = from_uri_buf;
1157         from_uri_s.len = room->uri.len;
1158         strncpy(from_uri_s.s, room->uri.s, room->uri.len);
1159
1160         LM_DBG("sending message\n");
1161
1162         to_uri_s.s = to_uri_buf;
1163         to_uri_s.len = ((del_member_t *)(*ps->param))->inv_uri.len;
1164         strncpy(to_uri_s.s, ((del_member_t *)(*ps->param))->inv_uri.s,
1165                         ((del_member_t *)(*ps->param))->inv_uri.len);
1166
1167         LM_DBG("to: %.*s\nfrom: %.*s\nbody: %.*s\n", STR_FMT(&to_uri_s),
1168                         STR_FMT(&from_uri_s), STR_FMT(&body_final));
1169         set_uac_req(&uac_r, &imc_msg_type, &extra_hdrs, &body_final, 0, 0, 0, 0);
1170         tmb.t_request(&uac_r,
1171                                         NULL,                                                                   /* Request-URI */
1172                                         &to_uri_s,                                                              /* To */
1173                                         &from_uri_s,                                                    /* From */
1174                                         (outbound_proxy.s)?&outbound_proxy:NULL /* outbound proxy*/
1175                                 );
1176
1177 error:
1178         if (room != NULL) imc_release_room(room);
1179         if ((del_member_t *)(*ps->param)) shm_free(*ps->param);
1180 }