sdpops: use PV cache to lookup the parameter
[sip-router] / modules / sdpops / sdpops_mod.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2011 Daniel-Constantin Mierla (asipto.com)
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 #include "../../sr_module.h"
30 #include "../../dprint.h"
31 #include "../../mod_fix.h"
32 #include "../../pvar.h"
33 #include "../../parser/sdp/sdp.h"
34 #include "../../trim.h"
35 #include "../../data_lump.h"
36
37 #include "api.h"
38 #include "sdpops_data.h"
39
40 MODULE_VERSION
41
42 static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char *bar);
43 static int w_sdp_remove_codecs_by_name(sip_msg_t* msg, char* codecs, char *bar);
44 static int w_sdp_keep_codecs_by_id(sip_msg_t* msg, char* codecs, char *bar);
45 static int w_sdp_keep_codecs_by_name(sip_msg_t* msg, char* codecs, char *bar);
46 static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar);
47 static int w_sdp_with_codecs_by_id(sip_msg_t* msg, char* codec, char *bar);
48 static int w_sdp_with_codecs_by_name(sip_msg_t* msg, char* codec, char *bar);
49 static int w_sdp_remove_media(sip_msg_t* msg, char* media, char *bar);
50 static int w_sdp_print(sip_msg_t* msg, char* level, char *bar);
51 static int w_get_sdp(sip_msg_t* msg, char *bar);
52
53 static int mod_init(void);
54
55 static cmd_export_t cmds[] = {
56         {"sdp_remove_codecs_by_id",    (cmd_function)w_sdp_remove_codecs_by_id,
57                 1, fixup_spve_null,  0, ANY_ROUTE},
58         {"sdp_remove_codecs_by_name",  (cmd_function)w_sdp_remove_codecs_by_name,
59                 1, fixup_spve_null,  0, ANY_ROUTE},
60         {"sdp_keep_codecs_by_id",    (cmd_function)w_sdp_keep_codecs_by_id,
61                 1, fixup_spve_null,  0, ANY_ROUTE},
62         {"sdp_keep_codecs_by_id",    (cmd_function)w_sdp_keep_codecs_by_id,
63                 2, fixup_spve_spve,  0, ANY_ROUTE},
64         {"sdp_keep_codecs_by_name",  (cmd_function)w_sdp_keep_codecs_by_name,
65                 1, fixup_spve_null,  0, ANY_ROUTE},
66         {"sdp_keep_codecs_by_name",  (cmd_function)w_sdp_keep_codecs_by_name,
67                 2, fixup_spve_spve,  0, ANY_ROUTE},
68         {"sdp_with_media",             (cmd_function)w_sdp_with_media,
69                 1, fixup_spve_null,  0, ANY_ROUTE},
70         {"sdp_remove_media",             (cmd_function)w_sdp_remove_media,
71                 1, fixup_spve_null,  0, ANY_ROUTE},
72         {"sdp_with_codecs_by_id",      (cmd_function)w_sdp_with_codecs_by_id,
73                 1, fixup_spve_null,  0, ANY_ROUTE},
74         {"sdp_with_codecs_by_name",    (cmd_function)w_sdp_with_codecs_by_name,
75                 1, fixup_spve_null,  0, ANY_ROUTE},
76         {"sdp_print",                  (cmd_function)w_sdp_print,
77                 1, fixup_igp_null,  0, ANY_ROUTE},
78         {"sdp_get",                  (cmd_function)w_get_sdp,
79                 1, 0,  0, ANY_ROUTE},
80         {"bind_sdpops",                (cmd_function)bind_sdpops,
81                 1, 0, 0, 0},
82         {0, 0, 0, 0, 0, 0}
83 };
84
85 static pv_export_t mod_pvs[] = {
86 #if 0
87         {{"sdp", (sizeof("sdp")-1)}, /* */
88                 PVT_OTHER, pv_get_sdp, 0,
89                 0, 0, 0, 0},
90 #endif
91
92         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
93 };
94
95 static param_export_t params[] = {
96         {0, 0, 0}
97 };
98
99 /** module exports */
100 struct module_exports exports= {
101         "sdpops",
102         DEFAULT_DLFLAGS, /* dlopen flags */
103         cmds,
104         params,
105         0,          /* exported statistics */
106         0  ,        /* exported MI functions */
107         mod_pvs,    /* exported pseudo-variables */
108         0,          /* extra processes */
109         mod_init,   /* module initialization function */
110         0,
111         0,
112         0           /* per-child init function */
113 };
114
115 /** 
116  * 
117  */
118 static int mod_init(void)
119 {
120         LM_DBG("sdpops module loaded\n");
121         return 0;
122 }
123
124
125 /**
126  *
127  */
128 int sdp_locate_line(sip_msg_t* msg, char *pos, str *aline)
129 {
130         char *p;
131         p = pos;
132         while(*p!='\n') p--;
133         aline->s = p + 1;
134         p = pos;
135         while(*p!='\n') p++;
136         aline->len = p - aline->s + 1;
137         return 0;
138 }
139
140 /**
141  *
142  */
143 int sdp_remove_str_codec_id_attrs(sip_msg_t* msg,
144                 sdp_stream_cell_t* sdp_stream, str *rm_codec)
145 {
146         str aline = {0, 0};
147         sdp_payload_attr_t *payload;
148         struct lump *anchor;
149
150         payload = sdp_stream->payload_attr;
151         while (payload) {
152                 LM_DBG("a= ... for codec %.*s/%.*s\n",
153                         payload->rtp_payload.len, payload->rtp_payload.s,
154                         payload->rtp_enc.len, payload->rtp_enc.s);
155                 if(rm_codec->len==payload->rtp_payload.len
156                                 && strncmp(payload->rtp_payload.s, rm_codec->s,
157                                         rm_codec->len)==0) {
158                         if(payload->rtp_enc.s!=NULL) {
159                                 if(sdp_locate_line(msg, payload->rtp_enc.s, &aline)==0)
160                                 {
161                                         LM_DBG("removing line: %.*s", aline.len, aline.s);
162                                         anchor = del_lump(msg, aline.s - msg->buf,
163                                                         aline.len, 0);
164                                         if (anchor == NULL) {
165                                                 LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
166                                                         rm_codec->len, rm_codec->s,
167                                                         aline.len, aline.s);
168                                                 return -1;
169                                         }
170                                 }
171                         }
172                         if(payload->fmtp_string.s!=NULL) {
173                                 if(sdp_locate_line(msg, payload->fmtp_string.s, &aline)==0)
174                                 {
175                                         LM_DBG("removing line: %.*s\n", aline.len, aline.s);
176                                         anchor = del_lump(msg, aline.s - msg->buf,
177                                                         aline.len, 0);
178                                         if (anchor == NULL) {
179                                                 LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
180                                                         rm_codec->len, rm_codec->s,
181                                                         aline.len, aline.s);
182                                                 return -1;
183                                         }
184                                 }
185                         }
186                 }
187                 payload=payload->next;
188         }
189
190         return 0;
191 }
192
193 /**
194  *
195  */
196 int sdp_codec_in_str(str *allcodecs, str* codec, char delim)
197 {
198         int i;
199         int cmp;
200
201         if(allcodecs==NULL || codec==NULL
202                         || allcodecs->len<=0 || codec->len<=0)
203                 return 0;
204
205         cmp = 1;
206         for(i=0; i<allcodecs->len; i++) {
207                 if(cmp==1) {
208                         if(codec->len <= allcodecs->len-i) {
209                                 if(strncmp(&allcodecs->s[i], codec->s, codec->len)==0) {
210                                         if(&allcodecs->s[i+codec->len]
211                                                                         == &allcodecs->s[allcodecs->len]
212                                                         || allcodecs->s[i+codec->len] == delim) {
213                                                 /* match */
214                                                 return 1;
215                                         }
216                                 }
217                         }
218                 }
219                 if(allcodecs->s[i]==delim)
220                         cmp = 1;
221                 else
222                         cmp = 0;
223         }
224
225         return 0;
226 }
227
228
229 /**
230  *
231  */
232 int sdp_remove_str_codec_id(sip_msg_t* msg, str *allcodecs, str* rmcodec)
233 {
234         int i;
235         int cmp;
236         struct lump *anchor;
237
238         if(msg==NULL || allcodecs==NULL || rmcodec==NULL
239                         || allcodecs->len<=0 || rmcodec->len<=0)
240                 return -1;
241
242         cmp = 1;
243         for(i=0; i<allcodecs->len; i++) {
244                 if(cmp==1) {
245                         if(rmcodec->len <= allcodecs->len-i) {
246                                 if(strncmp(&allcodecs->s[i], rmcodec->s, rmcodec->len)==0) {
247                                         if(&allcodecs->s[i+rmcodec->len]
248                                                                         == &allcodecs->s[allcodecs->len]
249                                                         || allcodecs->s[i+rmcodec->len] == ' ') {
250                                                 /* match - remove also the space before codec id */
251                                                 LM_DBG("found codec [%.*s] inside [%.*s]\n",
252                                                                         rmcodec->len, rmcodec->s,
253                                                                         allcodecs->len, allcodecs->s);
254                                                 anchor = del_lump(msg, &allcodecs->s[i-1] - msg->buf,
255                                                                 rmcodec->len+1, 0);
256                                                 if (anchor == NULL) {
257                                                         LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
258                                                                         rmcodec->len, rmcodec->s,
259                                                                         allcodecs->len, allcodecs->s);
260                                                         return -1;
261                                                 }
262                                                 return 0;
263                                         }
264                                 }
265                         }
266                 }
267                 if(allcodecs->s[i]==' ')
268                         cmp = 1;
269                 else
270                         cmp = 0;
271         }
272
273         return 0;
274 }
275
276 /**
277  *
278  */
279 int sdp_remove_codecs_by_id(sip_msg_t* msg, str* codecs)
280 {
281         sdp_info_t *sdp = NULL;
282         int sdp_session_num;
283         int sdp_stream_num;
284         sdp_session_cell_t* sdp_session;
285         sdp_stream_cell_t* sdp_stream;
286         str sdp_codecs;
287         str tmp_codecs;
288         str rm_codec;
289
290         if(parse_sdp(msg) < 0) {
291                 LM_ERR("Unable to parse sdp\n");
292                 return -1;
293         }
294
295         sdp = (sdp_info_t*)msg->body;
296
297         if(sdp==NULL) {
298                 LM_DBG("No sdp body\n");
299                 return -1;
300         }
301
302         LM_DBG("attempting to remove codecs from sdp: [%.*s]\n",
303                         codecs->len, codecs->s);
304
305         sdp_session_num = 0;
306         for(;;)
307         {
308                 sdp_session = get_sdp_session(msg, sdp_session_num);
309                 if(!sdp_session) break;
310                 sdp_stream_num = 0;
311                 for(;;)
312                 {
313                         sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
314                         if(!sdp_stream) break;
315
316                         LM_DBG("stream %d of %d - payloads [%.*s]\n",
317                                 sdp_stream_num, sdp_session_num, 
318                                 sdp_stream->payloads.len, sdp_stream->payloads.s);
319                         sdp_codecs = sdp_stream->payloads;
320                         tmp_codecs = *codecs;
321                         while(str_find_token(&tmp_codecs, &rm_codec, ',')==0
322                                         && rm_codec.len>0)
323                         {
324                                 tmp_codecs.len -=(int)(&rm_codec.s[rm_codec.len]-tmp_codecs.s);
325                                 tmp_codecs.s = rm_codec.s + rm_codec.len;
326
327                                 LM_DBG("codecs [%.*s] - remove [%.*s]\n",
328                                                 sdp_codecs.len, sdp_codecs.s,
329                                                 rm_codec.len, rm_codec.s);
330                                 sdp_remove_str_codec_id(msg, &sdp_codecs, &rm_codec);
331                                 sdp_remove_str_codec_id_attrs(msg, sdp_stream, &rm_codec);
332                         }
333                         sdp_stream_num++;
334                 }
335                 sdp_session_num++;
336         }
337
338         return 0;
339 }
340
341 /**
342  *
343  */
344 static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char* bar)
345 {
346         str lcodecs = {0, 0};
347
348         if(codecs==0)
349         {
350                 LM_ERR("invalid parameters\n");
351                 return -1;
352         }
353
354         if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
355         {
356                 LM_ERR("unable to get the list of codecs\n");
357                 return -1;
358         }
359
360         if(sdp_remove_codecs_by_id(msg, &lcodecs)<0)
361                 return -1;
362         return 1;
363 }
364
365 /**
366  *
367  */
368 int sdp_remove_codecs_by_name(sip_msg_t* msg, str* codecs)
369 {
370         sdp_info_t *sdp = NULL;
371         str idslist;
372
373         if(parse_sdp(msg) < 0) {
374                 LM_ERR("Unable to parse sdp\n");
375                 return -1;
376         }
377
378         sdp = (sdp_info_t*)msg->body;
379
380         if(sdp==NULL) {
381                 LM_DBG("No sdp body\n");
382                 return -1;
383         }
384
385         LM_DBG("attempting to remove codecs from sdp: [%.*s]\n",
386                         codecs->len, codecs->s);
387
388         if(sdpops_build_ids_list(sdp, codecs, &idslist)<0)
389                 return -1;
390
391         if(sdp_remove_codecs_by_id(msg, &idslist)<0)
392                 return -1;
393
394         return 0;
395
396 }
397
398 /**
399  *
400  */
401 static int w_sdp_remove_codecs_by_name(sip_msg_t* msg, char* codecs, char* bar)
402 {
403         str lcodecs = {0, 0};
404
405         if(codecs==0)
406         {
407                 LM_ERR("invalid parameters\n");
408                 return -1;
409         }
410
411         if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
412         {
413                 LM_ERR("unable to get the list of codecs\n");
414                 return -1;
415         }
416
417         if(sdp_remove_codecs_by_name(msg, &lcodecs)<0)
418                 return -1;
419         return 1;
420 }
421
422 /**
423  *
424  */
425 int sdp_keep_codecs_by_id(sip_msg_t* msg, str* codecs, str *media)
426 {
427         sdp_info_t *sdp = NULL;
428         int sdp_session_num;
429         int sdp_stream_num;
430         sdp_session_cell_t* sdp_session;
431         sdp_stream_cell_t* sdp_stream;
432         str sdp_codecs;
433         str tmp_codecs;
434         str rm_codec;
435
436         if(parse_sdp(msg) < 0) {
437                 LM_ERR("Unable to parse sdp\n");
438                 return -1;
439         }
440
441         sdp = (sdp_info_t*)msg->body;
442
443         if(sdp==NULL) {
444                 LM_DBG("No sdp body\n");
445                 return -1;
446         }
447
448         LM_DBG("attempting to keep codecs in sdp: [%.*s]\n",
449                         codecs->len, codecs->s);
450
451         sdp_session_num = 0;
452         for(;;)
453         {
454                 sdp_session = get_sdp_session(msg, sdp_session_num);
455                 if(!sdp_session) break;
456                 sdp_stream_num = 0;
457                 for(;;)
458                 {
459                         sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
460                         if(!sdp_stream) break;
461
462                         LM_DBG("stream %d of %d - payloads [%.*s]\n",
463                                 sdp_stream_num, sdp_session_num,
464                                 sdp_stream->payloads.len, sdp_stream->payloads.s);
465                         if((media==NULL)
466                                         || (media->len==sdp_stream->media.len
467                                                 && strncasecmp(sdp_stream->media.s, media->s,
468                                                         media->len)==0))
469                         {
470                                 sdp_codecs = sdp_stream->payloads;
471                                 tmp_codecs = sdp_stream->payloads;
472                                 while(str_find_token(&tmp_codecs, &rm_codec, ' ')==0
473                                                 && rm_codec.len>0)
474                                 {
475                                         tmp_codecs.len -=(int)(&rm_codec.s[rm_codec.len]-tmp_codecs.s);
476                                         tmp_codecs.s = rm_codec.s + rm_codec.len;
477
478                                         if(sdp_codec_in_str(codecs, &rm_codec, ',')==0) {
479                                                 LM_DBG("codecs [%.*s] - remove [%.*s]\n",
480                                                         sdp_codecs.len, sdp_codecs.s,
481                                                         rm_codec.len, rm_codec.s);
482                                                 sdp_remove_str_codec_id(msg, &sdp_codecs, &rm_codec);
483                                                 sdp_remove_str_codec_id_attrs(msg, sdp_stream, &rm_codec);
484                                         }
485                                 }
486                         }
487                         sdp_stream_num++;
488                 }
489                 sdp_session_num++;
490         }
491
492         return 0;
493 }
494
495 /**
496  *
497  */
498 static int w_sdp_keep_codecs_by_id(sip_msg_t* msg, char* codecs, char* media)
499 {
500         str lcodecs = {0, 0};
501         str lmedia = {0, 0};
502
503         if(codecs==0)
504         {
505                 LM_ERR("invalid parameters\n");
506                 return -1;
507         }
508
509         if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
510         {
511                 LM_ERR("unable to get the list of codecs\n");
512                 return -1;
513         }
514         if(media!=NULL)
515         {
516                 if(fixup_get_svalue(msg, (gparam_p)media, &lmedia)!=0)
517                 {
518                         LM_ERR("unable to get the media type\n");
519                         return -1;
520                 }
521         }
522
523         if(sdp_keep_codecs_by_id(msg, &lcodecs, (media)?&lmedia:NULL)<0)
524                 return -1;
525         return 1;
526 }
527
528 /**
529  *
530  */
531 int sdp_keep_codecs_by_name(sip_msg_t* msg, str* codecs, str *media)
532 {
533         sdp_info_t *sdp = NULL;
534         str idslist;
535
536         if(parse_sdp(msg) < 0) {
537                 LM_ERR("Unable to parse sdp\n");
538                 return -1;
539         }
540
541         sdp = (sdp_info_t*)msg->body;
542
543         if(sdp==NULL) {
544                 LM_DBG("No sdp body\n");
545                 return -1;
546         }
547
548         LM_DBG("attempting to keep codecs in sdp: [%.*s]\n",
549                         codecs->len, codecs->s);
550
551         if(sdpops_build_ids_list(sdp, codecs, &idslist)<0)
552                 return -1;
553
554         if(sdp_keep_codecs_by_id(msg, &idslist, media)<0)
555                 return -1;
556
557         return 0;
558
559 }
560
561 /**
562  *
563  */
564 static int w_sdp_keep_codecs_by_name(sip_msg_t* msg, char* codecs, char* media)
565 {
566         str lcodecs = {0, 0};
567         str lmedia = {0, 0};
568
569         if(codecs==0)
570         {
571                 LM_ERR("invalid parameters\n");
572                 return -1;
573         }
574
575         if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
576         {
577                 LM_ERR("unable to get the list of codecs\n");
578                 return -1;
579         }
580
581         if(media!=NULL)
582         {
583                 if(fixup_get_svalue(msg, (gparam_p)media, &lmedia)!=0)
584                 {
585                         LM_ERR("unable to get the media type\n");
586                         return -1;
587                 }
588         }
589
590         if(sdp_keep_codecs_by_name(msg, &lcodecs, (media)?&lmedia:NULL)<0)
591                 return -1;
592         return 1;
593 }
594
595 /** 
596  * @brief check 'media' matches the value of any 'm=value ...' lines
597  * @return -1 - error; 0 - not found; 1 - found
598  */
599 static int sdp_with_media(sip_msg_t *msg, str *media)
600 {
601         int sdp_session_num;
602         int sdp_stream_num;
603         sdp_session_cell_t* sdp_session;
604         sdp_stream_cell_t* sdp_stream;
605
606         if(parse_sdp(msg) < 0) {
607                 LM_ERR("Unable to parse sdp\n");
608                 return -1;
609         }
610
611         LM_DBG("attempting to search for media type: [%.*s]\n",
612                         media->len, media->s);
613
614         sdp_session_num = 0;
615         for(;;)
616         {
617                 sdp_session = get_sdp_session(msg, sdp_session_num);
618                 if(!sdp_session) break;
619                 sdp_stream_num = 0;
620                 for(;;)
621                 {
622                         sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
623                         if(!sdp_stream) break;
624
625                         LM_DBG("stream %d of %d - media [%.*s]\n",
626                                 sdp_stream_num, sdp_session_num,
627                                 sdp_stream->media.len, sdp_stream->media.s);
628                         if(media->len==sdp_stream->media.len
629                                         && strncasecmp(sdp_stream->media.s, media->s,
630                                                         media->len)==0)
631                                 return 1;
632                         sdp_stream_num++;
633                 }
634                 sdp_session_num++;
635         }
636
637         return 0;
638 }
639
640 /**
641  *
642  */
643 static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar)
644 {
645         str lmedia = {0, 0};
646
647         if(media==0)
648         {
649                 LM_ERR("invalid parameters\n");
650                 return -1;
651         }
652
653         if(fixup_get_svalue(msg, (gparam_p)media, &lmedia)!=0)
654         {
655                 LM_ERR("unable to get the media value\n");
656                 return -1;
657         }
658
659         if(sdp_with_media(msg, &lmedia)<=0)
660                 return -1;
661         return 1;
662 }
663
664 /**
665  * @brief remove streams matching the m='media'
666  * @return -1 - error; 0 - not found; >=1 - found
667  */
668 static int sdp_remove_media(sip_msg_t *msg, str *media)
669 {
670         sdp_info_t *sdp = NULL;
671         int sdp_session_num;
672         int sdp_stream_num;
673         sdp_session_cell_t* sdp_session;
674         sdp_stream_cell_t* sdp_stream;
675         sdp_stream_cell_t* nxt_stream;
676         int ret = 0;
677         char *dstart = NULL;
678         int dlen = 0;
679         struct lump *anchor;
680
681         if(parse_sdp(msg) < 0) {
682                 LM_ERR("Unable to parse sdp\n");
683                 return -1;
684         }
685
686         LM_DBG("attempting to search for media type: [%.*s]\n",
687                         media->len, media->s);
688
689         sdp = (sdp_info_t*)msg->body;
690
691         sdp_session_num = 0;
692         for(;;)
693         {
694                 sdp_session = get_sdp_session(msg, sdp_session_num);
695                 if(!sdp_session) break;
696                 sdp_stream_num = 0;
697                 for(;;)
698                 {
699                         sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
700                         if(!sdp_stream) break;
701
702                         LM_DBG("stream %d of %d - media [%.*s]\n",
703                                 sdp_stream_num, sdp_session_num,
704                                 sdp_stream->media.len, sdp_stream->media.s);
705                         if(media->len==sdp_stream->media.len
706                                         && strncasecmp(sdp_stream->media.s, media->s,
707                                                         media->len)==0)
708                         {
709                                 /* found - remove */
710                                 LM_DBG("removing media stream: %.*s", media->len, media->s);
711                                 nxt_stream = get_sdp_stream(msg, sdp_session_num,
712                                                                 sdp_stream_num+1);
713                                 /* skip back 'm=' */
714                                 dstart = sdp_stream->media.s - 2;
715                                 if(!nxt_stream) {
716                                         /* delete to end of sdp */
717                                         dlen = (int)(sdp->text.s + sdp->text.len - dstart);
718                                 } else {
719                                         /* delete to start of next stream */
720                                         dlen = (int)(nxt_stream->media.s - 2 - dstart);
721                                 }
722                                 anchor = del_lump(msg, dstart - msg->buf, dlen, 0);
723                                 if (anchor == NULL) {
724                                         LM_ERR("failed to remove media type [%.*s]\n",
725                                                  media->len, media->s);
726                                         return -1;
727                                 }
728
729                                 ret++;
730                         }
731                         sdp_stream_num++;
732                 }
733                 sdp_session_num++;
734         }
735
736         return ret;
737 }
738
739
740 /**
741  *
742  */
743 static int w_sdp_remove_media(sip_msg_t* msg, char* media, char *bar)
744 {
745         str lmedia = {0, 0};
746
747         if(media==0)
748         {
749                 LM_ERR("invalid parameters\n");
750                 return -1;
751         }
752
753         if(fixup_get_svalue(msg, (gparam_p)media, &lmedia)!=0)
754         {
755                 LM_ERR("unable to get the media value\n");
756                 return -1;
757         }
758
759         if(sdp_remove_media(msg, &lmedia)<=0)
760                 return -1;
761         return 1;
762 }
763
764
765 /**
766  *
767  */
768 int sdp_with_codecs_by_id(sip_msg_t* msg, str* codecs)
769 {
770         sdp_info_t *sdp = NULL;
771         int sdp_session_num;
772         int sdp_stream_num;
773         sdp_session_cell_t* sdp_session;
774         sdp_stream_cell_t* sdp_stream;
775         str sdp_codecs;
776         str tmp_codecs;
777         str fnd_codec;
778         int foundone = 0;
779         int notfound = 0;
780
781         if(parse_sdp(msg) < 0) {
782                 LM_ERR("Unable to parse sdp\n");
783                 return -1;
784         }
785
786         sdp = (sdp_info_t*)msg->body;
787
788         if(sdp==NULL) {
789                 LM_DBG("No sdp body\n");
790                 return -1;
791         }
792
793         LM_DBG("attempting to search codecs in sdp: [%.*s]\n",
794                         codecs->len, codecs->s);
795
796         sdp_session_num = 0;
797         for(;;)
798         {
799                 sdp_session = get_sdp_session(msg, sdp_session_num);
800                 if(!sdp_session) break;
801                 sdp_stream_num = 0;
802                 for(;;)
803                 {
804                         sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
805                         if(!sdp_stream) break;
806
807                         LM_DBG("stream %d of %d - payloads [%.*s]\n",
808                                 sdp_stream_num, sdp_session_num,
809                                 sdp_stream->payloads.len, sdp_stream->payloads.s);
810                         sdp_codecs = sdp_stream->payloads;
811                         tmp_codecs = *codecs;
812                         while(str_find_token(&tmp_codecs, &fnd_codec, ',')==0
813                                         && fnd_codec.len>0)
814                         {
815                                 tmp_codecs.len -=(int)(&fnd_codec.s[fnd_codec.len]-tmp_codecs.s);
816                                 tmp_codecs.s = fnd_codec.s + fnd_codec.len;
817
818                                 if(sdp_codec_in_str(&sdp_codecs, &fnd_codec, ' ')==0) {
819                                         LM_DBG("codecs [%.*s] - not found [%.*s]\n",
820                                                 sdp_codecs.len, sdp_codecs.s,
821                                                 fnd_codec.len, fnd_codec.s);
822                                         notfound = 1;
823                                 } else {
824                                         LM_DBG("codecs [%.*s] - found [%.*s]\n",
825                                                 sdp_codecs.len, sdp_codecs.s,
826                                                 fnd_codec.len, fnd_codec.s);
827                                         foundone = 1;
828                                 }
829                         }
830                         sdp_stream_num++;
831                 }
832                 sdp_session_num++;
833         }
834
835         return (foundone + ((foundone)?notfound:0));
836 }
837
838 /**
839  *
840  */
841 static int w_sdp_with_codecs_by_id(sip_msg_t* msg, char* codecs, char *bar)
842 {
843         str lcodecs = {0, 0};
844         int ret;
845
846         if(codecs==0)
847         {
848                 LM_ERR("invalid parameters\n");
849                 return -1;
850         }
851
852         if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
853         {
854                 LM_ERR("unable to get the codecs\n");
855                 return -1;
856         }
857
858         ret = sdp_with_codecs_by_id(msg, &lcodecs);
859         /* ret: -1 error; 0 not found */
860         if(ret<=0)
861                 return (ret - 1);
862         return ret;
863 }
864
865 /**
866  *
867  */
868 static int w_sdp_with_codecs_by_name(sip_msg_t* msg, char* codecs, char *bar)
869 {
870         str lcodecs = {0, 0};
871         str idslist;
872         sdp_info_t *sdp = NULL;
873         int ret;
874
875         if(codecs==0)
876         {
877                 LM_ERR("invalid parameters\n");
878                 return -1;
879         }
880
881         if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
882         {
883                 LM_ERR("unable to get the codecs\n");
884                 return -1;
885         }
886
887         if(parse_sdp(msg) < 0) {
888                 LM_ERR("Unable to parse sdp\n");
889                 return -1;
890         }
891
892         sdp = (sdp_info_t*)msg->body;
893
894         if(sdp==NULL) {
895                 LM_DBG("No sdp body\n");
896                 return -1;
897         }
898
899         if(sdpops_build_ids_list(sdp, &lcodecs, &idslist)<0)
900                 return -1;
901
902         ret = sdp_with_codecs_by_id(msg, &idslist);
903         /* ret: -1 error; 0 not found */
904         if(ret<=0)
905                 return (ret - 1);
906         return ret;
907 }
908
909 /**
910  *
911  */
912 static int w_sdp_print(sip_msg_t* msg, char* level, char *bar)
913 {
914         sdp_info_t *sdp = NULL;
915         int llevel = L_DBG;
916
917         if(parse_sdp(msg) < 0) {
918                 LM_ERR("Unable to parse sdp\n");
919                 return -1;
920         }
921
922         if(fixup_get_ivalue(msg, (gparam_p)level, &llevel)!=0)
923         {
924                 LM_ERR("unable to get the debug level value\n");
925                 return -1;
926         }
927
928         sdp = (sdp_info_t*)msg->body;
929
930         print_sdp(sdp, llevel);
931         return 1;
932 }
933
934
935 /**
936  *
937  */
938 static int w_get_sdp(sip_msg_t* msg, char *avp)
939 {
940         sdp_info_t *sdp = NULL;
941         int_str avp_val;
942         int_str avp_name;
943         static unsigned short avp_type = 0;
944         str s;
945         pv_spec_t *avp_spec = NULL;
946         int sdp_missing=1;
947         
948         s.s = avp; s.len = strlen(s.s);
949         if (pv_locate_name(&s) != s.len)
950         {
951                 LM_ERR("invalid parameter\n");
952                 return -1;
953         }
954         if (((avp_spec = pv_cache_get(&s)) == NULL)
955                         || avp_spec->type!=PVT_AVP) {
956                 LM_ERR("malformed or non AVP %s AVP definition\n", avp);
957                 return -1;
958         }
959
960         if(pv_get_avp_name(0, &avp_spec->pvp, &avp_name, &avp_type)!=0)
961         {
962                 LM_ERR("[%s]- invalid AVP definition\n", avp);
963                 return -1;
964         }
965
966         sdp_missing = parse_sdp(msg);
967         if(sdp_missing < 0) {
968                 LM_ERR("Unable to parse sdp\n");
969                 return -1;
970         }
971         sdp = (sdp_info_t*)msg->body;
972         
973         if (sdp_missing) {
974                 LM_DBG("No SDP\n");
975                 return -2;
976         } else {
977                 avp_val.s.s = pkg_malloc(sdp->raw_sdp.len);
978                 avp_val.s.len = sdp->raw_sdp.len;
979                 if (avp_val.s.s == NULL)
980                 {
981                   LM_ERR("Failed to alloc memory for SDP");
982                   return -1;
983                 }
984                 memcpy(avp_val.s.s, sdp->raw_sdp.s, avp_val.s.len);
985                 LM_DBG("Found SDP %.*s\n", sdp->raw_sdp.len, sdp->raw_sdp.s);
986         }
987         if (add_avp(AVP_VAL_STR | avp_type, avp_name, avp_val) != 0)
988         {
989           LM_ERR("Failed to add SDP avp");
990           return -1;
991         }
992         
993         return 1;
994 }
995
996 /**
997  *
998  */
999 int bind_sdpops(struct sdpops_binds *sob){
1000         if (sob == NULL) {
1001                 LM_WARN("bind_sdpops: Cannot load sdpops API into a NULL pointer\n");
1002                 return -1;
1003         }
1004         sob->sdp_with_media = sdp_with_media;
1005         return 0;
1006 }