func_pjsip_contact.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2015, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Get information about a PJSIP contact
00022  *
00023  * \author \verbatim Joshua Colp <jcolp@digium.com> \endverbatim
00024  *
00025  * \ingroup functions
00026  *
00027  */
00028 
00029 /*** MODULEINFO
00030    <support_level>core</support_level>
00031    <depend>pjproject</depend>
00032    <depend>res_pjsip</depend>
00033  ***/
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 430180 $")
00038 
00039 #include <pjsip.h>
00040 #include <pjlib.h>
00041 
00042 #include "asterisk/app.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/sorcery.h"
00046 #include "asterisk/res_pjsip.h"
00047 
00048 /*** DOCUMENTATION
00049    <function name="PJSIP_CONTACT" language="en_US">
00050       <synopsis>
00051          Get information about a PJSIP contact
00052       </synopsis>
00053       <syntax>
00054          <parameter name="name" required="true">
00055             <para>The name of the contact to query.</para>
00056          </parameter>
00057          <parameter name="field" required="true">
00058             <para>The configuration option for the contact to query for.
00059             Supported options are those fields on the
00060             <replaceable>contact</replaceable> object.</para>
00061             <enumlist>
00062                <configOptionToEnum>
00063                   <xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='contact']/configOption)"/>
00064                </configOptionToEnum>
00065             </enumlist>
00066          </parameter>
00067       </syntax>
00068    </function>
00069 ***/
00070 
00071 static int contact_function_get_permanent(void *obj, void *arg, int flags)
00072 {
00073    const char *id = arg;
00074 
00075    if (!strcmp(ast_sorcery_object_get_id(obj), id)) {
00076       return CMP_MATCH | CMP_STOP;
00077    }
00078 
00079    return 0;
00080 }
00081 
00082 static int pjsip_contact_function_read(struct ast_channel *chan,
00083    const char *cmd, char *data, struct ast_str **buf, ssize_t len)
00084 {
00085    struct ast_sorcery *pjsip_sorcery;
00086    char *parsed_data = ast_strdupa(data);
00087    char *contact_name;
00088    RAII_VAR(struct ast_sip_contact *, contact_obj, NULL, ao2_cleanup);
00089    RAII_VAR(struct ast_sip_contact_status *, contact_status, NULL, ao2_cleanup);
00090    int res = 0;
00091 
00092    AST_DECLARE_APP_ARGS(args,
00093       AST_APP_ARG(contact_name);
00094       AST_APP_ARG(field_name);
00095    );
00096 
00097    /* Check for zero arguments */
00098    if (ast_strlen_zero(parsed_data)) {
00099       ast_log(AST_LOG_ERROR, "Cannot call %s without arguments\n", cmd);
00100       return -1;
00101    }
00102 
00103    AST_STANDARD_APP_ARGS(args, parsed_data);
00104 
00105    if (ast_strlen_zero(args.contact_name)) {
00106       ast_log(AST_LOG_ERROR, "Cannot call %s without a contact name to query\n", cmd);
00107       return -1;
00108    }
00109 
00110    if (ast_strlen_zero(args.field_name)) {
00111       ast_log(AST_LOG_ERROR, "Cannot call %s with an empty field name to query\n", cmd);
00112       return -1;
00113    }
00114 
00115    pjsip_sorcery = ast_sip_get_sorcery();
00116    if (!pjsip_sorcery) {
00117       ast_log(AST_LOG_ERROR, "Unable to retrieve PJSIP configuration: sorcery object is NULL\n");
00118       return -1;
00119    }
00120 
00121    /* Determine if this is a permanent contact or a normal contact */
00122    if ((contact_name = strstr(args.contact_name, "@@"))) {
00123       size_t aor_name_len = contact_name - args.contact_name;
00124       char aor_name[aor_name_len + 1];
00125       RAII_VAR(struct ast_sip_aor *, aor_obj, NULL, ao2_cleanup);
00126 
00127       /* Grab only the AOR name so we can retrieve the AOR which will give us the contact */
00128       strncpy(aor_name, args.contact_name, aor_name_len);
00129       aor_name[aor_name_len] = '\0';
00130 
00131       aor_obj = ast_sorcery_retrieve_by_id(pjsip_sorcery, "aor", aor_name);
00132       if (!aor_obj) {
00133          ast_log(AST_LOG_WARNING, "Failed to retrieve information for contact '%s'\n", args.contact_name);
00134          return -1;
00135       }
00136 
00137       contact_obj = ao2_callback(aor_obj->permanent_contacts, 0, contact_function_get_permanent, args.contact_name);
00138    } else {
00139       contact_obj = ast_sorcery_retrieve_by_id(pjsip_sorcery, "contact", args.contact_name);
00140    }
00141 
00142    if (!contact_obj) {
00143       ast_log(AST_LOG_WARNING, "Failed to retrieve information for contact '%s'\n", args.contact_name);
00144       return -1;
00145    }
00146 
00147    contact_status = ast_sorcery_retrieve_by_id(pjsip_sorcery, CONTACT_STATUS, ast_sorcery_object_get_id(contact_obj));
00148 
00149    if (!strcmp(args.field_name, "status")) {
00150       if (!contact_status) {
00151          ast_str_set(buf, len, "%s", "Unknown");
00152       } else if (contact_status->status == UNAVAILABLE) {
00153          ast_str_set(buf, len, "%s", "Unreachable");
00154       } else if (contact_status->status == AVAILABLE) {
00155          ast_str_set(buf, len, "%s", "Reachable");
00156       }
00157    } else if (!strcmp(args.field_name, "rtt")) {
00158       if (!contact_status) {
00159          ast_str_set(buf, len, "%s", "N/A");
00160       } else {
00161          ast_str_set(buf, len, "%" PRId64, contact_status->rtt);
00162       }
00163    } else {
00164       struct ast_variable *change_set;
00165       struct ast_variable *it_change_set;
00166 
00167       change_set = ast_sorcery_objectset_create(pjsip_sorcery, contact_obj);
00168 
00169       if (!change_set) {
00170          ast_log(AST_LOG_WARNING, "Failed to retrieve information for contact '%s': change set is NULL\n", args.contact_name);
00171          return -1;
00172       }
00173 
00174       for (it_change_set = change_set; it_change_set; it_change_set = it_change_set->next) {
00175          if (!strcmp(it_change_set->name, args.field_name)) {
00176             ast_str_set(buf, len, "%s", it_change_set->value);
00177             break;
00178          }
00179       }
00180 
00181       if (!it_change_set) {
00182          ast_log(AST_LOG_WARNING, "Unknown property '%s' for PJSIP contact\n", args.field_name);
00183 
00184          res = 1;
00185       }
00186 
00187       ast_variables_destroy(change_set);
00188    }
00189 
00190    return res;
00191 }
00192 
00193 
00194 static struct ast_custom_function pjsip_contact_function = {
00195    .name = "PJSIP_CONTACT",
00196    .read2 = pjsip_contact_function_read,
00197 };
00198 
00199 static int unload_module(void)
00200 {
00201    return ast_custom_function_unregister(&pjsip_contact_function);
00202 }
00203 
00204 static int load_module(void)
00205 {
00206    return ast_custom_function_register(&pjsip_contact_function);
00207 }
00208 
00209 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get information about a PJSIP contact");

Generated on Thu Apr 16 06:27:36 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6