📄 pjsua_pres.c
字号:
/* $Id: pjsua_pres.c 1086 2007-03-20 09:11:40Z bennylp $ *//* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.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 <pjsua-lib/pjsua.h>#include <pjsua-lib/pjsua_internal.h>#define THIS_FILE "pjsua_pres.c"/* * Get total number of buddies. */PJ_DEF(unsigned) pjsua_get_buddy_count(void){ return pjsua_var.buddy_cnt;}/* * Check if buddy ID is valid. */PJ_DEF(pj_bool_t) pjsua_buddy_is_valid(pjsua_buddy_id buddy_id){ return buddy_id>=0 && buddy_id<PJ_ARRAY_SIZE(pjsua_var.buddy) && pjsua_var.buddy[buddy_id].uri.slen != 0;}/* * Enum buddy IDs. */PJ_DEF(pj_status_t) pjsua_enum_buddies( pjsua_buddy_id ids[], unsigned *count){ unsigned i, c; PJ_ASSERT_RETURN(ids && count, PJ_EINVAL); PJSUA_LOCK(); for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { if (!pjsua_var.buddy[i].uri.slen) continue; ids[c] = i; ++c; } *count = c; PJSUA_UNLOCK(); return PJ_SUCCESS;}/* * Get detailed buddy info. */PJ_DEF(pj_status_t) pjsua_buddy_get_info( pjsua_buddy_id buddy_id, pjsua_buddy_info *info){ int total=0; pjsua_buddy *buddy; PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); PJSUA_LOCK(); pj_bzero(info, sizeof(pjsua_buddy_info)); buddy = &pjsua_var.buddy[buddy_id]; info->id = buddy->index; if (pjsua_var.buddy[buddy_id].uri.slen == 0) { PJSUA_UNLOCK(); return PJ_SUCCESS; } /* uri */ info->uri.ptr = info->buf_ + total; pj_strncpy(&info->uri, &buddy->uri, sizeof(info->buf_)-total); total += info->uri.slen; /* contact */ info->contact.ptr = info->buf_ + total; pj_strncpy(&info->contact, &buddy->contact, sizeof(info->buf_)-total); total += info->contact.slen; /* status and status text */ if (buddy->sub == NULL || buddy->status.info_cnt==0) { info->status = PJSUA_BUDDY_STATUS_UNKNOWN; info->status_text = pj_str("?"); } else if (pjsua_var.buddy[buddy_id].status.info[0].basic_open) { info->status = PJSUA_BUDDY_STATUS_ONLINE; info->status_text = pj_str("Online"); } else { info->status = PJSUA_BUDDY_STATUS_OFFLINE; info->status_text = pj_str("Offline"); } /* monitor pres */ info->monitor_pres = buddy->monitor; PJSUA_UNLOCK(); return PJ_SUCCESS;}/* * Reset buddy descriptor. */static void reset_buddy(pjsua_buddy_id id){ pj_bzero(&pjsua_var.buddy[id], sizeof(pjsua_var.buddy[id])); pjsua_var.buddy[id].index = id;}/* * Add new buddy. */PJ_DEF(pj_status_t) pjsua_buddy_add( const pjsua_buddy_config *cfg, pjsua_buddy_id *p_buddy_id){ pjsip_name_addr *url; pjsip_sip_uri *sip_uri; int index; pj_str_t tmp; PJ_ASSERT_RETURN(pjsua_var.buddy_cnt <= PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_ETOOMANY); PJSUA_LOCK(); /* Find empty slot */ for (index=0; index<PJ_ARRAY_SIZE(pjsua_var.buddy); ++index) { if (pjsua_var.buddy[index].uri.slen == 0) break; } /* Expect to find an empty slot */ if (index == PJ_ARRAY_SIZE(pjsua_var.buddy)) { PJSUA_UNLOCK(); /* This shouldn't happen */ pj_assert(!"index < PJ_ARRAY_SIZE(pjsua_var.buddy)"); return PJ_ETOOMANY; } /* Get name and display name for buddy */ pj_strdup_with_null(pjsua_var.pool, &tmp, &cfg->uri); url = (pjsip_name_addr*)pjsip_parse_uri(pjsua_var.pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (url == NULL) { pjsua_perror(THIS_FILE, "Unable to add buddy", PJSIP_EINVALIDURI); PJSUA_UNLOCK(); return PJSIP_EINVALIDURI; } /* Only support SIP schemes */ if (!PJSIP_URI_SCHEME_IS_SIP(url) && !PJSIP_URI_SCHEME_IS_SIPS(url)) return PJSIP_EINVALIDSCHEME; /* Reset buddy, to make sure everything is cleared with default * values */ reset_buddy(index); /* Save URI */ pjsua_var.buddy[index].uri = tmp; sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(url->uri); pjsua_var.buddy[index].name = sip_uri->user; pjsua_var.buddy[index].display = url->display; pjsua_var.buddy[index].host = sip_uri->host; pjsua_var.buddy[index].port = sip_uri->port; pjsua_var.buddy[index].monitor = cfg->subscribe; if (pjsua_var.buddy[index].port == 0) pjsua_var.buddy[index].port = 5060; if (p_buddy_id) *p_buddy_id = index; pjsua_var.buddy_cnt++; pjsua_buddy_subscribe_pres(index, cfg->subscribe); PJSUA_UNLOCK(); return PJ_SUCCESS;}/* * Delete buddy. */PJ_DEF(pj_status_t) pjsua_buddy_del(pjsua_buddy_id buddy_id){ PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); PJSUA_LOCK(); if (pjsua_var.buddy[buddy_id].uri.slen == 0) { PJSUA_UNLOCK(); return PJ_SUCCESS; } /* Unsubscribe presence */ pjsua_buddy_subscribe_pres(buddy_id, PJ_FALSE); /* Remove buddy */ pjsua_var.buddy[buddy_id].uri.slen = 0; pjsua_var.buddy_cnt--; /* Reset buddy struct */ reset_buddy(buddy_id); PJSUA_UNLOCK(); return PJ_SUCCESS;}/* * Enable/disable buddy's presence monitoring. */PJ_DEF(pj_status_t) pjsua_buddy_subscribe_pres( pjsua_buddy_id buddy_id, pj_bool_t subscribe){ pjsua_buddy *buddy; PJ_ASSERT_RETURN(buddy_id>=0 && buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), PJ_EINVAL); PJSUA_LOCK(); buddy = &pjsua_var.buddy[buddy_id]; buddy->monitor = subscribe; pjsua_pres_refresh(); PJSUA_UNLOCK(); return PJ_SUCCESS;}/* * Dump presence subscriptions to log file. */PJ_DEF(void) pjsua_pres_dump(pj_bool_t verbose){ unsigned acc_id; unsigned i; PJSUA_LOCK(); /* * When no detail is required, just dump number of server and client * subscriptions. */ if (verbose == PJ_FALSE) { int count = 0; for (acc_id=0; acc_id<PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) { if (!pjsua_var.acc[acc_id].valid) continue; if (!pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) { struct pjsua_srv_pres *uapres; uapres = pjsua_var.acc[acc_id].pres_srv_list.next; while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { ++count; uapres = uapres->next; } } } PJ_LOG(3,(THIS_FILE, "Number of server/UAS subscriptions: %d", count)); count = 0; for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { if (pjsua_var.buddy[i].uri.slen == 0) continue; if (pjsua_var.buddy[i].sub) { ++count; } } PJ_LOG(3,(THIS_FILE, "Number of client/UAC subscriptions: %d", count)); PJSUA_UNLOCK(); return; } /* * Dumping all server (UAS) subscriptions */ PJ_LOG(3,(THIS_FILE, "Dumping pjsua server subscriptions:")); for (acc_id=0; acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++acc_id) { if (!pjsua_var.acc[acc_id].valid) continue; PJ_LOG(3,(THIS_FILE, " %.*s", (int)pjsua_var.acc[acc_id].cfg.id.slen, pjsua_var.acc[acc_id].cfg.id.ptr)); if (pj_list_empty(&pjsua_var.acc[acc_id].pres_srv_list)) { PJ_LOG(3,(THIS_FILE, " - none - ")); } else { struct pjsua_srv_pres *uapres; uapres = pjsua_var.acc[acc_id].pres_srv_list.next; while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { PJ_LOG(3,(THIS_FILE, " %10s %s", pjsip_evsub_get_state_name(uapres->sub), uapres->remote)); uapres = uapres->next; } } } /* * Dumping all client (UAC) subscriptions */ PJ_LOG(3,(THIS_FILE, "Dumping pjsua client subscriptions:")); if (pjsua_var.buddy_cnt == 0) { PJ_LOG(3,(THIS_FILE, " - no buddy list - ")); } else { for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { if (pjsua_var.buddy[i].uri.slen == 0) continue; if (pjsua_var.buddy[i].sub) { PJ_LOG(3,(THIS_FILE, " %10s %.*s", pjsip_evsub_get_state_name(pjsua_var.buddy[i].sub), (int)pjsua_var.buddy[i].uri.slen, pjsua_var.buddy[i].uri.ptr)); } else { PJ_LOG(3,(THIS_FILE, " %10s %.*s", "(null)", (int)pjsua_var.buddy[i].uri.slen, pjsua_var.buddy[i].uri.ptr)); } } } PJSUA_UNLOCK();}/*************************************************************************** * Server subscription. *//* Proto */static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata);/* The module instance. */static pjsip_module mod_pjsua_pres = { NULL, NULL, /* prev, next. */ { "mod-pjsua-pres", 14 }, /* Name. */ -1, /* Id */ PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ NULL, /* load() */ NULL, /* start() */ NULL, /* stop() */ NULL, /* unload() */ &pres_on_rx_request, /* on_rx_request() */ NULL, /* on_rx_response() */ NULL, /* on_tx_request. */ NULL, /* on_tx_response() */ NULL, /* on_tsx_state() */};/* Callback called when *server* subscription state has changed. */static void pres_evsub_on_srv_state( pjsip_evsub *sub, pjsip_event *event){ pjsua_srv_pres *uapres; PJ_UNUSED_ARG(event); PJSUA_LOCK(); uapres = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); if (uapres) { PJ_LOG(3,(THIS_FILE, "Server subscription to %s is %s", uapres->remote, pjsip_evsub_get_state_name(sub))); if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); pj_list_erase(uapres); } } PJSUA_UNLOCK();}/* This is called when request is received. * We need to check for incoming SUBSCRIBE request. */static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata){ int acc_id; pjsua_acc *acc; pj_str_t contact; pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; pjsua_srv_pres *uapres; pjsip_evsub *sub; pjsip_evsub_user pres_cb; pjsip_tx_data *tdata; pjsip_pres_status pres_status; pjsip_dialog *dlg; pj_status_t status; if (pjsip_method_cmp(req_method, &pjsip_subscribe_method) != 0) return PJ_FALSE; /* Incoming SUBSCRIBE: */ PJSUA_LOCK(); /* Find which account for the incoming request. */ acc_id = pjsua_acc_find_for_incoming(rdata); acc = &pjsua_var.acc[acc_id]; PJ_LOG(4,(THIS_FILE, "Creating server subscription, using account %d", acc_id)); /* Create suitable Contact header */ status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact, acc_id, rdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); PJSUA_UNLOCK(); return PJ_TRUE; } /* Create UAS dialog: */ status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create UAS dialog for subscription", status); PJSUA_UNLOCK(); return PJ_TRUE; } /* Set credentials. */ pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred); /* Init callback: */ pj_bzero(&pres_cb, sizeof(pres_cb)); pres_cb.on_evsub_state = &pres_evsub_on_srv_state; /* Create server presence subscription: */ status = pjsip_pres_create_uas( dlg, &pres_cb, rdata, &sub); if (status != PJ_SUCCESS) { pjsip_dlg_terminate(dlg); pjsua_perror(THIS_FILE, "Unable to create server subscription", status); PJSUA_UNLOCK(); return PJ_TRUE; } /* If account is locked to specific transport, then lock dialog * to this transport too. */ if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); pjsip_dlg_set_transport(dlg, &tp_sel); } /* Attach our data to the subscription: */ uapres = pj_pool_alloc(dlg->pool, sizeof(pjsua_srv_pres)); uapres->sub = sub; uapres->remote = pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE); status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, uapres->remote, PJSIP_MAX_URL_SIZE); if (status < 1) pj_ansi_strcpy(uapres->remote, "<-- url is too long-->"); else uapres->remote[status] = '\0'; pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, uapres); /* Add server subscription to the list: */ pj_list_push_back(&pjsua_var.acc[acc_id].pres_srv_list, uapres); /* Create and send 200 (OK) to the SUBSCRIBE request: */ status = pjsip_pres_accept(sub, rdata, 200, NULL); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to accept presence subscription", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* Set our online status: */ pj_bzero(&pres_status, sizeof(pres_status)); pres_status.info_cnt = 1; pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status; //Both pjsua_var.local_uri and pjsua_var.contact_uri are enclosed in "<" and ">" //causing XML parsing to fail. //pres_status.info[0].contact = pjsua_var.local_uri; pjsip_pres_set_status(sub, &pres_status); /* Create and send the first NOTIFY to active subscription: */ status = pjsip_pres_notify( sub, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, &tdata); if (status == PJ_SUCCESS) { pjsua_process_msg_data(tdata, NULL); status = pjsip_pres_send_request( sub, tdata); } if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create/send NOTIFY", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* Done: */ PJSUA_UNLOCK(); return PJ_TRUE;}/* * Client presence publication callback. */static void publish_cb(struct pjsip_publishc_cbparam *param){ pjsua_acc *acc = param->token; if (param->code/100 != 2 || param->status != PJ_SUCCESS) { if (param->status != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(param->status, errmsg, sizeof(errmsg)); PJ_LOG(1,(THIS_FILE, "Client publication (PUBLISH) failed, status=%d, msg=%s", param->status, errmsg)); } else { PJ_LOG(1,(THIS_FILE, "Client publication (PUBLISH) failed (%d/%.*s)", param->code, (int)param->reason.slen,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -