event.c 12.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
linphone
Copyright (C) 2000 - 2010 Simon MORLAT (simon.morlat@linphone.org)

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 "private.h"
21
#include "lpconfig.h"
22 23 24 25 26 27 28 29 30 31 32 33


LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){
	switch(ss){
		case SalSubscribeNone: return LinphoneSubscriptionNone;
		case SalSubscribePending: return LinphoneSubscriptionPending;
		case SalSubscribeTerminated: return LinphoneSubscriptionTerminated;
		case SalSubscribeActive: return LinphoneSubscriptionActive;
	}
	return LinphoneSubscriptionNone;
}

34 35 36 37
const char *linphone_subscription_state_to_string(LinphoneSubscriptionState state){
	switch(state){
		case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone";
		case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived";
38
		case LinphoneSubscriptionOutgoingInit: return "LinphoneSubscriptionOutoingInit";
39 40 41 42
		case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending";
		case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive";
		case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated";
		case LinphoneSubscriptionError: return "LinphoneSubscriptionError";
43
		case LinphoneSubscriptionExpiring: return "LinphoneSubscriptionExpiring";
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
	}
	return NULL;
}

LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishState state){
	switch(state){
		case LinphonePublishNone: return "LinphonePublishNone";
		case LinphonePublishProgress: return "LinphonePublishProgress";
		case LinphonePublishOk: return "LinphonePublishOk";
		case LinphonePublishError: return "LinphonePublishError";
		case LinphonePublishCleared: return "LinphonePublishCleared";
		case LinphonePublishExpiring: return "LinphonePublishExpiring";
	}
	return NULL;
}

Simon Morlat's avatar
Simon Morlat committed
60
static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, SalOp *op){
61 62 63
	LinphoneEvent *lev=ms_new0(LinphoneEvent,1);
	lev->lc=lc;
	lev->dir=dir;
Simon Morlat's avatar
Simon Morlat committed
64 65
	lev->op=op;
	lev->refcnt=1;
Simon Morlat's avatar
Simon Morlat committed
66
	lev->name=ms_strdup(name);
67 68 69 70
	sal_op_set_user_pointer(lev->op,lev);
	return lev;
}

71
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires){
Simon Morlat's avatar
Simon Morlat committed
72
	LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal));
73
	lev->expires=expires;
Simon Morlat's avatar
Simon Morlat committed
74 75 76
	return lev;
}

77
static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){
Simon Morlat's avatar
Simon Morlat committed
78
	LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op);
79
	lev->is_out_of_dialog_op=is_out_of_dialog;
80 81
	return lev;
}
Simon Morlat's avatar
Simon Morlat committed
82

83 84 85
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
	return linphone_event_new_with_op_base(lc,op,dir,name,FALSE);
}
Simon Morlat's avatar
Simon Morlat committed
86

87 88 89
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
	return linphone_event_new_with_op_base(lc,op,dir,name,TRUE);
}
Simon Morlat's avatar
Simon Morlat committed
90

91 92
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){
	LinphoneCore *lc=lev->lc;
93 94 95
	if (lev->subscription_state!=state){
		ms_message("LinphoneEvent [%p] moving to subscription state %s",lev,linphone_subscription_state_to_string(state));
		lev->subscription_state=state;
96 97 98
		if (lc->vtable.subscription_state_changed){
			lc->vtable.subscription_state_changed(lev->lc,lev,state);
		}
99
		if (state==LinphoneSubscriptionTerminated){
Simon Morlat's avatar
Simon Morlat committed
100 101
			linphone_event_unref(lev);
		}
102 103 104
	}
}

105 106 107 108 109 110 111 112
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state){
	LinphoneCore *lc=lev->lc;
	if (lev->publish_state!=state){
		ms_message("LinphoneEvent [%p] moving to publish state %s",lev,linphone_publish_state_to_string(state));
		lev->publish_state=state;
		if (lc->vtable.publish_state_changed){
			lc->vtable.publish_state_changed(lev->lc,lev,state);
		}
Simon Morlat's avatar
Simon Morlat committed
113 114 115 116 117 118 119 120 121 122 123 124 125 126
		switch(state){
			case LinphonePublishCleared:
				linphone_event_unref(lev);
				break;
			case LinphonePublishOk:
			case LinphonePublishError:
				if (lev->expires==-1)
					linphone_event_unref(lev);
				break;
			case LinphonePublishNone:
			case LinphonePublishProgress:
			case LinphonePublishExpiring:
				/*nothing special to do*/
				break;
127
		}
Simon Morlat's avatar
Simon Morlat committed
128
		
129 130 131 132 133 134 135
	}
}

LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){
	return lev->publish_state;
}

136 137
const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){
	return linphone_error_info_from_sal_op(lev->op);
138 139 140
}

LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){
141
	return linphone_error_info_get_reason(linphone_event_get_error_info(lev));
142 143
}

144 145
LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
	LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires);
146
	linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
Simon Morlat's avatar
Simon Morlat committed
147
	sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1));
148 149 150
	return lev;
}

151 152 153 154 155
LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
	LinphoneEvent *lev=linphone_core_create_subscribe(lc,resource,event,expires);
	linphone_event_send_subscribe(lev,body);
	return lev;
}
156

157 158

int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
159
	SalBody salbody;
160 161 162 163 164 165
	int err;
	
	if (lev->dir!=LinphoneSubscriptionOutgoing){
		ms_error("linphone_event_send_subscribe(): cannot send or update something that is not an outgoing subscription.");
		return -1;
	}
166 167 168
	switch (lev->subscription_state){
		case LinphoneSubscriptionIncomingReceived:
		case LinphoneSubscriptionTerminated:
169 170
		case LinphoneSubscriptionOutgoingInit:
			ms_error("linphone_event_send_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state));
171 172
			return -1;
		break;
173
		case LinphoneSubscriptionNone:
174 175 176 177 178 179
		case LinphoneSubscriptionActive:
		case LinphoneSubscriptionExpiring:
		case LinphoneSubscriptionError:
		case LinphoneSubscriptionPending:
			/*those states are ok*/
		break;
180
	}
181 182 183 184 185 186 187 188 189 190
	
	if (lev->send_custom_headers){
		sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers);
		lev->send_custom_headers=NULL;
	}else sal_op_set_sent_custom_header(lev->op,NULL);
	
	err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
	if (err==0){
		if (lev->subscription_state==LinphoneSubscriptionNone)
			linphone_event_set_state(lev,LinphoneSubscriptionOutgoingInit);
191
	}
192 193 194 195 196
	return err;
}

int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
	return linphone_event_send_subscribe(lev,body);
197 198 199 200
}

int linphone_event_accept_subscription(LinphoneEvent *lev){
	int err;
201
	if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
202 203 204 205 206 207 208 209 210 211 212
		ms_error("linphone_event_accept_subscription(): cannot accept subscription if subscription wasn't just received.");
		return -1;
	}
	err=sal_subscribe_accept(lev->op);
	if (err==0){
		linphone_event_set_state(lev,LinphoneSubscriptionActive);
	}
	return err;
}

int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){
213
	int err;
214
	if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
215 216 217
		ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received.");
		return -1;
	}
218 219 220
	err=sal_subscribe_decline(lev->op,linphone_reason_to_sal(reason));
	linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
	return err;
221 222 223 224
}

int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
	SalBody salbody;
225
	if (lev->subscription_state!=LinphoneSubscriptionActive){
226 227 228 229 230 231 232 233 234 235
		ms_error("linphone_event_notify(): cannot notify if subscription is not active.");
		return -1;
	}
	if (lev->dir!=LinphoneSubscriptionIncoming){
		ms_error("linphone_event_notify(): cannot notify if not an incoming subscription.");
		return -1;
	}
	return sal_notify(lev->op,sal_body_from_content(&salbody,body));
}

236 237
LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
	LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires);
238
	linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0));
Simon Morlat's avatar
Simon Morlat committed
239
	sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
240 241 242
	return lev;
}

243
static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){
244
	SalBody salbody;
245
	int err;
246
	
247
	if (lev->dir!=LinphoneSubscriptionInvalidDir){
248 249 250
		ms_error("linphone_event_update_publish(): this is not a PUBLISH event.");
		return -1;
	}
251 252 253 254
	if (lev->send_custom_headers){
		sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers);
		lev->send_custom_headers=NULL;
	}else sal_op_set_sent_custom_header(lev->op,NULL);
255
	err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
256 257
	if (err==0){
		linphone_event_set_publish_state(lev,LinphonePublishProgress);
258
	}else if (notify_err){
259 260 261
		linphone_event_set_publish_state(lev,LinphonePublishError);
	}
	return err;
262 263
}

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
	int err;
	LinphoneEvent *lev=linphone_core_create_publish(lc,resource,event,expires);
	err=_linphone_event_send_publish(lev,body,FALSE);
	if (err==-1){
		linphone_event_unref(lev);
		lev=NULL;
	}
	return lev;
}


int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body){
	return _linphone_event_send_publish(lev,body,TRUE);
}

int linphone_event_update_publish(LinphoneEvent* lev, const LinphoneContent* body ) {
	return linphone_event_send_publish(lev,body);
}


285
void linphone_event_set_user_data(LinphoneEvent *ev, void *up){
286 287 288
	ev->userdata=up;
}

289
void *linphone_event_get_user_data(const LinphoneEvent *ev){
290 291 292
	return ev->userdata;
}

293 294 295 296 297 298 299 300 301 302
void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value){
	ev->send_custom_headers=sal_custom_header_append(ev->send_custom_headers, name, value);
}

const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){
	const SalCustomHeader *ch=sal_op_get_recv_custom_header(ev->op);
	return sal_custom_header_find(ch,name);
}


303
void linphone_event_terminate(LinphoneEvent *lev){
304
	lev->terminating=TRUE;
305 306 307 308 309 310
	if (lev->dir==LinphoneSubscriptionIncoming){
		sal_notify_close(lev->op);
	}else if (lev->dir==LinphoneSubscriptionOutgoing){
		sal_unsubscribe(lev->op);
	}
	
311
	if (lev->publish_state!=LinphonePublishNone){
Simon Morlat's avatar
Simon Morlat committed
312
		if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){
313
			sal_publish(lev->op,NULL,NULL,NULL,0,NULL);
314 315
		}else sal_op_stop_refreshing(lev->op);
		linphone_event_set_publish_state(lev,LinphonePublishCleared);
316 317 318 319
		return;
	}
	
	if (lev->subscription_state!=LinphoneSubscriptionNone){
320
		linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
321
		return;
322 323 324
	}
}

Simon Morlat's avatar
Simon Morlat committed
325 326 327 328 329 330 331

LinphoneEvent *linphone_event_ref(LinphoneEvent *lev){
	lev->refcnt++;
	return lev;
}

static void linphone_event_destroy(LinphoneEvent *lev){
332 333
	if (lev->op)
		sal_op_release(lev->op);
Simon Morlat's avatar
Simon Morlat committed
334
	ms_free(lev->name);
335 336 337
	ms_free(lev);
}

Simon Morlat's avatar
Simon Morlat committed
338 339 340 341 342
void linphone_event_unref(LinphoneEvent *lev){
	lev->refcnt--;
	if (lev->refcnt==0) linphone_event_destroy(lev);
}

Simon Morlat's avatar
Simon Morlat committed
343
LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev){
344 345
	return lev->dir;
}
Simon Morlat's avatar
Simon Morlat committed
346 347

LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev){
348
	return lev->subscription_state;
Simon Morlat's avatar
Simon Morlat committed
349 350 351 352 353 354
}

const char *linphone_event_get_name(const LinphoneEvent *lev){
	return lev->name;
}

355
const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev){
356 357 358 359 360
	if (lev->is_out_of_dialog_op){
		return (LinphoneAddress*)sal_op_get_to_address(lev->op);
	}else{
		return (LinphoneAddress*)sal_op_get_from_address(lev->op);
	}
361 362 363
}

const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){
364 365 366 367 368
	if (lev->is_out_of_dialog_op){
		return (LinphoneAddress*)sal_op_get_from_address(lev->op);
	}else{
		return (LinphoneAddress*)sal_op_get_to_address(lev->op);
	}
369 370
}

371 372 373 374
LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){
	return lev->lc;
}