⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjsua_pres.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $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 + -