sal_op_call.c 28.3 KB
Newer Older
jehan's avatar
jehan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
linphone
Copyright (C) 2012  Belledonne Communications, Grenoble, France

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "sal_impl.h"
jehan's avatar
jehan committed
20
#include "offeranswer.h"
jehan's avatar
jehan committed
21

22 23 24 25
static void call_set_released(SalOp* op){
	op->state=SalOpStateTerminated;
	op->base.root->callbacks.call_released(op);
}
jehan's avatar
jehan committed
26 27 28 29
static void call_set_released_and_unref(SalOp* op) {
	call_set_released(op);
	sal_op_unref(op);
}
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
static void call_set_error(SalOp* op,belle_sip_response_t* response){
	SalError error=SalErrorUnknown;
	SalReason sr=SalReasonUnknown;
	belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
	char* reason=(char*)belle_sip_response_get_reason_phrase(response);
	int code = belle_sip_response_get_status_code(response);
	if (reason_header){
		reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header)));
	}
	sal_compute_sal_errors_from_code(code,&error,&sr);
	op->base.root->callbacks.call_failure(op,error,sr,reason,code);
	if (reason_header != NULL){
		ms_free(reason);
	}
	call_set_released(op);
}
46

jehan's avatar
jehan committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60
static void sdp_process(SalOp *h){
	ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming");
	if (h->result){
		sal_media_description_unref(h->result);
	}
	h->result=sal_media_description_new();
	if (h->sdp_offering){
		offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);
	}else{
		int i;
		if (h->sdp_answer){
			belle_sip_object_unref(h->sdp_answer);
		}
		offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);
61
		h->sdp_answer=(belle_sdp_session_description_t *)belle_sip_object_ref(media_description_to_sdp(h->result));
jehan's avatar
jehan committed
62 63 64 65 66
		/*once we have generated the SDP answer, we modify the result description for processing by the upper layer.
		 It should contains media parameters constraint from the remote offer, not our response*/
		strcpy(h->result->addr,h->base.remote_media->addr);
		h->result->bandwidth=h->base.remote_media->bandwidth;

67 68 69 70 71 72
		for(i=0;i<h->result->n_active_streams;++i){
			/*fixme add rtcp*/
			strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
			h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
			h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
			h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
jehan's avatar
jehan committed
73

74 75
			if (h->result->streams[i].proto == SalProtoRtpSavp) {
				h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
jehan's avatar
jehan committed
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
			}
		}
	}

}
static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) {
	belle_sip_header_content_type_t* content_type ;
	belle_sip_header_content_length_t* content_length;
	int length;
	char buff[1024];

	if (session_desc) {
		content_type = belle_sip_header_content_type_create("application","sdp");
		length = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,0,sizeof(buff));
		if (length==sizeof(buff)) {
			ms_error("Buffer too small or sdp too big");
		}

		content_length= belle_sip_header_content_length_create(length);
		belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_type));
		belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_length));
		belle_sip_message_set_body(msg,buff,length);
		return 0;
	} else {
		return -1;
	}
}
static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){
	return set_sdp(msg,media_description_to_sdp(desc));

}
jehan's avatar
jehan committed
107
static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
jehan's avatar
jehan committed
108 109 110 111
	SalOp* op=(SalOp*)user_ctx;
	if (!op->dialog)  {
		/*call terminated very early*/
		op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503);
112
		call_set_released(op);
jehan's avatar
jehan committed
113 114 115
	} else {
		/*dialog will terminated shortly, nothing to do*/
	}
jehan's avatar
jehan committed
116
}
jehan's avatar
jehan committed
117 118
static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
	SalOp* op=(SalOp*)ctx;
119

120
	if (op->dialog && op->dialog==belle_sip_dialog_terminated_get_dialog(event))  {
jehan's avatar
jehan committed
121 122
		belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog);

123 124 125 126 127 128 129 130
		switch(belle_sip_dialog_get_previous_state(op->dialog)) {
		case BELLE_SIP_DIALOG_CONFIRMED:
			if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) {
				/*this is probably a "normal termination from a BYE*/
				op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
				op->state=SalOpStateTerminating;
			}
			break;
jehan's avatar
jehan committed
131 132 133 134 135 136
		case BELLE_SIP_DIALOG_NULL: {
			if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_server_transaction_t)) {
				/*call declined very early, no need to notify call release*/
				break;
			}
		}
137
		default: {
jehan's avatar
jehan committed
138

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
			belle_sip_response_t* response=belle_sip_transaction_get_response(trans);
			int code = belle_sip_response_get_status_code(response);
			if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(trans,belle_sip_client_transaction_t)) {
				switch (code) {
				case 487:
					call_set_released(op);
					break;
				case 401:
				case 407:
					if (op->state!=SalOpStateTerminating) {
						/*normal termination for chalanged dialog */
						break;
					}
				default:
					call_set_error(op,response);
				}
			} else {
jehan's avatar
jehan committed
156
				sal_op_ref(op); /*to make sure op is still there when call released is scheduled*/
157
				belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack)
jehan's avatar
jehan committed
158
											,(belle_sip_callback_t) call_set_released_and_unref
159 160
											, op);
			}
161

162 163
		}
		}
164
		belle_sip_object_unref(op->dialog);
jehan's avatar
jehan committed
165
		op->dialog=NULL;
166 167 168
		sal_op_unref(op);
	} else {
		ms_error("dialog unknown for op ");
jehan's avatar
jehan committed
169
	}
170 171 172 173

	ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_get_dialog(event)
													,op);

jehan's avatar
jehan committed
174
}
jehan's avatar
jehan committed
175 176 177 178 179 180 181 182
static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) {
	belle_sdp_session_description_t* sdp;
	if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) {
		op->base.remote_media=sal_media_description_new();
		sdp_to_media_description(sdp,op->base.remote_media);
		if (op->base.local_media) sdp_process(op);
	}
}
jehan's avatar
jehan committed
183 184 185
static void cancelling_invite(SalOp* op ){
	belle_sip_request_t* cancel;
	ms_message("Cancelling INVITE requets from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op));
186
	cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans);
jehan's avatar
jehan committed
187
	sal_op_send_request(op,cancel);
188
	op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
189
}
jehan's avatar
jehan committed
190 191 192 193
static void call_response_event(void *op_base, const belle_sip_response_event_t *event){
	SalOp* op = (SalOp*)op_base;
	belle_sip_request_t* ack;
	belle_sip_dialog_state_t dialog_state;
jehan's avatar
jehan committed
194
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
195
	belle_sip_request_t* req;
jehan's avatar
jehan committed
196 197
	belle_sip_response_t* response=belle_sip_response_event_get_response(event);
	int code = belle_sip_response_get_status_code(response);
198 199


jehan's avatar
jehan committed
200 201 202 203
	if (!client_transaction) {
		ms_warning("Discarding state less response [%i] on op [%p]",code,op);
		return;
	}
204
	req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
205
	set_or_update_dialog(op,belle_sip_response_event_get_dialog(event));
206
	dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
jehan's avatar
jehan committed
207

jehan's avatar
jehan committed
208 209
		switch(dialog_state) {

210
		case BELLE_SIP_DIALOG_NULL:
jehan's avatar
jehan committed
211
		case BELLE_SIP_DIALOG_EARLY: {
212 213 214 215 216 217 218 219 220 221
			if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) {
				if ( op->state == SalOpStateTerminating) {
					if (code <200) {
						cancelling_invite(op);
					} else if (code<400) {
						sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
					} else {
						/*nop ?*/
					}
					break;
jehan's avatar
jehan committed
222
				} else if (code >= 180 && code<300) {
223 224 225
					handle_sdp_from_response(op,response);
					op->base.root->callbacks.call_ringing(op);
					break;
jehan's avatar
jehan committed
226 227 228 229 230 231 232
				} else if (code>=300){
					if (dialog_state==BELLE_SIP_DIALOG_NULL) {
						call_set_error(op,response);
						break;
					} else {
					/*nop let process_dialog_terminated manage error reporting*/
					}
233 234 235 236 237
				}

			} else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0
						|| strcmp("BYE",belle_sip_request_get_method(req))==0) {
				break;/*200ok for cancel or BYE*/
jehan's avatar
jehan committed
238
			} else {
239
				/*nop error*/
jehan's avatar
jehan committed
240
			}
241
			ms_error("call op [%p] receive an unexpected answer [%i]",op,code);
jehan's avatar
jehan committed
242 243 244
		}
		case BELLE_SIP_DIALOG_CONFIRMED: {
			switch (op->state) {
jehan's avatar
jehan committed
245 246
			case SalOpStateEarly:/*invite case*/
			case SalOpStateActive: /*re-invite case*/
jehan's avatar
jehan committed
247 248
				if (code >=200
					&& code<300
249
					&& strcmp("INVITE",belle_sip_request_get_method(req))==0) {
jehan's avatar
jehan committed
250 251 252 253 254 255 256 257 258 259 260 261
					handle_sdp_from_response(op,response);
					ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog));
					if (ack==NULL) {
						ms_error("This call has been already terminated.");

						return ;
					}
					if (op->sdp_answer){
						set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer);
						op->sdp_answer=NULL;
					}
					belle_sip_dialog_send_ack(op->dialog,ack);
jehan's avatar
jehan committed
262 263
					op->base.root->callbacks.call_accepted(op); /*INVITE*/

jehan's avatar
jehan committed
264
					op->state=SalOpStateActive;
265
				}  else {
jehan's avatar
jehan committed
266
					/*nop*/
jehan's avatar
jehan committed
267
				}
jehan's avatar
jehan committed
268
			break;
269 270
			case SalOpStateTerminating:
				//FIXME send bye
jehan's avatar
jehan committed
271 272
			case SalOpStateTerminated:
			default:
273
				ms_error("call op [%p] receive answer [%i] not implemented",op,code);
jehan's avatar
jehan committed
274 275 276
			}
		break;
		}
277 278 279 280 281 282 283 284 285 286
		case BELLE_SIP_DIALOG_TERMINATED: {
			/*if (code>=400 && strcmp("INVITE",belle_sip_request_get_method(req))==0){
				call_set_error(op,response);
				call_set_released(op);
				op->state=SalOpStateTerminated;
			break;
			}*/
			break;
		}
		/* no break */
jehan's avatar
jehan committed
287
		default: {
288
			ms_error("call op [%p] receive answer [%i] not implemented",op,code);
jehan's avatar
jehan committed
289 290 291 292 293
		}
		/* no break */
	}


jehan's avatar
jehan committed
294
}
295

jehan's avatar
jehan committed
296
static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
297 298 299 300
	SalOp* op=(SalOp*)user_ctx;
	if (!op->dialog)  {
		/*call terminated very early*/
		op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408);
301
		call_set_released(op);
302 303 304 305
		op->state=SalOpStateTerminated;
	} else {
		/*dialog will terminated shortly, nothing to do*/
	}
jehan's avatar
jehan committed
306 307
}
static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
308 309 310 311 312 313 314 315 316 317 318 319
	SalOp* op = (SalOp*)user_ctx;
	belle_sip_client_transaction_t *client_transaction=belle_sip_transaction_terminated_event_get_client_transaction(event);
	belle_sip_server_transaction_t *server_transaction=belle_sip_transaction_terminated_event_get_server_transaction(event);
	belle_sip_request_t* req;
	belle_sip_response_t* resp;
	if (client_transaction) {
		req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
		resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction));
	} else {
		req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction));
		resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction));
	}
320 321
	if (op->state ==SalOpStateTerminating &&
			strcmp("BYE",belle_sip_request_get_method(req))==0
322 323
					&& (!resp || (belle_sip_response_get_status_code(resp) !=401
									&& belle_sip_response_get_status_code(resp) !=407))) {
324

325
		call_set_released(op);
326 327
	}

jehan's avatar
jehan committed
328
}
jehan's avatar
jehan committed
329 330 331 332 333
static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_transaction, belle_sip_request_t* request,int status_code) {
	belle_sip_response_t* resp;
	op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
	resp=belle_sip_response_create_from_request(request,status_code);
	belle_sip_server_transaction_send_response(server_transaction,resp);
334

jehan's avatar
jehan committed
335 336 337 338 339 340 341 342 343
	return;
}
static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) {
	belle_sip_response_t* resp;
	resp=belle_sip_response_create_from_request(request,500);
	belle_sip_server_transaction_send_response(server_transaction,resp);
	return;
}

jehan's avatar
jehan committed
344 345 346 347 348 349 350 351 352 353
static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
	belle_sdp_session_description_t* sdp;
	if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(invite)))) {
		op->sdp_offering=FALSE;
		op->base.remote_media=sal_media_description_new();
		sdp_to_media_description(sdp,op->base.remote_media);
		belle_sip_object_unref(sdp);
	}else
		op->sdp_offering=TRUE;
}
jehan's avatar
jehan committed
354 355 356
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
	SalOp* op = (SalOp*)op_base;
	belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
jehan's avatar
jehan committed
357
	belle_sdp_session_description_t* sdp;
jehan's avatar
jehan committed
358 359
	belle_sip_request_t* req = belle_sip_request_event_get_request(event);
	belle_sip_dialog_state_t dialog_state;
360
	belle_sip_response_t* resp;
jehan's avatar
jehan committed
361
	belle_sip_header_t* call_info;
jehan's avatar
jehan committed
362

363 364 365 366 367 368
	if (server_transaction){
		belle_sip_object_ref(server_transaction); /*ACK does'nt create srv transaction*/
		belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op);
		sal_op_ref(op);
	}

369 370 371 372
	if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
		if (op->pending_server_trans)belle_sip_object_unref(op->pending_server_trans);
		/*updating pending invite transaction*/
		op->pending_server_trans=server_transaction;
373
		belle_sip_object_ref(op->pending_server_trans);
374 375
	}

jehan's avatar
jehan committed
376
	if (!op->dialog) {
377
		set_or_update_dialog(op,belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)));
jehan's avatar
jehan committed
378 379 380 381 382 383
		ms_message("new incoming call from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
	}
	dialog_state=belle_sip_dialog_get_state(op->dialog);
	switch(dialog_state) {

	case BELLE_SIP_DIALOG_NULL: {
384 385 386 387 388 389
		if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
			if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) {
				belle_sip_object_ref(op->replaces);
			} else if(op->replaces) {
				ms_warning("replace header already set");
			}
jehan's avatar
jehan committed
390

391
			process_sdp_for_invite(op,req);
jehan's avatar
jehan committed
392

393 394 395 396 397
			if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) {
				if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) {
					op->auto_answer_asked=TRUE;
					ms_message("The caller asked to automatically answer the call(Emergency?)\n");
				}
jehan's avatar
jehan committed
398 399
			}

400
			op->base.root->callbacks.call_received(op);
jehan's avatar
jehan committed
401

402 403
			break;
		} /* else same behavior as for EARLY state*/
jehan's avatar
jehan committed
404
	}
jehan's avatar
jehan committed
405 406 407 408 409 410 411
	case BELLE_SIP_DIALOG_EARLY: {
		//hmm probably a cancel
		if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) {
			if(belle_sip_request_event_get_server_transaction(event)) {
				/*first answer 200 ok to cancel*/
				belle_sip_server_transaction_send_response(server_transaction
															,belle_sip_response_create_from_request(req,200));
412
				/*terminate invite transaction*/
jehan's avatar
jehan committed
413
				call_terminated(op
414 415
								,op->pending_server_trans
								,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487);
jehan's avatar
jehan committed
416 417 418 419 420 421 422


			} else {
				/*call leg does not exist*/
				belle_sip_server_transaction_send_response(server_transaction
															,belle_sip_response_create_from_request(req,481));
			}
jehan's avatar
jehan committed
423 424 425
		} else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) {
			resp=belle_sip_response_create_from_request(req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
jehan's avatar
jehan committed
426 427
		} else {
			belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY");
428
			unsupported_method(server_transaction,req);
jehan's avatar
jehan committed
429 430 431
		}
		break;
	}
jehan's avatar
jehan committed
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
	case BELLE_SIP_DIALOG_CONFIRMED:
		/*great ACK received*/
		if (strcmp("ACK",belle_sip_request_get_method(req))==0) {
			if (op->sdp_offering){
				if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))){
					if (op->base.remote_media)
						sal_media_description_unref(op->base.remote_media);
					op->base.remote_media=sal_media_description_new();
					sdp_to_media_description(sdp,op->base.remote_media);
					sdp_process(op);
					belle_sip_object_unref(sdp);
				}
			}
			/*FIXME
		if (op->reinvite){
			op->reinvite=FALSE;
		}*/
			op->base.root->callbacks.call_ack(op);
		} else if(strcmp("BYE",belle_sip_request_get_method(req))==0) {
451 452
			resp=belle_sip_response_create_from_request(req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
453 454 455
			op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
			op->state=SalOpStateTerminating;
			/*call end not notified by dialog deletion because transaction can end before dialog*/
jehan's avatar
jehan committed
456 457 458 459 460 461 462 463 464 465 466 467 468
		} else if(strcmp("INVITE",belle_sip_request_get_method(req))==0) {
			/*re-invite*/
			if (op->base.remote_media){
				sal_media_description_unref(op->base.remote_media);
				op->base.remote_media=NULL;
			}
			if (op->result){
				sal_media_description_unref(op->result);
				op->result=NULL;
			}
			process_sdp_for_invite(op,req);

			op->base.root->callbacks.call_updating(op);
jehan's avatar
jehan committed
469 470 471 472 473 474 475 476 477 478 479
		} else if (strcmp("INFO",belle_sip_request_get_method(req))==0
				&& belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))
				&&	strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) {
				/*vfu request*/
				ms_message("Receiving VFU request on op [%p]",op);
				if (op->base.root->callbacks.vfu_request){
					op->base.root->callbacks.vfu_request(op);

				}
				resp=belle_sip_response_create_from_request(req,200);
				belle_sip_server_transaction_send_response(server_transaction,resp);
480
		}else if (strcmp("REFER",belle_sip_request_get_method(req))==0) {
jehan's avatar
jehan committed
481 482 483
			sal_op_process_refer(op,event);
		} else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
			sal_op_call_process_notify(op,event);
jehan's avatar
jehan committed
484 485 486
		} else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) {
			resp=belle_sip_response_create_from_request(req,200);
			belle_sip_server_transaction_send_response(server_transaction,resp);
487
		} else{
jehan's avatar
jehan committed
488
			ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog);
489
			unsupported_method(server_transaction,req);
jehan's avatar
jehan committed
490 491
		}
		break;
jehan's avatar
jehan committed
492 493 494
	default: {
		ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
	}
jehan's avatar
jehan committed
495
	/* no break */
jehan's avatar
jehan committed
496 497
	}

498
	if (server_transaction) belle_sip_object_unref(server_transaction);
jehan's avatar
jehan committed
499

jehan's avatar
jehan committed
500 501
}

502

jehan's avatar
jehan committed
503 504 505 506 507 508 509 510 511
/*Call API*/
int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){
	if (desc)
		sal_media_description_ref(desc);
	if (op->base.local_media)
		sal_media_description_unref(op->base.local_media);
	op->base.local_media=desc;
	return 0;
}
jehan's avatar
jehan committed
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) {
	belle_sip_header_allow_t* header_allow;
	header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(header_allow));

	if (op->base.root->session_expires!=0){
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200"));
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer"));
	}
	if (op->base.local_media){
			op->sdp_offering=TRUE;
			set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media);
	}else op->sdp_offering=FALSE;
	return;
}
jehan's avatar
jehan committed
527
int sal_call(SalOp *op, const char *from, const char *to){
528
	belle_sip_request_t* invite;
jehan's avatar
jehan committed
529
	op->dir=SalOpDirOutgoing;
530

jehan's avatar
jehan committed
531 532 533
	sal_op_set_from(op,from);
	sal_op_set_to(op,to);

534
	ms_message("[%s] calling [%s] on op [%p]", from, to, op);
535
	invite=sal_op_build_request(op,"INVITE");
jehan's avatar
jehan committed
536

537
	sal_op_fill_invite(op,invite);
jehan's avatar
jehan committed
538

jehan's avatar
jehan committed
539
	sal_op_call_fill_cbs(op);
540 541 542 543 544 545
	if (op->replaces){
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->replaces));
			if (op->referred_by)
				belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->referred_by));
	}

jehan's avatar
jehan committed
546 547
	return sal_op_send_request(op,invite);

548

jehan's avatar
jehan committed
549
}
jehan's avatar
jehan committed
550 551 552 553 554 555
void sal_op_call_fill_cbs(SalOp*op) {
	op->callbacks.process_io_error=call_process_io_error;
	op->callbacks.process_response_event=call_response_event;
	op->callbacks.process_timeout=call_process_timeout;
	op->callbacks.process_transaction_terminated=call_process_transaction_terminated;
	op->callbacks.process_request_event=process_request_event;
jehan's avatar
jehan committed
556
	op->callbacks.process_dialog_terminated=process_dialog_terminated;
557
	op->type=SalOpCall;
jehan's avatar
jehan committed
558
}
jehan's avatar
jehan committed
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* response) {
	if (op->base.local_media){
		/*this is the case where we received an invite without SDP*/
		if (op->sdp_offering) {
			set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media);
		}else{
			if (op->sdp_answer==NULL) sdp_process(op);
			if (op->sdp_answer){
				set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer);
				op->sdp_answer=NULL;
			}
		}
	}else{
		ms_error("You are accepting a call but not defined any media capabilities !");
	}
}
jehan's avatar
jehan committed
575
int sal_call_notify_ringing(SalOp *op, bool_t early_media){
jehan's avatar
jehan committed
576
	int status_code =early_media?183:180;
jehan's avatar
jehan committed
577 578
	belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans));
	belle_sip_response_t* ringing_response = belle_sip_response_create_from_request(req,status_code);
jehan's avatar
jehan committed
579
	if (early_media){
jehan's avatar
jehan committed
580
		handle_offer_answer_response(op,ringing_response);
jehan's avatar
jehan committed
581
	}
jehan's avatar
jehan committed
582
	/*fixme it should support PRACK in the right way*/
583
	if (belle_sip_message_get_header((belle_sip_message_t*)req,"Require") || belle_sip_message_get_header((belle_sip_message_t*)req,"Supported")) {
jehan's avatar
jehan committed
584 585
		belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op);
		belle_sip_header_contact_t* contact_header;
586
		belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100Rel")));
jehan's avatar
jehan committed
587 588 589 590 591
		belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1")));
		if (contact && (contact_header=belle_sip_header_contact_create(contact))) {
				belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header));
		}
	}
jehan's avatar
jehan committed
592
	belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response);
jehan's avatar
jehan committed
593
	return 0;
jehan's avatar
jehan committed
594
}
jehan's avatar
jehan committed
595 596


jehan's avatar
jehan committed
597 598
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h){
jehan's avatar
jehan committed
599 600 601
	belle_sip_response_t *response;
	belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(h);
	belle_sip_header_contact_t* contact_header;
jehan's avatar
jehan committed
602 603 604 605 606 607

	if (!h->pending_server_trans) {
		ms_error("No transaction to accept for op [%p]",h);
		return -1;
	}

jehan's avatar
jehan committed
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
	/* sends a 200 OK */
	response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200);

	if (response==NULL){
		ms_error("Fail to build answer for call");
		return -1;
	}
	if (h->base.root->session_expires!=0){
		if (h->supports_session_timers) {
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create( "Supported", "timer"));
		}
	}

	if (contact && (contact_header=belle_sip_header_contact_create(contact))) {
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header));
	}

jehan's avatar
jehan committed
625 626
	handle_offer_answer_response(h,response);

jehan's avatar
jehan committed
627 628
	belle_sip_server_transaction_send_response(h->pending_server_trans,response);
	return 0;
jehan's avatar
jehan committed
629
}
jehan's avatar
jehan committed
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){
	belle_sip_response_t* response;
	belle_sip_header_contact_t* contact=NULL;
	int status;
	switch(reason) {
	case SalReasonBusy:
		status=486;
		break;
	case SalReasonTemporarilyUnavailable:
		status=480;
		break;
	case SalReasonDoNotDisturb:
		status=600;
		break;
	case SalReasonMedia:
		status=415;
		break;
jehan's avatar
jehan committed
647 648 649
	case SalReasonDeclined:
		status=603;
		break;
jehan's avatar
jehan committed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
	case SalReasonRedirect:
		if(redirection!=NULL) {
			if (strstr(redirection,"sip:")!=0) status=302;
			status=380;
			contact= belle_sip_header_contact_new();
			belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection));
			break;
		} else {
			ms_error("Cannot redirect to null");
		}
		/* no break */

	default:
		status=500;
		ms_error("Unexpected decline reason [%i]",reason);
		/* no break */
	}
	response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status);
	if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact));
	belle_sip_server_transaction_send_response(op->pending_server_trans,response);
	return 0;

jehan's avatar
jehan committed
672
}
jehan's avatar
jehan committed
673 674 675 676
int sal_call_update(SalOp *op, const char *subject){
	belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE");
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject));
	sal_op_fill_invite(op, reinvite);
jehan's avatar
jehan committed
677
	return sal_op_send_request(op,reinvite);
jehan's avatar
jehan committed
678 679
}
SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){
jehan's avatar
jehan committed
680
	return h->base.remote_media;;
jehan's avatar
jehan committed
681
}
jehan's avatar
jehan committed
682 683


jehan's avatar
jehan committed
684
SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
jehan's avatar
jehan committed
685 686 687 688
	if (h->base.local_media && h->base.remote_media && !h->result){
			sdp_process(h);
	}
	return h->result;
jehan's avatar
jehan committed
689 690 691 692 693
}
int sal_call_send_dtmf(SalOp *h, char dtmf){
	ms_fatal("sal_call_send_dtmf not implemented yet");
	return -1;
}
jehan's avatar
jehan committed
694
int sal_call_terminate(SalOp *op){
695
	belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/
jehan's avatar
jehan committed
696
	op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
697 698 699
	switch(dialog_state) {
		case BELLE_SIP_DIALOG_CONFIRMED: {
			sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
700
			op->state=SalOpStateTerminating;
jehan's avatar
jehan committed
701 702 703 704 705 706
			break;
		}
		case BELLE_SIP_DIALOG_NULL: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
707 708
			} else if (op->pending_client_trans
					&& belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){
jehan's avatar
jehan committed
709 710 711
				cancelling_invite(op);
				break;
			} else {
712 713 714 715
				/*just schedule call released*/
				belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack)
															,(belle_sip_callback_t) call_set_released
															, op);
jehan's avatar
jehan committed
716 717 718 719 720 721 722 723 724 725 726
			}
			break;
		}
		case BELLE_SIP_DIALOG_EARLY: {
			if (op->dir == SalOpDirIncoming) {
				sal_call_decline(op, SalReasonDeclined,NULL);
				op->state=SalOpStateTerminated;
			} else  {
				cancelling_invite(op);
			}
			break;
jehan's avatar
jehan committed
727 728 729 730 731 732 733
		}
		default: {
			ms_fatal("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
			return -1;
		}
	}
	return 0;
jehan's avatar
jehan committed
734 735
}
bool_t sal_call_autoanswer_asked(SalOp *op){
jehan's avatar
jehan committed
736
	return op->auto_answer_asked;
jehan's avatar
jehan committed
737
}
jehan's avatar
jehan committed
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
void sal_call_send_vfu_request(SalOp *op){
	char info_body[] =
			"<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
			 "<media_control>"
			 "  <vc_primitive>"
			 "    <to_encoder>"
			 "      <picture_fast_update></picture_fast_update>"
			 "    </to_encoder>"
			 "  </vc_primitive>"
			 "</media_control>";
	size_t content_lenth = sizeof(info_body) - 1;
	belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/
	if (dialog_state == BELLE_SIP_DIALOG_CONFIRMED) {
		belle_sip_request_t* info =	belle_sip_dialog_create_request(op->dialog,"INFO");
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","media_control+xml")));
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_lenth)));
		belle_sip_message_set_body(BELLE_SIP_MESSAGE(info),info_body,content_lenth);
		sal_op_send_request(op,info);
	} else {
		ms_warning("Cannot send vfu request to [%s] because dialog [%p] in wrong state [%s]",sal_op_get_to(op)
																							,op->dialog
																							,belle_sip_dialog_state_to_string(dialog_state));
	}

jehan's avatar
jehan committed
762 763 764 765 766 767
	return ;
}
int sal_call_is_offerer(const SalOp *h){
	return h->sdp_offering;
}

768 769 770 771 772 773 774
void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){
	ms_warning("sal_expire_old_registration_contacts not implemented ");
}

void sal_use_dates(Sal *ctx, bool_t enabled){
	ms_warning("sal_use_dates not implemented yet");
}
775 776