blob: f9c51dda19c4a6e20402e40b4fa72b86177b647c [file] [log] [blame]
Benny Prijono834aee32006-02-19 01:38:06 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono834aee32006-02-19 01:38:06 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
Benny Prijono4f9f64e2006-02-27 00:00:30 +000019#include <pjsua-lib/pjsua.h>
Benny Prijonoeebe9af2006-06-13 22:57:13 +000020#include <pjsua-lib/pjsua_internal.h>
Benny Prijono834aee32006-02-19 01:38:06 +000021
Benny Prijono834aee32006-02-19 01:38:06 +000022
23#define THIS_FILE "pjsua_pres.c"
24
25
Benny Prijonoeebe9af2006-06-13 22:57:13 +000026/*
27 * Get total number of buddies.
28 */
29PJ_DEF(unsigned) pjsua_get_buddy_count(void)
30{
31 return pjsua_var.buddy_cnt;
32}
Benny Prijono834aee32006-02-19 01:38:06 +000033
Benny Prijonoeebe9af2006-06-13 22:57:13 +000034
35/*
36 * Check if buddy ID is valid.
37 */
38PJ_DEF(pj_bool_t) pjsua_buddy_is_valid(pjsua_buddy_id buddy_id)
39{
Benny Prijonoa1e69682007-05-11 15:14:34 +000040 return buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy) &&
Benny Prijonoeebe9af2006-06-13 22:57:13 +000041 pjsua_var.buddy[buddy_id].uri.slen != 0;
42}
43
44
45/*
46 * Enum buddy IDs.
47 */
48PJ_DEF(pj_status_t) pjsua_enum_buddies( pjsua_buddy_id ids[],
49 unsigned *count)
50{
51 unsigned i, c;
52
53 PJ_ASSERT_RETURN(ids && count, PJ_EINVAL);
54
55 PJSUA_LOCK();
56
57 for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
58 if (!pjsua_var.buddy[i].uri.slen)
59 continue;
60 ids[c] = i;
61 ++c;
62 }
63
64 *count = c;
65
66 PJSUA_UNLOCK();
67
68 return PJ_SUCCESS;
69
70}
71
72
73/*
74 * Get detailed buddy info.
75 */
76PJ_DEF(pj_status_t) pjsua_buddy_get_info( pjsua_buddy_id buddy_id,
77 pjsua_buddy_info *info)
78{
79 int total=0;
80 pjsua_buddy *buddy;
81
82 PJ_ASSERT_RETURN(buddy_id>=0 &&
83 buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy),
84 PJ_EINVAL);
85
86 PJSUA_LOCK();
87
Benny Prijonoac623b32006-07-03 15:19:31 +000088 pj_bzero(info, sizeof(pjsua_buddy_info));
Benny Prijonoeebe9af2006-06-13 22:57:13 +000089
90 buddy = &pjsua_var.buddy[buddy_id];
91 info->id = buddy->index;
92 if (pjsua_var.buddy[buddy_id].uri.slen == 0) {
93 PJSUA_UNLOCK();
94 return PJ_SUCCESS;
95 }
96
97 /* uri */
98 info->uri.ptr = info->buf_ + total;
99 pj_strncpy(&info->uri, &buddy->uri, sizeof(info->buf_)-total);
100 total += info->uri.slen;
101
102 /* contact */
103 info->contact.ptr = info->buf_ + total;
104 pj_strncpy(&info->contact, &buddy->contact, sizeof(info->buf_)-total);
105 total += info->contact.slen;
106
107 /* status and status text */
108 if (buddy->sub == NULL || buddy->status.info_cnt==0) {
109 info->status = PJSUA_BUDDY_STATUS_UNKNOWN;
110 info->status_text = pj_str("?");
111 } else if (pjsua_var.buddy[buddy_id].status.info[0].basic_open) {
112 info->status = PJSUA_BUDDY_STATUS_ONLINE;
113 info->status_text = pj_str("Online");
114 } else {
115 info->status = PJSUA_BUDDY_STATUS_OFFLINE;
116 info->status_text = pj_str("Offline");
117 }
118
119 /* monitor pres */
120 info->monitor_pres = buddy->monitor;
121
122 PJSUA_UNLOCK();
123 return PJ_SUCCESS;
124}
125
126
127/*
128 * Reset buddy descriptor.
129 */
130static void reset_buddy(pjsua_buddy_id id)
131{
Benny Prijonoac623b32006-07-03 15:19:31 +0000132 pj_bzero(&pjsua_var.buddy[id], sizeof(pjsua_var.buddy[id]));
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000133 pjsua_var.buddy[id].index = id;
134}
135
136
137/*
138 * Add new buddy.
139 */
140PJ_DEF(pj_status_t) pjsua_buddy_add( const pjsua_buddy_config *cfg,
141 pjsua_buddy_id *p_buddy_id)
142{
143 pjsip_name_addr *url;
144 pjsip_sip_uri *sip_uri;
145 int index;
146 pj_str_t tmp;
147
148 PJ_ASSERT_RETURN(pjsua_var.buddy_cnt <=
149 PJ_ARRAY_SIZE(pjsua_var.buddy),
150 PJ_ETOOMANY);
151
152 PJSUA_LOCK();
153
154 /* Find empty slot */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000155 for (index=0; index<(int)PJ_ARRAY_SIZE(pjsua_var.buddy); ++index) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000156 if (pjsua_var.buddy[index].uri.slen == 0)
157 break;
158 }
159
160 /* Expect to find an empty slot */
161 if (index == PJ_ARRAY_SIZE(pjsua_var.buddy)) {
162 PJSUA_UNLOCK();
163 /* This shouldn't happen */
164 pj_assert(!"index < PJ_ARRAY_SIZE(pjsua_var.buddy)");
165 return PJ_ETOOMANY;
166 }
167
168
169 /* Get name and display name for buddy */
170 pj_strdup_with_null(pjsua_var.pool, &tmp, &cfg->uri);
171 url = (pjsip_name_addr*)pjsip_parse_uri(pjsua_var.pool, tmp.ptr, tmp.slen,
172 PJSIP_PARSE_URI_AS_NAMEADDR);
173
174 if (url == NULL) {
175 pjsua_perror(THIS_FILE, "Unable to add buddy", PJSIP_EINVALIDURI);
176 PJSUA_UNLOCK();
177 return PJSIP_EINVALIDURI;
178 }
179
Benny Prijonofc493592007-02-18 20:56:32 +0000180 /* Only support SIP schemes */
181 if (!PJSIP_URI_SCHEME_IS_SIP(url) && !PJSIP_URI_SCHEME_IS_SIPS(url))
182 return PJSIP_EINVALIDSCHEME;
183
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000184 /* Reset buddy, to make sure everything is cleared with default
185 * values
186 */
187 reset_buddy(index);
188
189 /* Save URI */
190 pjsua_var.buddy[index].uri = tmp;
191
Benny Prijono9c1528f2007-02-10 19:22:25 +0000192 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(url->uri);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000193 pjsua_var.buddy[index].name = sip_uri->user;
194 pjsua_var.buddy[index].display = url->display;
195 pjsua_var.buddy[index].host = sip_uri->host;
196 pjsua_var.buddy[index].port = sip_uri->port;
197 pjsua_var.buddy[index].monitor = cfg->subscribe;
198 if (pjsua_var.buddy[index].port == 0)
199 pjsua_var.buddy[index].port = 5060;
200
201 if (p_buddy_id)
202 *p_buddy_id = index;
203
204 pjsua_var.buddy_cnt++;
205
206 pjsua_buddy_subscribe_pres(index, cfg->subscribe);
207
208 PJSUA_UNLOCK();
209
210 return PJ_SUCCESS;
211}
212
213
214/*
215 * Delete buddy.
216 */
217PJ_DEF(pj_status_t) pjsua_buddy_del(pjsua_buddy_id buddy_id)
218{
219 PJ_ASSERT_RETURN(buddy_id>=0 &&
220 buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy),
221 PJ_EINVAL);
222
223 PJSUA_LOCK();
224
225 if (pjsua_var.buddy[buddy_id].uri.slen == 0) {
226 PJSUA_UNLOCK();
227 return PJ_SUCCESS;
228 }
229
230 /* Unsubscribe presence */
231 pjsua_buddy_subscribe_pres(buddy_id, PJ_FALSE);
232
233 /* Remove buddy */
234 pjsua_var.buddy[buddy_id].uri.slen = 0;
235 pjsua_var.buddy_cnt--;
236
237 /* Reset buddy struct */
238 reset_buddy(buddy_id);
239
240 PJSUA_UNLOCK();
241 return PJ_SUCCESS;
242}
243
244
245/*
246 * Enable/disable buddy's presence monitoring.
247 */
248PJ_DEF(pj_status_t) pjsua_buddy_subscribe_pres( pjsua_buddy_id buddy_id,
249 pj_bool_t subscribe)
250{
251 pjsua_buddy *buddy;
252
253 PJ_ASSERT_RETURN(buddy_id>=0 &&
254 buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy),
255 PJ_EINVAL);
256
257 PJSUA_LOCK();
258
259 buddy = &pjsua_var.buddy[buddy_id];
260 buddy->monitor = subscribe;
261 pjsua_pres_refresh();
262
263 PJSUA_UNLOCK();
264
265 return PJ_SUCCESS;
266}
267
268
269/*
270 * Dump presence subscriptions to log file.
271 */
272PJ_DEF(void) pjsua_pres_dump(pj_bool_t verbose)
273{
274 unsigned acc_id;
275 unsigned i;
276
277
278 PJSUA_LOCK();
279
280 /*
281 * When no detail is required, just dump number of server and client
282 * subscriptions.
283 */
284 if (verbose == PJ_FALSE) {
285
286 int count = 0;
287
288 for (acc_id=0; acc_id<PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) {
289
290 if (!pjsua_var.acc[acc_id].valid)
291 continue;
292
293 if (!pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) {
294 struct pjsua_srv_pres *uapres;
295
296 uapres = pjsua_var.acc[acc_id].pres_srv_list.next;
297 while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) {
298 ++count;
299 uapres = uapres->next;
300 }
301 }
302 }
303
304 PJ_LOG(3,(THIS_FILE, "Number of server/UAS subscriptions: %d",
305 count));
306
307 count = 0;
308
309 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
310 if (pjsua_var.buddy[i].uri.slen == 0)
311 continue;
312 if (pjsua_var.buddy[i].sub) {
313 ++count;
314 }
315 }
316
317 PJ_LOG(3,(THIS_FILE, "Number of client/UAC subscriptions: %d",
318 count));
319 PJSUA_UNLOCK();
320 return;
321 }
322
323
324 /*
325 * Dumping all server (UAS) subscriptions
326 */
327 PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:"));
328
329 for (acc_id=0; acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) {
330
331 if (!pjsua_var.acc[acc_id].valid)
332 continue;
333
334 PJ_LOG(3,(THIS_FILE, " %.*s",
335 (int)pjsua_var.acc[acc_id].cfg.id.slen,
336 pjsua_var.acc[acc_id].cfg.id.ptr));
337
338 if (pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) {
339
340 PJ_LOG(3,(THIS_FILE, " - none - "));
341
342 } else {
343 struct pjsua_srv_pres *uapres;
344
345 uapres = pjsua_var.acc[acc_id].pres_srv_list.next;
346 while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) {
347
348 PJ_LOG(3,(THIS_FILE, " %10s %s",
349 pjsip_evsub_get_state_name(uapres->sub),
350 uapres->remote));
351
352 uapres = uapres->next;
353 }
354 }
355 }
356
357 /*
358 * Dumping all client (UAC) subscriptions
359 */
360 PJ_LOG(3,(THIS_FILE, "Dumping pjsua client subscriptions:"));
361
362 if (pjsua_var.buddy_cnt == 0) {
363
364 PJ_LOG(3,(THIS_FILE, " - no buddy list - "));
365
366 } else {
367 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
368
369 if (pjsua_var.buddy[i].uri.slen == 0)
370 continue;
371
372 if (pjsua_var.buddy[i].sub) {
373 PJ_LOG(3,(THIS_FILE, " %10s %.*s",
374 pjsip_evsub_get_state_name(pjsua_var.buddy[i].sub),
375 (int)pjsua_var.buddy[i].uri.slen,
376 pjsua_var.buddy[i].uri.ptr));
377 } else {
378 PJ_LOG(3,(THIS_FILE, " %10s %.*s",
379 "(null)",
380 (int)pjsua_var.buddy[i].uri.slen,
381 pjsua_var.buddy[i].uri.ptr));
382 }
383 }
384 }
385
386 PJSUA_UNLOCK();
387}
388
389
390/***************************************************************************
391 * Server subscription.
Benny Prijono834aee32006-02-19 01:38:06 +0000392 */
393
394/* Proto */
395static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata);
396
397/* The module instance. */
398static pjsip_module mod_pjsua_pres =
399{
400 NULL, NULL, /* prev, next. */
401 { "mod-pjsua-pres", 14 }, /* Name. */
402 -1, /* Id */
403 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
Benny Prijono834aee32006-02-19 01:38:06 +0000404 NULL, /* load() */
405 NULL, /* start() */
406 NULL, /* stop() */
407 NULL, /* unload() */
408 &pres_on_rx_request, /* on_rx_request() */
409 NULL, /* on_rx_response() */
410 NULL, /* on_tx_request. */
411 NULL, /* on_tx_response() */
412 NULL, /* on_tsx_state() */
413
414};
415
416
417/* Callback called when *server* subscription state has changed. */
418static void pres_evsub_on_srv_state( pjsip_evsub *sub, pjsip_event *event)
419{
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000420 pjsua_srv_pres *uapres;
Benny Prijono834aee32006-02-19 01:38:06 +0000421
422 PJ_UNUSED_ARG(event);
423
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000424 PJSUA_LOCK();
425
Benny Prijonoa1e69682007-05-11 15:14:34 +0000426 uapres = (pjsua_srv_pres*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);
Benny Prijono834aee32006-02-19 01:38:06 +0000427 if (uapres) {
428 PJ_LOG(3,(THIS_FILE, "Server subscription to %s is %s",
429 uapres->remote, pjsip_evsub_get_state_name(sub)));
430
431 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000432 pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL);
Benny Prijono834aee32006-02-19 01:38:06 +0000433 pj_list_erase(uapres);
434 }
435 }
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000436
437 PJSUA_UNLOCK();
Benny Prijono834aee32006-02-19 01:38:06 +0000438}
439
440/* This is called when request is received.
441 * We need to check for incoming SUBSCRIBE request.
442 */
443static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata)
444{
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000445 int acc_id;
Benny Prijono6f979412006-06-15 12:25:46 +0000446 pjsua_acc *acc;
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000447 pj_str_t contact;
Benny Prijono834aee32006-02-19 01:38:06 +0000448 pjsip_method *req_method = &rdata->msg_info.msg->line.req.method;
449 pjsua_srv_pres *uapres;
450 pjsip_evsub *sub;
451 pjsip_evsub_user pres_cb;
452 pjsip_tx_data *tdata;
453 pjsip_pres_status pres_status;
454 pjsip_dialog *dlg;
455 pj_status_t status;
456
457 if (pjsip_method_cmp(req_method, &pjsip_subscribe_method) != 0)
458 return PJ_FALSE;
459
460 /* Incoming SUBSCRIBE: */
461
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000462 PJSUA_LOCK();
463
Benny Prijonoa91a0032006-02-26 21:23:45 +0000464 /* Find which account for the incoming request. */
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000465 acc_id = pjsua_acc_find_for_incoming(rdata);
Benny Prijono6f979412006-06-15 12:25:46 +0000466 acc = &pjsua_var.acc[acc_id];
Benny Prijonoa91a0032006-02-26 21:23:45 +0000467
Benny Prijono6f979412006-06-15 12:25:46 +0000468 PJ_LOG(4,(THIS_FILE, "Creating server subscription, using account %d",
469 acc_id));
470
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000471 /* Create suitable Contact header */
472 status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact,
473 acc_id, rdata);
474 if (status != PJ_SUCCESS) {
475 pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
476 PJSUA_UNLOCK();
477 return PJ_TRUE;
478 }
479
Benny Prijono834aee32006-02-19 01:38:06 +0000480 /* Create UAS dialog: */
Benny Prijonodc39fe82006-05-26 12:17:46 +0000481 status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata,
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000482 &contact, &dlg);
Benny Prijono834aee32006-02-19 01:38:06 +0000483 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000484 pjsua_perror(THIS_FILE,
485 "Unable to create UAS dialog for subscription",
486 status);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000487 PJSUA_UNLOCK();
488 return PJ_TRUE;
Benny Prijono834aee32006-02-19 01:38:06 +0000489 }
490
Benny Prijono6f979412006-06-15 12:25:46 +0000491 /* Set credentials. */
492 pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred);
493
Benny Prijono834aee32006-02-19 01:38:06 +0000494 /* Init callback: */
Benny Prijonoac623b32006-07-03 15:19:31 +0000495 pj_bzero(&pres_cb, sizeof(pres_cb));
Benny Prijono834aee32006-02-19 01:38:06 +0000496 pres_cb.on_evsub_state = &pres_evsub_on_srv_state;
497
498 /* Create server presence subscription: */
499 status = pjsip_pres_create_uas( dlg, &pres_cb, rdata, &sub);
500 if (status != PJ_SUCCESS) {
Benny Prijono1c2bf462006-03-05 11:54:02 +0000501 pjsip_dlg_terminate(dlg);
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000502 pjsua_perror(THIS_FILE, "Unable to create server subscription",
503 status);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000504 PJSUA_UNLOCK();
505 return PJ_TRUE;
Benny Prijono834aee32006-02-19 01:38:06 +0000506 }
507
Benny Prijono62c5c5b2007-01-13 23:22:40 +0000508 /* If account is locked to specific transport, then lock dialog
509 * to this transport too.
510 */
511 if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
512 pjsip_tpselector tp_sel;
513
514 pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
515 pjsip_dlg_set_transport(dlg, &tp_sel);
516 }
517
Benny Prijono834aee32006-02-19 01:38:06 +0000518 /* Attach our data to the subscription: */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000519 uapres = PJ_POOL_ALLOC_T(dlg->pool, pjsua_srv_pres);
Benny Prijono834aee32006-02-19 01:38:06 +0000520 uapres->sub = sub;
Benny Prijonoa1e69682007-05-11 15:14:34 +0000521 uapres->remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE);
Benny Prijono834aee32006-02-19 01:38:06 +0000522 status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri,
523 uapres->remote, PJSIP_MAX_URL_SIZE);
524 if (status < 1)
525 pj_ansi_strcpy(uapres->remote, "<-- url is too long-->");
526 else
527 uapres->remote[status] = '\0';
528
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000529 pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, uapres);
Benny Prijono834aee32006-02-19 01:38:06 +0000530
531 /* Add server subscription to the list: */
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000532 pj_list_push_back(&pjsua_var.acc[acc_id].pres_srv_list, uapres);
Benny Prijono834aee32006-02-19 01:38:06 +0000533
534
535 /* Create and send 200 (OK) to the SUBSCRIBE request: */
536 status = pjsip_pres_accept(sub, rdata, 200, NULL);
537 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000538 pjsua_perror(THIS_FILE, "Unable to accept presence subscription",
539 status);
Benny Prijono834aee32006-02-19 01:38:06 +0000540 pj_list_erase(uapres);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000541 pjsip_pres_terminate(sub, PJ_FALSE);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000542 PJSUA_UNLOCK();
Benny Prijono834aee32006-02-19 01:38:06 +0000543 return PJ_FALSE;
544 }
545
546
547 /* Set our online status: */
Benny Prijonoac623b32006-07-03 15:19:31 +0000548 pj_bzero(&pres_status, sizeof(pres_status));
Benny Prijono834aee32006-02-19 01:38:06 +0000549 pres_status.info_cnt = 1;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000550 pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status;
551 //Both pjsua_var.local_uri and pjsua_var.contact_uri are enclosed in "<" and ">"
Benny Prijono834aee32006-02-19 01:38:06 +0000552 //causing XML parsing to fail.
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000553 //pres_status.info[0].contact = pjsua_var.local_uri;
Benny Prijono834aee32006-02-19 01:38:06 +0000554
555 pjsip_pres_set_status(sub, &pres_status);
556
557 /* Create and send the first NOTIFY to active subscription: */
558 status = pjsip_pres_notify( sub, PJSIP_EVSUB_STATE_ACTIVE, NULL,
559 NULL, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000560 if (status == PJ_SUCCESS) {
561 pjsua_process_msg_data(tdata, NULL);
Benny Prijono834aee32006-02-19 01:38:06 +0000562 status = pjsip_pres_send_request( sub, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000563 }
Benny Prijono834aee32006-02-19 01:38:06 +0000564
565 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000566 pjsua_perror(THIS_FILE, "Unable to create/send NOTIFY",
567 status);
Benny Prijono834aee32006-02-19 01:38:06 +0000568 pj_list_erase(uapres);
Benny Prijono1c2bf462006-03-05 11:54:02 +0000569 pjsip_pres_terminate(sub, PJ_FALSE);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000570 PJSUA_UNLOCK();
Benny Prijono834aee32006-02-19 01:38:06 +0000571 return PJ_FALSE;
572 }
573
574
575 /* Done: */
576
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000577 PJSUA_UNLOCK();
578
Benny Prijono834aee32006-02-19 01:38:06 +0000579 return PJ_TRUE;
580}
581
582
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000583/*
584 * Client presence publication callback.
585 */
586static void publish_cb(struct pjsip_publishc_cbparam *param)
587{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000588 pjsua_acc *acc = (pjsua_acc*) param->token;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000589
590 if (param->code/100 != 2 || param->status != PJ_SUCCESS) {
591 if (param->status != PJ_SUCCESS) {
592 char errmsg[PJ_ERR_MSG_SIZE];
593
594 pj_strerror(param->status, errmsg, sizeof(errmsg));
595 PJ_LOG(1,(THIS_FILE,
596 "Client publication (PUBLISH) failed, status=%d, msg=%s",
597 param->status, errmsg));
598 } else {
599 PJ_LOG(1,(THIS_FILE,
600 "Client publication (PUBLISH) failed (%d/%.*s)",
601 param->code, (int)param->reason.slen,
602 param->reason.ptr));
603 }
604
605 pjsip_publishc_destroy(param->pubc);
606 acc->publish_sess = NULL;
607 }
608}
609
610
611/*
612 * Send PUBLISH request.
613 */
614static pj_status_t send_publish(int acc_id, pj_bool_t active)
615{
616 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
617 pjsua_acc *acc = &pjsua_var.acc[acc_id];
618 pjsip_pres_status pres_status;
619 pjsip_tx_data *tdata;
620 pj_status_t status;
621
622
623 /* Create PUBLISH request */
624 if (active) {
Benny Prijono8c6e8842007-02-24 15:33:54 +0000625 char *bpos;
626 pj_str_t entity;
627
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000628 status = pjsip_publishc_publish(acc->publish_sess, PJ_TRUE, &tdata);
629 if (status != PJ_SUCCESS) {
630 pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status);
631 goto on_error;
632 }
633
634 /* Set our online status: */
635 pj_bzero(&pres_status, sizeof(pres_status));
636 pres_status.info_cnt = 1;
637 pres_status.info[0].basic_open = acc->online_status;
638
Benny Prijono8c6e8842007-02-24 15:33:54 +0000639 /* Be careful not to send PIDF with presence entity ID containing
640 * "<" character.
641 */
642 if ((bpos=pj_strchr(&acc_cfg->id, '<')) != NULL) {
643 char *epos = pj_strchr(&acc_cfg->id, '>');
644 if (epos - bpos < 2) {
645 pj_assert(!"Unexpected invalid URI");
646 status = PJSIP_EINVALIDURI;
647 goto on_error;
648 }
649 entity.ptr = bpos+1;
650 entity.slen = epos - bpos - 1;
651 } else {
652 entity = acc_cfg->id;
653 }
654
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000655 /* Create and add PIDF message body */
656 status = pjsip_pres_create_pidf(tdata->pool, &pres_status,
Benny Prijono8c6e8842007-02-24 15:33:54 +0000657 &entity, &tdata->msg->body);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000658 if (status != PJ_SUCCESS) {
659 pjsua_perror(THIS_FILE, "Error creating PIDF for PUBLISH request",
660 status);
661 pjsip_tx_data_dec_ref(tdata);
662 goto on_error;
663 }
664 } else {
665 status = pjsip_publishc_unpublish(acc->publish_sess, &tdata);
666 if (status != PJ_SUCCESS) {
667 pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status);
668 goto on_error;
669 }
670 }
671
672 /* Add headers etc */
673 pjsua_process_msg_data(tdata, NULL);
674
675 /* Send the PUBLISH request */
676 status = pjsip_publishc_send(acc->publish_sess, tdata);
677 if (status != PJ_SUCCESS) {
678 pjsua_perror(THIS_FILE, "Error sending PUBLISH request", status);
679 goto on_error;
680 }
681
682 acc->publish_state = acc->online_status;
683 return PJ_SUCCESS;
684
685on_error:
686 pjsip_publishc_destroy(acc->publish_sess);
687 acc->publish_sess = NULL;
688 return status;
689}
690
691
692/* Create client publish session */
Benny Prijono8b6834f2007-02-24 13:29:22 +0000693pj_status_t pjsua_pres_init_publish_acc(int acc_id)
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000694{
695 const pj_str_t STR_PRESENCE = { "presence", 8 };
696 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
697 pjsua_acc *acc = &pjsua_var.acc[acc_id];
698 pj_status_t status;
699
700 /* Create and init client publication session */
701 if (acc_cfg->publish_enabled) {
702
703 /* Create client publication */
704 status = pjsip_publishc_create(pjsua_var.endpt, 0, acc, &publish_cb,
705 &acc->publish_sess);
706 if (status != PJ_SUCCESS) {
707 acc->publish_sess = NULL;
708 return status;
709 }
710
711 /* Initialize client publication */
712 status = pjsip_publishc_init(acc->publish_sess, &STR_PRESENCE,
713 &acc_cfg->id, &acc_cfg->id,
714 &acc_cfg->id,
Benny Prijono703b7d72007-03-20 09:13:24 +0000715 60);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000716 if (status != PJ_SUCCESS) {
717 acc->publish_sess = NULL;
718 return status;
719 }
720
Benny Prijono703b7d72007-03-20 09:13:24 +0000721 /* Add credential for authentication */
722 pjsip_publishc_set_credentials(acc->publish_sess, acc->cred_cnt,
723 acc->cred);
724
725 /* Set route-set */
726 pjsip_publishc_set_route_set(acc->publish_sess, &acc->route_set);
727
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000728 /* Send initial PUBLISH request */
729 if (acc->online_status != 0) {
730 status = send_publish(acc_id, PJ_TRUE);
731 if (status != PJ_SUCCESS)
732 return status;
733 }
734
735 } else {
736 acc->publish_sess = NULL;
737 }
738
739 return PJ_SUCCESS;
740}
741
742
743/* Init presence for account */
744pj_status_t pjsua_pres_init_acc(int acc_id)
745{
746 pjsua_acc *acc = &pjsua_var.acc[acc_id];
747
748 /* Init presence subscription */
749 pj_list_init(&acc->pres_srv_list);
750
Benny Prijono8b6834f2007-02-24 13:29:22 +0000751 return PJ_SUCCESS;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000752}
753
754
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000755/* Terminate server subscription for the account */
756void pjsua_pres_delete_acc(int acc_id)
Benny Prijono834aee32006-02-19 01:38:06 +0000757{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000758 pjsua_acc *acc = &pjsua_var.acc[acc_id];
759 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
Benny Prijono834aee32006-02-19 01:38:06 +0000760 pjsua_srv_pres *uapres;
761
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000762 uapres = pjsua_var.acc[acc_id].pres_srv_list.next;
Benny Prijono834aee32006-02-19 01:38:06 +0000763
Benny Prijono922933b2007-01-21 16:23:56 +0000764 /* Notify all subscribers that we're no longer available */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000765 while (uapres != &acc->pres_srv_list) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000766
767 pjsip_pres_status pres_status;
768 pj_str_t reason = { "noresource", 10 };
769 pjsip_tx_data *tdata;
770
771 pjsip_pres_get_status(uapres->sub, &pres_status);
772
773 pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status;
774 pjsip_pres_set_status(uapres->sub, &pres_status);
775
776 if (pjsip_pres_notify(uapres->sub,
777 PJSIP_EVSUB_STATE_TERMINATED, NULL,
778 &reason, &tdata)==PJ_SUCCESS)
779 {
780 pjsip_pres_send_request(uapres->sub, tdata);
781 }
782
783 uapres = uapres->next;
784 }
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000785
Benny Prijono922933b2007-01-21 16:23:56 +0000786 /* Clear server presence subscription list because account might be reused
787 * later. */
788 pj_list_init(&acc->pres_srv_list);
789
790 /* Terminate presence publication, if any */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000791 if (acc->publish_sess) {
792 acc->online_status = PJ_FALSE;
793 send_publish(acc_id, PJ_FALSE);
794 if (acc->publish_sess) {
795 pjsip_publishc_destroy(acc->publish_sess);
796 acc->publish_sess = NULL;
797 }
798 acc_cfg->publish_enabled = PJ_FALSE;
799 }
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000800}
801
802
803/* Refresh subscription (e.g. when our online status has changed) */
804static void refresh_server_subscription(int acc_id)
805{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000806 pjsua_acc *acc = &pjsua_var.acc[acc_id];
807 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000808 pjsua_srv_pres *uapres;
809
810 uapres = pjsua_var.acc[acc_id].pres_srv_list.next;
811
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000812 while (uapres != &acc->pres_srv_list) {
Benny Prijono834aee32006-02-19 01:38:06 +0000813
814 pjsip_pres_status pres_status;
815 pjsip_tx_data *tdata;
816
817 pjsip_pres_get_status(uapres->sub, &pres_status);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000818 if (pres_status.info[0].basic_open != acc->online_status) {
819 pres_status.info[0].basic_open = acc->online_status;
Benny Prijono834aee32006-02-19 01:38:06 +0000820 pjsip_pres_set_status(uapres->sub, &pres_status);
821
Benny Prijono21b9ad92006-08-15 13:11:22 +0000822 if (pjsip_pres_current_notify(uapres->sub, &tdata)==PJ_SUCCESS) {
823 pjsua_process_msg_data(tdata, NULL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000824 pjsip_pres_send_request(uapres->sub, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000825 }
Benny Prijono834aee32006-02-19 01:38:06 +0000826 }
827
828 uapres = uapres->next;
829 }
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000830
Benny Prijono8b6834f2007-02-24 13:29:22 +0000831 /* Send PUBLISH if required. We only do this when we have a PUBLISH
832 * session. If we don't have a PUBLISH session, then it could be
833 * that we're waiting until registration has completed before we
834 * send the first PUBLISH.
835 */
836 if (acc_cfg->publish_enabled && acc->publish_sess) {
837 if (acc->publish_state != acc->online_status) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000838 send_publish(acc_id, PJ_TRUE);
839 }
840 }
Benny Prijono834aee32006-02-19 01:38:06 +0000841}
842
843
844
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000845/***************************************************************************
846 * Client subscription.
Benny Prijono834aee32006-02-19 01:38:06 +0000847 */
848
849/* Callback called when *client* subscription state has changed. */
850static void pjsua_evsub_on_state( pjsip_evsub *sub, pjsip_event *event)
851{
852 pjsua_buddy *buddy;
853
854 PJ_UNUSED_ARG(event);
855
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000856 PJSUA_LOCK();
857
Benny Prijonoa1e69682007-05-11 15:14:34 +0000858 buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);
Benny Prijono834aee32006-02-19 01:38:06 +0000859 if (buddy) {
860 PJ_LOG(3,(THIS_FILE,
Benny Prijono9fc735d2006-05-28 14:58:12 +0000861 "Presence subscription to %.*s is %s",
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000862 (int)pjsua_var.buddy[buddy->index].uri.slen,
863 pjsua_var.buddy[buddy->index].uri.ptr,
Benny Prijono834aee32006-02-19 01:38:06 +0000864 pjsip_evsub_get_state_name(sub)));
865
866 if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
867 buddy->sub = NULL;
868 buddy->status.info_cnt = 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000869 pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL);
Benny Prijono834aee32006-02-19 01:38:06 +0000870 }
Benny Prijono9fc735d2006-05-28 14:58:12 +0000871
872 /* Call callback */
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000873 if (pjsua_var.ua_cfg.cb.on_buddy_state)
874 (*pjsua_var.ua_cfg.cb.on_buddy_state)(buddy->index);
Benny Prijono834aee32006-02-19 01:38:06 +0000875 }
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000876
877 PJSUA_UNLOCK();
Benny Prijono834aee32006-02-19 01:38:06 +0000878}
879
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000880
881/* Callback when transaction state has changed. */
882static void pjsua_evsub_on_tsx_state(pjsip_evsub *sub,
883 pjsip_transaction *tsx,
884 pjsip_event *event)
885{
886 pjsua_buddy *buddy;
887 pjsip_contact_hdr *contact_hdr;
888
889 PJSUA_LOCK();
890
Benny Prijonoa1e69682007-05-11 15:14:34 +0000891 buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000892 if (!buddy) {
893 PJSUA_UNLOCK();
894 return;
895 }
896
897 /* We only use this to update buddy's Contact, when it's not
898 * set.
899 */
900 if (buddy->contact.slen != 0) {
901 /* Contact already set */
902 PJSUA_UNLOCK();
903 return;
904 }
905
906 /* Only care about 2xx response to outgoing SUBSCRIBE */
907 if (tsx->status_code/100 != 2 ||
908 tsx->role != PJSIP_UAC_ROLE ||
909 event->type != PJSIP_EVENT_RX_MSG ||
910 pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method)!=0)
911 {
912 PJSUA_UNLOCK();
913 return;
914 }
915
916 /* Find contact header. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000917 contact_hdr = (pjsip_contact_hdr*)
918 pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg,
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000919 PJSIP_H_CONTACT, NULL);
920 if (!contact_hdr) {
921 PJSUA_UNLOCK();
922 return;
923 }
924
Benny Prijonoa1e69682007-05-11 15:14:34 +0000925 buddy->contact.ptr = (char*)
926 pj_pool_alloc(pjsua_var.pool, PJSIP_MAX_URL_SIZE);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000927 buddy->contact.slen = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR,
928 contact_hdr->uri,
929 buddy->contact.ptr,
930 PJSIP_MAX_URL_SIZE);
931 if (buddy->contact.slen < 0)
932 buddy->contact.slen = 0;
933
934 PJSUA_UNLOCK();
935}
936
937
Benny Prijono834aee32006-02-19 01:38:06 +0000938/* Callback called when we receive NOTIFY */
939static void pjsua_evsub_on_rx_notify(pjsip_evsub *sub,
940 pjsip_rx_data *rdata,
941 int *p_st_code,
942 pj_str_t **p_st_text,
943 pjsip_hdr *res_hdr,
944 pjsip_msg_body **p_body)
945{
946 pjsua_buddy *buddy;
947
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000948 PJSUA_LOCK();
949
Benny Prijonoa1e69682007-05-11 15:14:34 +0000950 buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id);
Benny Prijono834aee32006-02-19 01:38:06 +0000951 if (buddy) {
952 /* Update our info. */
953 pjsip_pres_get_status(sub, &buddy->status);
Benny Prijono834aee32006-02-19 01:38:06 +0000954 }
955
956 /* The default is to send 200 response to NOTIFY.
957 * Just leave it there..
958 */
959 PJ_UNUSED_ARG(rdata);
960 PJ_UNUSED_ARG(p_st_code);
961 PJ_UNUSED_ARG(p_st_text);
962 PJ_UNUSED_ARG(res_hdr);
963 PJ_UNUSED_ARG(p_body);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000964
965 PJSUA_UNLOCK();
Benny Prijono834aee32006-02-19 01:38:06 +0000966}
967
968
969/* Event subscription callback. */
970static pjsip_evsub_user pres_callback =
971{
972 &pjsua_evsub_on_state,
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000973 &pjsua_evsub_on_tsx_state,
Benny Prijono834aee32006-02-19 01:38:06 +0000974
975 NULL, /* on_rx_refresh: don't care about SUBSCRIBE refresh, unless
976 * we want to authenticate
977 */
978
979 &pjsua_evsub_on_rx_notify,
980
981 NULL, /* on_client_refresh: Use default behaviour, which is to
982 * refresh client subscription. */
983
984 NULL, /* on_server_timeout: Use default behaviour, which is to send
985 * NOTIFY to terminate.
986 */
987};
988
989
990/* It does what it says.. */
991static void subscribe_buddy_presence(unsigned index)
992{
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000993 pjsua_buddy *buddy;
994 int acc_id;
995 pjsua_acc *acc;
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000996 pj_str_t contact;
Benny Prijono834aee32006-02-19 01:38:06 +0000997 pjsip_dialog *dlg;
998 pjsip_tx_data *tdata;
999 pj_status_t status;
1000
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001001 buddy = &pjsua_var.buddy[index];
1002 acc_id = pjsua_acc_find_for_outgoing(&buddy->uri);
Benny Prijono8b1889b2006-06-06 18:40:40 +00001003
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001004 acc = &pjsua_var.acc[acc_id];
Benny Prijonoa91a0032006-02-26 21:23:45 +00001005
Benny Prijonob4a17c92006-07-10 14:40:21 +00001006 PJ_LOG(4,(THIS_FILE, "Using account %d for buddy %d subscription",
1007 acc_id, index));
1008
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001009 /* Generate suitable Contact header */
1010 status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
1011 acc_id, &buddy->uri);
1012 if (status != PJ_SUCCESS) {
1013 pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
1014 return;
1015 }
1016
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001017 /* Create UAC dialog */
Benny Prijono834aee32006-02-19 01:38:06 +00001018 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001019 &acc->cfg.id,
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001020 &contact,
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001021 &buddy->uri,
Benny Prijono834aee32006-02-19 01:38:06 +00001022 NULL, &dlg);
1023 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +00001024 pjsua_perror(THIS_FILE, "Unable to create dialog",
1025 status);
Benny Prijono834aee32006-02-19 01:38:06 +00001026 return;
1027 }
1028
Benny Prijonodc752ca2006-09-22 16:55:42 +00001029 status = pjsip_pres_create_uac( dlg, &pres_callback,
1030 PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub);
1031 if (status != PJ_SUCCESS) {
1032 pjsua_var.buddy[index].sub = NULL;
1033 pjsua_perror(THIS_FILE, "Unable to create presence client",
1034 status);
1035 pjsip_dlg_terminate(dlg);
1036 return;
1037 }
1038
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001039 /* If account is locked to specific transport, then lock dialog
1040 * to this transport too.
1041 */
1042 if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
1043 pjsip_tpselector tp_sel;
1044
1045 pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
1046 pjsip_dlg_set_transport(dlg, &tp_sel);
1047 }
1048
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001049 /* Set route-set */
1050 if (!pj_list_empty(&acc->route_set)) {
1051 pjsip_dlg_set_route_set(dlg, &acc->route_set);
1052 }
1053
1054 /* Set credentials */
1055 if (acc->cred_cnt) {
Benny Prijonodc39fe82006-05-26 12:17:46 +00001056 pjsip_auth_clt_set_credentials( &dlg->auth_sess,
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001057 acc->cred_cnt, acc->cred);
Benny Prijonodc39fe82006-05-26 12:17:46 +00001058 }
Benny Prijono1d8d6082006-04-29 12:38:25 +00001059
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001060 pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy);
Benny Prijono834aee32006-02-19 01:38:06 +00001061
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001062 status = pjsip_pres_initiate(buddy->sub, -1, &tdata);
Benny Prijono834aee32006-02-19 01:38:06 +00001063 if (status != PJ_SUCCESS) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001064 pjsip_pres_terminate(buddy->sub, PJ_FALSE);
1065 buddy->sub = NULL;
Benny Prijonobcaed6c2006-02-19 15:37:19 +00001066 pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE",
1067 status);
Benny Prijono834aee32006-02-19 01:38:06 +00001068 return;
1069 }
1070
Benny Prijono21b9ad92006-08-15 13:11:22 +00001071 pjsua_process_msg_data(tdata, NULL);
1072
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001073 status = pjsip_pres_send_request(buddy->sub, tdata);
Benny Prijono834aee32006-02-19 01:38:06 +00001074 if (status != PJ_SUCCESS) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001075 pjsip_pres_terminate(buddy->sub, PJ_FALSE);
1076 buddy->sub = NULL;
Benny Prijonobcaed6c2006-02-19 15:37:19 +00001077 pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE",
1078 status);
Benny Prijono834aee32006-02-19 01:38:06 +00001079 return;
1080 }
Benny Prijono834aee32006-02-19 01:38:06 +00001081}
1082
1083
1084/* It does what it says... */
1085static void unsubscribe_buddy_presence(unsigned index)
1086{
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001087 pjsua_buddy *buddy;
Benny Prijono834aee32006-02-19 01:38:06 +00001088 pjsip_tx_data *tdata;
1089 pj_status_t status;
1090
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001091 buddy = &pjsua_var.buddy[index];
1092
1093 if (buddy->sub == NULL)
Benny Prijono834aee32006-02-19 01:38:06 +00001094 return;
1095
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001096 if (pjsip_evsub_get_state(buddy->sub) == PJSIP_EVSUB_STATE_TERMINATED) {
1097 pjsua_var.buddy[index].sub = NULL;
Benny Prijono834aee32006-02-19 01:38:06 +00001098 return;
1099 }
1100
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001101 status = pjsip_pres_initiate( buddy->sub, 0, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +00001102 if (status == PJ_SUCCESS) {
1103 pjsua_process_msg_data(tdata, NULL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001104 status = pjsip_pres_send_request( buddy->sub, tdata );
Benny Prijono21b9ad92006-08-15 13:11:22 +00001105 }
Benny Prijono834aee32006-02-19 01:38:06 +00001106
Benny Prijono1c2bf462006-03-05 11:54:02 +00001107 if (status != PJ_SUCCESS) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001108 pjsip_pres_terminate(buddy->sub, PJ_FALSE);
1109 buddy->sub = NULL;
Benny Prijonobcaed6c2006-02-19 15:37:19 +00001110 pjsua_perror(THIS_FILE, "Unable to unsubscribe presence",
1111 status);
Benny Prijono834aee32006-02-19 01:38:06 +00001112 }
1113}
1114
1115
1116/* It does what it says.. */
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001117static void refresh_client_subscriptions(void)
Benny Prijono834aee32006-02-19 01:38:06 +00001118{
Benny Prijono9fc735d2006-05-28 14:58:12 +00001119 unsigned i;
Benny Prijono834aee32006-02-19 01:38:06 +00001120
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001121 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
Benny Prijono834aee32006-02-19 01:38:06 +00001122
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001123 if (!pjsua_var.buddy[i].uri.slen)
1124 continue;
1125
1126 if (pjsua_var.buddy[i].monitor && !pjsua_var.buddy[i].sub) {
Benny Prijono834aee32006-02-19 01:38:06 +00001127 subscribe_buddy_presence(i);
1128
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001129 } else if (!pjsua_var.buddy[i].monitor && pjsua_var.buddy[i].sub) {
Benny Prijono834aee32006-02-19 01:38:06 +00001130 unsubscribe_buddy_presence(i);
1131
1132 }
1133 }
1134}
1135
1136
1137/*
1138 * Init presence
1139 */
1140pj_status_t pjsua_pres_init()
1141{
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001142 unsigned i;
Benny Prijono834aee32006-02-19 01:38:06 +00001143 pj_status_t status;
1144
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001145 status = pjsip_endpt_register_module( pjsua_var.endpt, &mod_pjsua_pres);
Benny Prijono834aee32006-02-19 01:38:06 +00001146 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +00001147 pjsua_perror(THIS_FILE, "Unable to register pjsua presence module",
1148 status);
Benny Prijono834aee32006-02-19 01:38:06 +00001149 }
1150
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001151 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
1152 reset_buddy(i);
1153 }
1154
Benny Prijono834aee32006-02-19 01:38:06 +00001155 return status;
1156}
1157
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001158
Benny Prijono834aee32006-02-19 01:38:06 +00001159/*
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001160 * Start presence subsystem.
Benny Prijono9fc735d2006-05-28 14:58:12 +00001161 */
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001162pj_status_t pjsua_pres_start(void)
Benny Prijono9fc735d2006-05-28 14:58:12 +00001163{
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001164 /* Nothing to do (is it?) */
Benny Prijono9fc735d2006-05-28 14:58:12 +00001165 return PJ_SUCCESS;
1166}
1167
1168
1169/*
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001170 * Refresh presence subscriptions
Benny Prijono834aee32006-02-19 01:38:06 +00001171 */
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001172void pjsua_pres_refresh()
Benny Prijono834aee32006-02-19 01:38:06 +00001173{
Benny Prijonob9b32ab2006-06-01 12:28:44 +00001174 unsigned i;
1175
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001176 refresh_client_subscriptions();
Benny Prijonob9b32ab2006-06-01 12:28:44 +00001177
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001178 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1179 if (pjsua_var.acc[i].valid)
1180 refresh_server_subscription(i);
1181 }
Benny Prijono834aee32006-02-19 01:38:06 +00001182}
1183
1184
1185/*
1186 * Shutdown presence.
1187 */
1188void pjsua_pres_shutdown(void)
1189{
Benny Prijono9fc735d2006-05-28 14:58:12 +00001190 unsigned i;
Benny Prijono834aee32006-02-19 01:38:06 +00001191
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001192 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1193 if (!pjsua_var.acc[i].valid)
1194 continue;
1195 pjsua_pres_delete_acc(i);
Benny Prijonoa91a0032006-02-26 21:23:45 +00001196 }
1197
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001198 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
1199 pjsua_var.buddy[i].monitor = 0;
Benny Prijono834aee32006-02-19 01:38:06 +00001200 }
Benny Prijonoa91a0032006-02-26 21:23:45 +00001201
Benny Prijonob9b32ab2006-06-01 12:28:44 +00001202 pjsua_pres_refresh();
Benny Prijono834aee32006-02-19 01:38:06 +00001203}