http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / userapps / opensource / libosip2 / src / osip2 / osip_negotiation.c
1 /*
2   The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3   Copyright (C) 2001,2002,2003  Aymeric MOIZARD jack@atosc.org
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14   
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20
21 #include <osip2/osip_negotiation.h>
22 #include <osip2/internal.h>
23
24 static int sdp_partial_clone (osip_negotiation_t * config,
25                               osip_negotiation_ctx_t * con,
26                               sdp_message_t * remote, sdp_message_t ** dest);
27 static int sdp_confirm_media (osip_negotiation_t * config,
28                               osip_negotiation_ctx_t * context,
29                               sdp_message_t * remote, sdp_message_t ** dest);
30 static __payload_t *osip_negotiation_find_audio_payload (osip_negotiation_t *
31                                                          cfg, char *payload);
32 static __payload_t *osip_negotiation_find_video_payload (osip_negotiation_t *
33                                                          cfg, char *payload);
34 static __payload_t *osip_negotiation_find_other_payload (osip_negotiation_t *
35                                                          cfg, char *payload);
36
37
38
39 int
40 osip_negotiation_ctx_init (osip_negotiation_ctx_t ** con)
41 {
42   (*con) =
43     (osip_negotiation_ctx_t *) osip_malloc (sizeof (osip_negotiation_ctx_t));
44   if (*con == NULL)
45     return -1;
46   (*con)->mycontext = NULL;     /* fixed Sep 24 2003 */
47   (*con)->remote = NULL;
48   (*con)->local = NULL;
49   return 0;
50 }
51
52 void
53 osip_negotiation_ctx_free (osip_negotiation_ctx_t * con)
54 {
55   if (con == NULL)
56     return;
57   sdp_message_free (con->remote);
58   sdp_message_free (con->local);
59   osip_free (con);
60 }
61
62 /* this method is used by end-user application so any pointer can
63    be associated with this context (usefull to link with your own context */
64 int
65 osip_negotiation_ctx_set_mycontext (osip_negotiation_ctx_t * con,
66                                     void *my_instance)
67 {
68   if (con == NULL)
69     return -1;
70   con->mycontext = my_instance;
71   return 0;
72 }
73
74 void *
75 osip_negotiation_ctx_get_mycontext (osip_negotiation_ctx_t * con)
76 {
77   if (con == NULL)
78     return NULL;
79   return con->mycontext;
80 }
81
82 sdp_message_t *
83 osip_negotiation_ctx_get_local_sdp (osip_negotiation_ctx_t * con)
84 {
85   if (con == NULL)
86     return NULL;
87   return con->local;
88 }
89
90 int
91 osip_negotiation_ctx_set_local_sdp (osip_negotiation_ctx_t * con,
92                                     sdp_message_t * sdp)
93 {
94   if (con == NULL)
95     return -1;
96   con->local = sdp;
97   return 0;
98 }
99
100 sdp_message_t *
101 osip_negotiation_ctx_get_remote_sdp (osip_negotiation_ctx_t * con)
102 {
103   if (con == NULL)
104     return NULL;
105   return con->remote;
106 }
107
108 int
109 osip_negotiation_ctx_set_remote_sdp (osip_negotiation_ctx_t * con,
110                                      sdp_message_t * sdp)
111 {
112   if (con == NULL)
113     return -1;
114   con->remote = sdp;
115   return 0;
116 }
117
118 int
119 __payload_init (__payload_t ** payload)
120 {
121   *payload = (__payload_t *) osip_malloc (sizeof (__payload_t));
122   if (*payload == NULL)
123     return -1;
124   (*payload)->payload = NULL;
125   (*payload)->number_of_port = NULL;
126   (*payload)->proto = NULL;
127   (*payload)->c_nettype = NULL;
128   (*payload)->c_addrtype = NULL;
129   (*payload)->c_addr = NULL;
130   (*payload)->c_addr_multicast_ttl = NULL;
131   (*payload)->c_addr_multicast_int = NULL;
132   (*payload)->a_rtpmap = NULL;
133   return 0;
134 }
135
136 void
137 __payload_free (__payload_t * payload)
138 {
139   if (payload == NULL)
140     return;
141   osip_free (payload->payload);
142   osip_free (payload->number_of_port);
143   osip_free (payload->proto);
144   osip_free (payload->c_nettype);
145   osip_free (payload->c_addrtype);
146   osip_free (payload->c_addr);
147   osip_free (payload->c_addr_multicast_ttl);
148   osip_free (payload->c_addr_multicast_int);
149   osip_free (payload->a_rtpmap);
150   osip_free (payload);
151 }
152
153 int
154 osip_negotiation_init (osip_negotiation_t ** config_out)
155 {
156   osip_negotiation_t *config;
157
158   config = (osip_negotiation_t *) osip_malloc (sizeof (osip_negotiation_t));
159   if (config == NULL)
160     return -1;
161   config->o_username = NULL;
162   config->o_session_id = NULL;
163   config->o_session_version = NULL;
164   config->o_nettype = NULL;
165   config->o_addrtype = NULL;
166   config->o_addr = NULL;
167
168   config->c_nettype = NULL;
169   config->c_addrtype = NULL;
170   config->c_addr = NULL;
171   config->c_addr_multicast_ttl = NULL;
172   config->c_addr_multicast_int = NULL;
173
174   /* supported codec for the SIP User Agent */
175   config->audio_codec = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
176   osip_list_init (config->audio_codec);
177   config->video_codec = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
178   osip_list_init (config->video_codec);
179   config->other_codec = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
180   osip_list_init (config->other_codec);
181
182   config->fcn_set_info = NULL;
183   config->fcn_set_uri = NULL;
184   config->fcn_set_emails = NULL;
185   config->fcn_set_phones = NULL;
186   config->fcn_set_attributes = NULL;
187   config->fcn_accept_audio_codec = NULL;
188   config->fcn_accept_video_codec = NULL;
189   config->fcn_accept_other_codec = NULL;
190
191   *config_out = config;
192
193   return 0;
194 }
195
196 void
197 osip_negotiation_free (osip_negotiation_t * config)
198 {
199   if (config == NULL)
200     return;
201   osip_free (config->o_username);
202   osip_free (config->o_session_id);
203   osip_free (config->o_session_version);
204   osip_free (config->o_nettype);
205   osip_free (config->o_addrtype);
206   osip_free (config->o_addr);
207
208   osip_free (config->c_nettype);
209   osip_free (config->c_addrtype);
210   osip_free (config->c_addr);
211   osip_free (config->c_addr_multicast_ttl);
212   osip_free (config->c_addr_multicast_int);
213
214   osip_list_special_free (config->audio_codec,
215                           (void *(*)(void *)) &__payload_free);
216   osip_list_special_free (config->video_codec,
217                           (void *(*)(void *)) &__payload_free);
218   osip_list_special_free (config->other_codec,
219                           (void *(*)(void *)) &__payload_free);
220
221   /* other are pointer to func, they don't need free() calls */
222
223   /* yes, this is done here... :) */
224   osip_free (config);
225 }
226
227 int
228 osip_negotiation_set_o_username (osip_negotiation_t * config, char *tmp)
229 {
230   if (config == NULL)
231     return -1;
232   config->o_username = tmp;
233   return 0;
234 }
235
236 int
237 osip_negotiation_set_o_session_id (osip_negotiation_t * config, char *tmp)
238 {
239   if (config == NULL)
240     return -1;
241   config->o_session_id = tmp;
242   return 0;
243 }
244
245 int
246 osip_negotiation_set_o_session_version (osip_negotiation_t * config,
247                                         char *tmp)
248 {
249   if (config == NULL)
250     return -1;
251   config->o_session_version = tmp;
252   return 0;
253 }
254
255 int
256 osip_negotiation_set_o_nettype (osip_negotiation_t * config, char *tmp)
257 {
258   if (config == NULL)
259     return -1;
260   config->o_nettype = tmp;
261   return 0;
262 }
263
264 int
265 osip_negotiation_set_o_addrtype (osip_negotiation_t * config, char *tmp)
266 {
267   if (config == NULL)
268     return -1;
269   config->o_addrtype = tmp;
270   return 0;
271 }
272
273 int
274 osip_negotiation_set_o_addr (osip_negotiation_t * config, char *tmp)
275 {
276   if (config == NULL)
277     return -1;
278   config->o_addr = tmp;
279   return 0;
280 }
281
282 int
283 osip_negotiation_set_c_nettype (osip_negotiation_t * config, char *tmp)
284 {
285   if (config == NULL)
286     return -1;
287   config->c_nettype = tmp;
288   return 0;
289 }
290
291 int
292 osip_negotiation_set_c_addrtype (osip_negotiation_t * config, char *tmp)
293 {
294   if (config == NULL)
295     return -1;
296   config->c_addrtype = tmp;
297   return 0;
298 }
299
300 int
301 osip_negotiation_set_c_addr (osip_negotiation_t * config, char *tmp)
302 {
303   if (config == NULL)
304     return -1;
305   config->c_addr = tmp;
306   return 0;
307 }
308
309 int
310 osip_negotiation_set_c_addr_multicast_ttl (osip_negotiation_t * config,
311                                            char *tmp)
312 {
313   if (config == NULL)
314     return -1;
315   config->c_addr_multicast_ttl = tmp;
316   return 0;
317 }
318
319 int
320 osip_negotiation_set_c_addr_multicast_int (osip_negotiation_t * config,
321                                            char *tmp)
322 {
323   if (config == NULL)
324     return -1;
325   config->c_addr_multicast_int = tmp;
326   return 0;
327 }
328
329 int
330 osip_negotiation_add_support_for_audio_codec (osip_negotiation_t * config,
331                                               char *payload,
332                                               char *number_of_port,
333                                               char *proto, char *c_nettype,
334                                               char *c_addrtype, char *c_addr,
335                                               char *c_addr_multicast_ttl,
336                                               char *c_addr_multicast_int,
337                                               char *a_rtpmap)
338 {
339   int i;
340   __payload_t *my_payload;
341
342   i = __payload_init (&my_payload);
343   if (i != 0)
344     return -1;
345   my_payload->payload = payload;
346   my_payload->number_of_port = number_of_port;
347   my_payload->proto = proto;
348   my_payload->c_nettype = c_nettype;
349   my_payload->c_addrtype = c_addrtype;
350   my_payload->c_addr = c_addr;
351   my_payload->c_addr_multicast_ttl = c_addr_multicast_ttl;
352   my_payload->c_addr_multicast_int = c_addr_multicast_int;
353   my_payload->a_rtpmap = a_rtpmap;
354   osip_list_add (config->audio_codec, my_payload, -1);
355   return 0;
356 }
357
358 int
359 osip_negotiation_add_support_for_video_codec (osip_negotiation_t * config,
360                                               char *payload,
361                                               char *number_of_port,
362                                               char *proto, char *c_nettype,
363                                               char *c_addrtype, char *c_addr,
364                                               char *c_addr_multicast_ttl,
365                                               char *c_addr_multicast_int,
366                                               char *a_rtpmap)
367 {
368   int i;
369   __payload_t *my_payload;
370
371   i = __payload_init (&my_payload);
372   if (i != 0)
373     return -1;
374   my_payload->payload = payload;
375   my_payload->number_of_port = number_of_port;
376   my_payload->proto = proto;
377   my_payload->c_nettype = c_nettype;
378   my_payload->c_addrtype = c_addrtype;
379   my_payload->c_addr = c_addr;
380   my_payload->c_addr_multicast_ttl = c_addr_multicast_ttl;
381   my_payload->c_addr_multicast_int = c_addr_multicast_int;
382   my_payload->a_rtpmap = a_rtpmap;
383   osip_list_add (config->video_codec, my_payload, -1);
384   return 0;
385 }
386
387 int
388 osip_negotiation_add_support_for_other_codec (osip_negotiation_t * config,
389                                               char *payload,
390                                               char *number_of_port,
391                                               char *proto, char *c_nettype,
392                                               char *c_addrtype, char *c_addr,
393                                               char *c_addr_multicast_ttl,
394                                               char *c_addr_multicast_int,
395                                               char *a_rtpmap)
396 {
397   int i;
398   __payload_t *my_payload;
399
400   i = __payload_init (&my_payload);
401   if (i != 0)
402     return -1;
403   my_payload->payload = payload;
404   my_payload->number_of_port = number_of_port;
405   my_payload->proto = proto;
406   my_payload->c_nettype = c_nettype;
407   my_payload->c_addrtype = c_addrtype;
408   my_payload->c_addr = c_addr;
409   my_payload->c_addr_multicast_ttl = c_addr_multicast_ttl;
410   my_payload->c_addr_multicast_int = c_addr_multicast_int;
411   my_payload->a_rtpmap = a_rtpmap;
412   osip_list_add (config->other_codec, my_payload, -1);
413   return 0;
414 }
415
416 int
417 osip_negotiation_remove_audio_payloads (osip_negotiation_t * config)
418 {
419   osip_list_special_free (config->audio_codec,
420                           (void *(*)(void *)) &__payload_free);
421   config->audio_codec = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
422   osip_list_init (config->audio_codec);
423   return 0;
424 }
425
426 int
427 osip_negotiation_remove_video_payloads (osip_negotiation_t * config)
428 {
429   osip_list_special_free (config->video_codec,
430                           (void *(*)(void *)) &__payload_free);
431   config->video_codec = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
432   osip_list_init (config->video_codec);
433   return 0;
434 }
435
436 int
437 osip_negotiation_remove_other_payloads (osip_negotiation_t * config)
438 {
439   osip_list_special_free (config->other_codec,
440                           (void *(*)(void *)) &__payload_free);
441   config->other_codec = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
442   osip_list_init (config->other_codec);
443   return 0;
444 }
445
446 static __payload_t *
447 osip_negotiation_find_audio_payload (osip_negotiation_t * config,
448                                      char *payload)
449 {
450   __payload_t *my;
451   size_t length = strlen (payload);
452   int pos = 0;
453
454   if (payload == NULL)
455     return NULL;
456   while (!osip_list_eol (config->audio_codec, pos))
457     {
458       my = (__payload_t *) osip_list_get (config->audio_codec, pos);
459       if (strlen (my->payload) == length)
460         if (0 == strncmp (my->payload, payload, length))
461           return my;
462       pos++;
463     }
464   return NULL;
465 }
466
467 static __payload_t *
468 osip_negotiation_find_video_payload (osip_negotiation_t * config,
469                                      char *payload)
470 {
471   __payload_t *my;
472   size_t length = strlen (payload);
473   int pos = 0;
474
475   if (payload == NULL)
476     return NULL;
477   while (!osip_list_eol (config->video_codec, pos))
478     {
479       my = (__payload_t *) osip_list_get (config->video_codec, pos);
480       if (strlen (my->payload) == length)
481         if (0 == strncmp (my->payload, payload, length))
482           return my;
483       pos++;
484     }
485   return NULL;
486 }
487
488 static __payload_t *
489 osip_negotiation_find_other_payload (osip_negotiation_t * config,
490                                      char *payload)
491 {
492   __payload_t *my;
493   size_t length = strlen (payload);
494   int pos = 0;
495
496   if (payload == NULL)
497     return NULL;
498   while (!osip_list_eol (config->other_codec, pos))
499     {
500       my = (__payload_t *) osip_list_get (config->other_codec, pos);
501       if (strlen (my->payload) == length)
502         if (0 == strncmp (my->payload, payload, length))
503           return my;
504       pos++;
505     }
506   return NULL;
507 }
508
509 int
510 osip_negotiation_set_fcn_set_info (osip_negotiation_t * config,
511                                    int (*fcn) (osip_negotiation_ctx_t *,
512                                                sdp_message_t *))
513 {
514   if (config == NULL)
515     return -1;
516   config->fcn_set_info = (int (*)(void *, sdp_message_t *)) fcn;
517   return 0;
518 }
519
520 int
521 osip_negotiation_set_fcn_set_uri (osip_negotiation_t * config,
522                                   int (*fcn) (osip_negotiation_ctx_t *,
523                                               sdp_message_t *))
524 {
525   if (config == NULL)
526     return -1;
527   config->fcn_set_uri = (int (*)(void *, sdp_message_t *)) fcn;
528   return 0;
529 }
530
531 int
532 osip_negotiation_set_fcn_set_emails (osip_negotiation_t * config,
533                                      int (*fcn) (osip_negotiation_ctx_t *,
534                                                  sdp_message_t *))
535 {
536   if (config == NULL)
537     return -1;
538   config->fcn_set_emails = (int (*)(void *, sdp_message_t *)) fcn;
539   return 0;
540 }
541
542 int
543 osip_negotiation_set_fcn_set_phones (osip_negotiation_t * config,
544                                      int (*fcn) (osip_negotiation_ctx_t *,
545                                                  sdp_message_t *))
546 {
547   if (config == NULL)
548     return -1;
549   config->fcn_set_phones = (int (*)(void *, sdp_message_t *)) fcn;
550   return 0;
551 }
552
553 int
554 osip_negotiation_set_fcn_set_attributes (osip_negotiation_t * config,
555                                          int (*fcn) (osip_negotiation_ctx_t *,
556                                                      sdp_message_t *, int))
557 {
558   if (config == NULL)
559     return -1;
560   config->fcn_set_attributes = (int (*)(void *, sdp_message_t *, int)) fcn;
561   return 0;
562 }
563
564 int
565 osip_negotiation_set_fcn_accept_audio_codec (osip_negotiation_t * config,
566                                              int (*fcn)
567                                              (osip_negotiation_ctx_t *,
568                                               char *, char *, int, char *))
569 {
570   if (config == NULL)
571     return -1;
572   config->fcn_accept_audio_codec = (int (*)(void *, char *,
573                                             char *, int, char *)) fcn;
574   return 0;
575 }
576
577 int
578 osip_negotiation_set_fcn_accept_video_codec (osip_negotiation_t * config,
579                                              int (*fcn)
580                                              (osip_negotiation_ctx_t *,
581                                               char *, char *, int, char *))
582 {
583   if (config == NULL)
584     return -1;
585   config->fcn_accept_video_codec = (int (*)(void *, char *,
586                                             char *, int, char *)) fcn;
587   return 0;
588 }
589
590 int
591 osip_negotiation_set_fcn_accept_other_codec (osip_negotiation_t * config,
592                                              int (*fcn)
593                                              (osip_negotiation_ctx_t *,
594                                               char *, char *, char *, char *))
595 {
596   if (config == NULL)
597     return -1;
598   config->fcn_accept_other_codec = (int (*)(void *, char *,
599                                             char *, char *, char *)) fcn;
600   return 0;
601 }
602
603 int
604 osip_negotiation_set_fcn_get_audio_port (osip_negotiation_t * config,
605                                          char *(*fcn) (osip_negotiation_ctx_t
606                                                        *, int))
607 {
608   if (config == NULL)
609     return -1;
610   config->fcn_get_audio_port = (char *(*)(void *, int)) fcn;
611   return 0;
612 }
613
614 int
615 osip_negotiation_set_fcn_get_video_port (osip_negotiation_t * config,
616                                          char *(*fcn) (osip_negotiation_ctx_t
617                                                        *, int))
618 {
619   if (config == NULL)
620     return -1;
621   config->fcn_get_video_port = (char *(*)(void *, int)) fcn;
622   return 0;
623 }
624
625 int
626 osip_negotiation_set_fcn_get_other_port (osip_negotiation_t * config,
627                                          char *(*fcn) (osip_negotiation_ctx_t
628                                                        *, int))
629 {
630   if (config == NULL)
631     return -1;
632   config->fcn_get_other_port = (char *(*)(void *, int)) fcn;
633   return 0;
634 }
635
636 static int
637 sdp_partial_clone (osip_negotiation_t * config,
638                    osip_negotiation_ctx_t * con, sdp_message_t * remote,
639                    sdp_message_t ** dest)
640 {
641   int i;
642
643   sdp_message_v_version_set (*dest, osip_strdup ("0"));
644
645   /* those fields MUST be set */
646   sdp_message_o_origin_set (*dest,
647                             osip_strdup (config->o_username),
648                             osip_strdup (config->o_session_id),
649                             osip_strdup (config->o_session_version),
650                             osip_strdup (config->o_nettype),
651                             osip_strdup (config->o_addrtype),
652                             osip_strdup (config->o_addr));
653   sdp_message_s_name_set (*dest, osip_strdup (remote->s_name));
654   if (config->fcn_set_info != NULL)
655     config->fcn_set_info (con, *dest);
656   if (config->fcn_set_uri != NULL)
657     config->fcn_set_uri (con, *dest);
658   if (config->fcn_set_emails != NULL)
659     config->fcn_set_emails (con, *dest);
660   if (config->fcn_set_phones != NULL)
661     config->fcn_set_phones (con, *dest);
662   if (config->c_nettype != NULL)
663     sdp_message_c_connection_add (*dest, -1,
664                                   osip_strdup (config->c_nettype),
665                                   osip_strdup (config->c_addrtype),
666                                   osip_strdup (config->c_addr),
667                                   osip_strdup (config->c_addr_multicast_ttl),
668                                   osip_strdup (config->c_addr_multicast_int));
669
670   {                             /* offer-answer draft says we must copy the "t=" line */
671     char *tmp = sdp_message_t_start_time_get (remote, 0);
672     char *tmp2 = sdp_message_t_stop_time_get (remote, 0);
673
674     if (tmp == NULL || tmp2 == NULL)
675       return -1;                /* no t line?? */
676     i =
677       sdp_message_t_time_descr_add (*dest, osip_strdup (tmp),
678                                     osip_strdup (tmp2));
679     if (i != 0)
680       return -1;
681   }
682   if (config->fcn_set_attributes != NULL)
683     config->fcn_set_attributes (con, *dest, -1);
684   return 0;
685 }
686
687 static int
688 sdp_confirm_media (osip_negotiation_t * config,
689                    osip_negotiation_ctx_t * context, sdp_message_t * remote,
690                    sdp_message_t ** dest)
691 {
692   char *payload;
693   char *tmp, *tmp2, *tmp3, *tmp4;
694   int ret;
695   int i;
696   int k;
697   int audio_qty = 0;            /* accepted audio line: do not accept more than one */
698   int video_qty = 0;
699
700   i = 0;
701   while (!sdp_message_endof_media (remote, i))
702     {
703       tmp = sdp_message_m_media_get (remote, i);
704       tmp2 = sdp_message_m_port_get (remote, i);
705       tmp3 = sdp_message_m_number_of_port_get (remote, i);
706       tmp4 = sdp_message_m_proto_get (remote, i);
707
708       if (tmp == NULL)
709         return -1;
710       sdp_message_m_media_add (*dest, osip_strdup (tmp), osip_strdup ("0"),
711                                NULL, osip_strdup (tmp4));
712       k = 0;
713       if (0 == strncmp (tmp, "audio", 5))
714         {
715           do
716             {
717               payload = sdp_message_m_payload_get (remote, i, k);
718               if (payload != NULL)
719                 {
720                   __payload_t *my_payload =
721                     osip_negotiation_find_audio_payload (config, payload);
722
723                   if (my_payload != NULL)       /* payload is supported */
724                     {
725                       ret = -1; /* somtimes, codec can be refused even if supported */
726                       if (config->fcn_accept_audio_codec != NULL)
727                         ret = config->fcn_accept_audio_codec (context, tmp2,
728                                                               tmp3, audio_qty,
729                                                               payload);
730                       if (0 == ret)
731                         {
732                           sdp_message_m_payload_add (*dest, i,
733                                                      osip_strdup (payload));
734                           if (my_payload->a_rtpmap != NULL)
735                             sdp_message_a_attribute_add (*dest, i,
736                                                          osip_strdup
737                                                          ("rtpmap"),
738                                                          osip_strdup
739                                                          (my_payload->
740                                                           a_rtpmap));
741                           if (my_payload->c_nettype != NULL)
742                             {
743                               sdp_media_t *med =
744                                 osip_list_get ((*dest)->m_medias, i);
745
746                               if (osip_list_eol (med->c_connections, 0))
747                                 sdp_message_c_connection_add (*dest, i,
748                                                               osip_strdup
749                                                               (my_payload->
750                                                                c_nettype),
751                                                               osip_strdup
752                                                               (my_payload->
753                                                                c_addrtype),
754                                                               osip_strdup
755                                                               (my_payload->
756                                                                c_addr),
757                                                               osip_strdup
758                                                               (my_payload->
759                                                                c_addr_multicast_ttl),
760                                                               osip_strdup
761                                                               (my_payload->
762                                                                c_addr_multicast_int));
763                             }
764                         }
765                     }
766                 }
767               k++;
768             }
769           while (payload != NULL);
770           if (NULL != sdp_message_m_payload_get (*dest, i, 0))
771             audio_qty = 1;
772         }
773       else if (0 == strncmp (tmp, "video", 5))
774         {
775           do
776             {
777               payload = sdp_message_m_payload_get (remote, i, k);
778               if (payload != NULL)
779                 {
780                   __payload_t *my_payload =
781                     osip_negotiation_find_video_payload (config, payload);
782
783                   if (my_payload != NULL)       /* payload is supported */
784                     {
785                       ret = -1;
786                       if (config->fcn_accept_video_codec != NULL)
787                         ret =
788                           config->fcn_accept_video_codec (context, tmp2, tmp3,
789                                                           video_qty, payload);
790                       if (0 == ret)
791                         {
792                           sdp_message_m_payload_add (*dest, i,
793                                                      osip_strdup (payload));
794                           /* TODO  set the attribute list (rtpmap..) */
795                           if (my_payload->a_rtpmap != NULL)
796                             sdp_message_a_attribute_add (*dest, i,
797                                                          osip_strdup
798                                                          ("rtpmap"),
799                                                          osip_strdup
800                                                          (my_payload->
801                                                           a_rtpmap));
802                           if (my_payload->c_nettype != NULL)
803                             {
804                               sdp_media_t *med =
805                                 osip_list_get ((*dest)->m_medias, i);
806
807                               if (osip_list_eol (med->c_connections, 0))
808                                 sdp_message_c_connection_add (*dest, i,
809                                                               osip_strdup
810                                                               (my_payload->
811                                                                c_nettype),
812                                                               osip_strdup
813                                                               (my_payload->
814                                                                c_addrtype),
815                                                               osip_strdup
816                                                               (my_payload->
817                                                                c_addr),
818                                                               osip_strdup
819                                                               (my_payload->
820                                                                c_addr_multicast_ttl),
821                                                               osip_strdup
822                                                               (my_payload->
823                                                                c_addr_multicast_int));
824                             }
825                         }
826                     }
827                 }
828               k++;
829             }
830           while (payload != NULL);
831           if (NULL != sdp_message_m_payload_get (*dest, i, 0))
832             video_qty = 1;
833         }
834       else
835         {
836           do
837             {
838               payload = sdp_message_m_payload_get (remote, i, k);
839               if (payload != NULL)
840                 {
841                   __payload_t *my_payload =
842                     osip_negotiation_find_other_payload (config, payload);
843
844                   if (my_payload != NULL)       /* payload is supported */
845                     {
846                       ret = -1;
847                       if (config->fcn_accept_other_codec != NULL)
848                         ret =
849                           config->fcn_accept_other_codec (context, tmp, tmp2,
850                                                           tmp3, payload);
851                       if (0 == ret)
852                         {
853                           sdp_message_m_payload_add (*dest, i,
854                                                      osip_strdup (payload));
855                           /* rtpmap has no meaning here! */
856                           if (my_payload->c_nettype != NULL)
857                             {
858                               sdp_media_t *med =
859                                 osip_list_get ((*dest)->m_medias, i);
860
861                               if (osip_list_eol (med->c_connections, 0))
862                                 sdp_message_c_connection_add (*dest, i,
863                                                               osip_strdup
864                                                               (my_payload->
865                                                                c_nettype),
866                                                               osip_strdup
867                                                               (my_payload->
868                                                                c_addrtype),
869                                                               osip_strdup
870                                                               (my_payload->
871                                                                c_addr),
872                                                               osip_strdup
873                                                               (my_payload->
874                                                                c_addr_multicast_ttl),
875                                                               osip_strdup
876                                                               (my_payload->
877                                                                c_addr_multicast_int));
878                             }
879                         }
880                     }
881                 }
882               k++;
883             }
884           while (payload != NULL);
885         }
886       i++;
887     }
888   return 0;
889 }
890
891 int
892 osip_negotiation_ctx_execute_negotiation (osip_negotiation_t * config,
893                                           osip_negotiation_ctx_t * context)
894 {
895   int m_lines_that_match = 0;
896   sdp_message_t *remote;
897   sdp_message_t *local;
898   int i;
899
900   if (context == NULL)
901     return -1;
902   remote = context->remote;
903   if (remote == NULL)
904     return -1;
905
906   i = sdp_message_init (&local);
907   if (i != 0)
908     return -1;
909
910   if (0 != strncmp (remote->v_version, "0", 1))
911     {
912       sdp_message_free (local);
913       /*      sdp_context->fcn_wrong_version(context); */
914       return 406;               /* Not Acceptable */
915     }
916
917   i = sdp_partial_clone (config, context, remote, &local);
918   if (i != 0)
919     {
920       sdp_message_free (local);
921       return -1;
922     }
923   i = sdp_confirm_media (config, context, remote, &local);
924   if (i != 0)
925     {
926       sdp_message_free (local);
927       return i;
928     }
929
930   i = 0;
931   while (!sdp_message_endof_media (local, i))
932     {
933       /* this is to refuse each line with no codec that matches! */
934       if (NULL == sdp_message_m_payload_get (local, i, 0))
935         {
936           sdp_media_t *med = osip_list_get ((local)->m_medias, i);
937           char *str = sdp_message_m_payload_get (remote, i, 0);
938
939           sdp_message_m_payload_add (local, i, osip_strdup (str));
940           osip_free (med->m_port);
941           med->m_port = osip_strdup ("0");      /* refuse this line */
942         }
943       else
944         {                       /* number of "m" lines that match */
945           sdp_media_t *med = osip_list_get (local->m_medias, i);
946
947           m_lines_that_match++;
948           osip_free (med->m_port);
949           /* AMD: use the correct fcn_get_xxx_port method: */
950           if (0 == strcmp (med->m_media, "audio"))
951             {
952               if (config->fcn_get_audio_port != NULL)
953                 med->m_port = config->fcn_get_audio_port (context, i);
954               else
955                 med->m_port = osip_strdup ("0");        /* should never happen */
956             }
957           else if (0 == strcmp (med->m_media, "video"))
958             {
959               if (config->fcn_get_video_port != NULL)
960                 med->m_port = config->fcn_get_video_port (context, i);
961               else
962                 med->m_port = osip_strdup ("0");        /* should never happen */
963             }
964           else
965             {
966               if (config->fcn_get_other_port != NULL)
967                 med->m_port = config->fcn_get_other_port (context, i);
968               else
969                 med->m_port = osip_strdup ("0");        /* should never happen */
970             }
971         }
972       i++;
973     }
974   if (m_lines_that_match > 0)
975     {
976       context->local = local;
977       return 200;
978     }
979   else
980     {
981       sdp_message_free (local);
982       return 415;
983     }
984
985 }
986
987 int
988 osip_negotiation_sdp_build_offer (osip_negotiation_t * config,
989                                   osip_negotiation_ctx_t * con,
990                                   sdp_message_t ** sdp, char *audio_port,
991                                   char *video_port)
992 {
993   int i;
994   int media_line = 0;
995
996   i = sdp_message_init (sdp);
997   if (i != 0)
998     return -1;
999
1000   sdp_message_v_version_set (*sdp, osip_strdup ("0"));
1001
1002   /* those fields MUST be set */
1003   sdp_message_o_origin_set (*sdp,
1004                             osip_strdup (config->o_username),
1005                             osip_strdup (config->o_session_id),
1006                             osip_strdup (config->o_session_version),
1007                             osip_strdup (config->o_nettype),
1008                             osip_strdup (config->o_addrtype),
1009                             osip_strdup (config->o_addr));
1010   sdp_message_s_name_set (*sdp, osip_strdup ("A call"));
1011   if (config->fcn_set_info != NULL)
1012     config->fcn_set_info (con, *sdp);
1013   if (config->fcn_set_uri != NULL)
1014     config->fcn_set_uri (con, *sdp);
1015   if (config->fcn_set_emails != NULL)
1016     config->fcn_set_emails (con, *sdp);
1017   if (config->fcn_set_phones != NULL)
1018     config->fcn_set_phones (con, *sdp);
1019   if (config->c_nettype != NULL)
1020     sdp_message_c_connection_add (*sdp, -1,
1021                                   osip_strdup (config->c_nettype),
1022                                   osip_strdup (config->c_addrtype),
1023                                   osip_strdup (config->c_addr),
1024                                   osip_strdup (config->c_addr_multicast_ttl),
1025                                   osip_strdup (config->c_addr_multicast_int));
1026
1027   {                             /* offer-answer draft says we must copy the "t=" line */
1028     int now = time (NULL);
1029     char *tmp = osip_malloc (15);
1030     char *tmp2 = osip_malloc (15);
1031
1032     sprintf (tmp, "%i", now);
1033     sprintf (tmp2, "%i", now + 3600);
1034
1035     i = sdp_message_t_time_descr_add (*sdp, tmp, tmp2);
1036     if (i != 0)
1037       return -1;
1038   }
1039   if (config->fcn_set_attributes != NULL)
1040     config->fcn_set_attributes (con, *sdp, -1);
1041
1042
1043   /* add all audio codec */
1044   if (!osip_list_eol (config->audio_codec, 0))
1045     {
1046       int pos = 0;
1047       __payload_t *my =
1048         (__payload_t *) osip_list_get (config->audio_codec, pos);
1049
1050       /* all media MUST have the same PROTO, PORT. */
1051       sdp_message_m_media_add (*sdp, osip_strdup ("audio"),
1052                                osip_strdup (audio_port),
1053                                osip_strdup (my->number_of_port),
1054                                osip_strdup (my->proto));
1055
1056       while (!osip_list_eol (config->audio_codec, pos))
1057         {
1058           my = (__payload_t *) osip_list_get (config->audio_codec, pos);
1059           sdp_message_m_payload_add (*sdp, media_line,
1060                                      osip_strdup (my->payload));
1061           if (my->a_rtpmap != NULL)
1062             sdp_message_a_attribute_add (*sdp, media_line,
1063                                          osip_strdup ("rtpmap"),
1064                                          osip_strdup (my->a_rtpmap));
1065           pos++;
1066         }
1067       media_line++;
1068     }
1069
1070   /* add all video codec */
1071   if (!osip_list_eol (config->video_codec, 0))
1072     {
1073       int pos = 0;
1074       __payload_t *my =
1075         (__payload_t *) osip_list_get (config->video_codec, pos);
1076
1077       /* all media MUST have the same PROTO, PORT. */
1078       sdp_message_m_media_add (*sdp, osip_strdup ("video"),
1079                                osip_strdup (video_port),
1080                                osip_strdup (my->number_of_port),
1081                                osip_strdup (my->proto));
1082
1083       while (!osip_list_eol (config->video_codec, pos))
1084         {
1085           my = (__payload_t *) osip_list_get (config->video_codec, pos);
1086           sdp_message_m_payload_add (*sdp, media_line,
1087                                      osip_strdup (my->payload));
1088           if (my->a_rtpmap != NULL)
1089             sdp_message_a_attribute_add (*sdp, media_line,
1090                                          osip_strdup ("rtpmap"),
1091                                          osip_strdup (my->a_rtpmap));
1092           pos++;
1093         }
1094       media_line++;
1095     }
1096   return 0;
1097 }
1098
1099 /* build the SDP packet with only one audio codec and one video codec.
1100  * - Usefull if you don't want to restrict proposal to one codec only -
1101  * - Limitation, only one codec will be proposed
1102  */
1103 int
1104 __osip_negotiation_sdp_build_offer (osip_negotiation_t * config,
1105                                     osip_negotiation_ctx_t * con,
1106                                     sdp_message_t ** sdp, char *audio_port,
1107                                     char *video_port, char *audio_codec,
1108                                     char *video_codec)
1109 {
1110   int i;
1111   int media_line = 0;
1112
1113   i = sdp_message_init (sdp);
1114   if (i != 0)
1115     return -1;
1116
1117   sdp_message_v_version_set (*sdp, osip_strdup ("0"));
1118
1119   /* those fields MUST be set */
1120   sdp_message_o_origin_set (*sdp,
1121                             osip_strdup (config->o_username),
1122                             osip_strdup (config->o_session_id),
1123                             osip_strdup (config->o_session_version),
1124                             osip_strdup (config->o_nettype),
1125                             osip_strdup (config->o_addrtype),
1126                             osip_strdup (config->o_addr));
1127   sdp_message_s_name_set (*sdp, osip_strdup ("A call"));
1128   if (config->fcn_set_info != NULL)
1129     config->fcn_set_info (con, *sdp);
1130   if (config->fcn_set_uri != NULL)
1131     config->fcn_set_uri (con, *sdp);
1132   if (config->fcn_set_emails != NULL)
1133     config->fcn_set_emails (con, *sdp);
1134   if (config->fcn_set_phones != NULL)
1135     config->fcn_set_phones (con, *sdp);
1136   if (config->c_nettype != NULL)
1137     sdp_message_c_connection_add (*sdp, -1,
1138                                   osip_strdup (config->c_nettype),
1139                                   osip_strdup (config->c_addrtype),
1140                                   osip_strdup (config->c_addr),
1141                                   osip_strdup (config->c_addr_multicast_ttl),
1142                                   osip_strdup (config->c_addr_multicast_int));
1143
1144   {                             /* offer-answer draft says we must copy the "t=" line */
1145     int now = time (NULL);
1146     char *tmp = osip_malloc (15);
1147     char *tmp2 = osip_malloc (15);
1148
1149     sprintf (tmp, "%i", now);
1150     sprintf (tmp2, "%i", now + 3600);
1151
1152     i = sdp_message_t_time_descr_add (*sdp, tmp, tmp2);
1153     if (i != 0)
1154       return -1;
1155   }
1156   if (config->fcn_set_attributes != NULL)
1157     config->fcn_set_attributes (con, *sdp, -1);
1158
1159
1160   /* add all audio codec */
1161   if (audio_codec != NULL)
1162     {
1163       if (!osip_list_eol (config->audio_codec, 0))
1164         {
1165           int pos = 0;
1166           __payload_t *my =
1167             (__payload_t *) osip_list_get (config->audio_codec, pos);
1168
1169           while (!osip_list_eol (config->audio_codec, pos))
1170             {
1171               my = (__payload_t *) osip_list_get (config->audio_codec, pos);
1172               if (0 == strcmp (audio_codec, my->payload))
1173                 {
1174                   /* all media MUST have the same PROTO, PORT. */
1175                   sdp_message_m_media_add (*sdp, osip_strdup ("audio"),
1176                                            osip_strdup (audio_port),
1177                                            osip_strdup (my->number_of_port),
1178                                            osip_strdup (my->proto));
1179                   sdp_message_m_payload_add (*sdp, media_line,
1180                                              osip_strdup (my->payload));
1181                   if (my->a_rtpmap != NULL)
1182                     sdp_message_a_attribute_add (*sdp, media_line,
1183                                                  osip_strdup ("rtpmap"),
1184                                                  osip_strdup (my->a_rtpmap));
1185                   media_line++;
1186                   break;
1187                 }
1188               pos++;
1189             }
1190         }
1191     }
1192
1193   /* add all video codec */
1194   if (video_codec != NULL)
1195     {
1196       if (!osip_list_eol (config->video_codec, 0))
1197         {
1198           int pos = 0;
1199           __payload_t *my =
1200             (__payload_t *) osip_list_get (config->video_codec, pos);
1201
1202           while (!osip_list_eol (config->video_codec, pos))
1203             {
1204               my = (__payload_t *) osip_list_get (config->video_codec, pos);
1205               if (0 == strcmp (video_codec, my->payload))
1206                 {
1207                   /* all media MUST have the same PROTO, PORT. */
1208                   sdp_message_m_media_add (*sdp, osip_strdup ("video"),
1209                                            osip_strdup (video_port),
1210                                            osip_strdup (my->number_of_port),
1211                                            osip_strdup (my->proto));
1212                   sdp_message_m_payload_add (*sdp, media_line,
1213                                              osip_strdup (my->payload));
1214                   if (my->a_rtpmap != NULL)
1215                     sdp_message_a_attribute_add (*sdp, media_line,
1216                                                  osip_strdup ("rtpmap"),
1217                                                  osip_strdup (my->a_rtpmap));
1218                   media_line++;
1219                   break;
1220                 }
1221               pos++;
1222             }
1223         }
1224     }
1225   return 0;
1226 }
1227
1228
1229 int
1230 osip_negotiation_sdp_message_put_on_hold (sdp_message_t * sdp)
1231 {
1232   int pos;
1233   int pos_media = -1;
1234   char *rcvsnd;
1235   int recv_send = -1;
1236
1237   pos = 0;
1238   rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1239   while (rcvsnd != NULL)
1240     {
1241       if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly"))
1242         {
1243           recv_send = 0;
1244         }
1245       else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly")
1246                                   || 0 == strcmp (rcvsnd, "sendrecv")))
1247         {
1248           recv_send = 0;
1249           sprintf (rcvsnd, "sendonly");
1250         }
1251       pos++;
1252       rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1253     }
1254
1255   pos_media = 0;
1256   while (!sdp_message_endof_media (sdp, pos_media))
1257     {
1258       pos = 0;
1259       rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1260       while (rcvsnd != NULL)
1261         {
1262           if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly"))
1263             {
1264               recv_send = 0;
1265             }
1266           else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly")
1267                                       || 0 == strcmp (rcvsnd, "sendrecv")))
1268             {
1269               recv_send = 0;
1270               sprintf (rcvsnd, "sendonly");
1271             }
1272           pos++;
1273           rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1274         }
1275       pos_media++;
1276     }
1277
1278   if (recv_send == -1)
1279     {
1280       /* we need to add a global attribute with a field set to "sendonly" */
1281       sdp_message_a_attribute_add (sdp, -1, osip_strdup ("sendonly"), NULL);
1282     }
1283
1284   return 0;
1285 }
1286
1287 int
1288 osip_negotiation_sdp_message_put_off_hold (sdp_message_t * sdp)
1289 {
1290   int pos;
1291   int pos_media = -1;
1292   char *rcvsnd;
1293
1294   pos = 0;
1295   rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1296   while (rcvsnd != NULL)
1297     {
1298       if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly")
1299                              || 0 == strcmp (rcvsnd, "recvonly")))
1300         {
1301           sprintf (rcvsnd, "sendrecv");
1302         }
1303       pos++;
1304       rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1305     }
1306
1307   pos_media = 0;
1308   while (!sdp_message_endof_media (sdp, pos_media))
1309     {
1310       pos = 0;
1311       rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1312       while (rcvsnd != NULL)
1313         {
1314           if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly")
1315                                  || 0 == strcmp (rcvsnd, "recvonly")))
1316             {
1317               sprintf (rcvsnd, "sendrecv");
1318             }
1319           pos++;
1320           rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos);
1321         }
1322       pos_media++;
1323     }
1324
1325   return 0;
1326 }