Wed Jul 14 06:25:49 2010

Asterisk developer's documentation


func_redirecting.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2008 Digium, Inc.
00005  *
00006  * Richard Mudgett <rmudgett@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 /*!
00020  * \file
00021  * \brief Redirecting data dialplan function
00022  * \ingroup functions
00023  *
00024  * \author Richard Mudgett <rmudgett@digium.com>
00025  *
00026  * See Also:
00027  * \arg \ref AstCREDITS
00028  */
00029 
00030 
00031 #include "asterisk.h"
00032 
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 263541 $")
00034 
00035 /* ------------------------------------------------------------------- */
00036 
00037 
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <string.h>
00041 #include <sys/types.h>
00042 
00043 #include "asterisk/module.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/app.h"
00049 #include "asterisk/options.h"
00050 #include "asterisk/callerid.h"
00051 
00052 /*
00053  * Do not document the REDIRECTING(pres) datatype.
00054  * It has turned out that the from-pres and to-pres values must be kept
00055  * separate.  They represent two different parties and there is a case when
00056  * they are active at the same time.  The plain pres option will simply
00057  * live on as a historical relic.
00058  */
00059 /*** DOCUMENTATION
00060    <function name="REDIRECTING" language="en_US">
00061       <synopsis>
00062          Gets or sets Redirecting data on the channel.
00063       </synopsis>
00064       <syntax>
00065          <parameter name="datatype" required="true">
00066             <para>The allowable datatypes are:</para>
00067             <enumlist>
00068                <enum name = "from-all" />
00069                <enum name = "from-num" />
00070                <enum name = "from-name" />
00071                <enum name = "from-tag" />
00072                <enum name = "from-ton" />
00073                <enum name = "from-pres" />
00074                <enum name = "to-all" />
00075                <enum name = "to-num" />
00076                <enum name = "to-name" />
00077                <enum name = "to-tag" />
00078                <enum name = "to-ton" />
00079                <enum name = "to-pres" />
00080                <enum name = "reason" />
00081                <enum name = "count" />
00082             </enumlist>
00083          </parameter>
00084          <parameter name="i">
00085             <para>If set, this will prevent the channel from sending out protocol
00086             messages because of the value being set</para>
00087          </parameter>
00088       </syntax>
00089       <description>
00090          <para>Gets or sets Redirecting data on the channel. The allowable values
00091          for the <replaceable>reason</replaceable> field are the following:</para>
00092          <enumlist>
00093             <enum name = "unknown"><para>Unknown</para></enum>
00094             <enum name = "cfb"><para>Call Forwarding Busy</para></enum>
00095             <enum name = "cfnr"><para>Call Forwarding No Reply</para></enum>
00096             <enum name = "unavailable"><para>Callee is Unavailable</para></enum>
00097             <enum name = "time_of_day"><para>Time of Day</para></enum>
00098             <enum name = "dnd"><para>Do Not Disturb</para></enum>
00099             <enum name = "deflection"><para>Call Deflection</para></enum>
00100             <enum name = "follow_me"><para>Follow Me</para></enum>
00101             <enum name = "out_of_order"><para>Called DTE Out-Of-Order</para></enum>
00102             <enum name = "away"><para>Callee is Away</para></enum>
00103             <enum name = "cf_dte"><para>Call Forwarding By The Called DTE</para></enum>
00104             <enum name = "cfu"><para>Call Forwarding Unconditional</para></enum>
00105          </enumlist>
00106       </description>
00107    </function>
00108  ***/
00109 
00110 enum ID_FIELD_STATUS {
00111    ID_FIELD_VALID,
00112    ID_FIELD_INVALID,
00113    ID_FIELD_UNKNOWN
00114 };
00115 
00116 
00117 
00118 
00119 /* ******************************************************************* */
00120 /*!
00121  * \internal
00122  * \brief Read values from the party id struct.
00123  *
00124  * \param buf Buffer to fill with read value.
00125  * \param len Length of the buffer
00126  * \param data Remaining function datatype string
00127  *
00128  * \retval ID_FIELD_VALID on success.
00129  * \retval ID_FIELD_UNKNOWN on unknown field name.
00130  */
00131 static enum ID_FIELD_STATUS redirecting_id_read(char *buf, size_t len, char *data, const struct ast_party_id *id)
00132 {
00133    enum ID_FIELD_STATUS status;
00134 
00135    status = ID_FIELD_VALID;
00136 
00137    if (!strncasecmp("all", data, 3)) {
00138       snprintf(buf, len, "\"%s\" <%s>",
00139           S_OR(id->name, ""),
00140           S_OR(id->number, ""));
00141    } else if (!strncasecmp("name", data, 4)) {
00142       if (id->name) {
00143          ast_copy_string(buf, id->name, len);
00144       }
00145    } else if (!strncasecmp("num", data, 3)) {
00146       if (id->number) {
00147          ast_copy_string(buf, id->number, len);
00148       }
00149    } else if (!strncasecmp("tag", data, 3)) {
00150       if (id->tag) {
00151          ast_copy_string(buf, id->tag, len);
00152       }
00153    } else if (!strncasecmp("ton", data, 3)) {
00154       snprintf(buf, len, "%d", id->number_type);
00155    } else if (!strncasecmp("pres", data, 4)) {
00156       ast_copy_string(buf, ast_named_caller_presentation(id->number_presentation), len);
00157    } else {
00158       status = ID_FIELD_UNKNOWN;
00159    }
00160 
00161    return status;
00162 }
00163 
00164 
00165 
00166 
00167 /* ******************************************************************* */
00168 /*!
00169  * \internal
00170  * \brief Read values from the redirecting information struct.
00171  *
00172  * \param chan Asterisk channel to read
00173  * \param cmd Not used
00174  * \param data Redirecting function datatype string
00175  * \param buf Buffer to fill with read value.
00176  * \param len Length of the buffer
00177  *
00178  * \retval 0 on success.
00179  * \retval -1 on error.
00180  */
00181 static int redirecting_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00182 {
00183    /* Ensure that the buffer is empty */
00184    *buf = 0;
00185 
00186    if (!chan)
00187       return -1;
00188 
00189    ast_channel_lock(chan);
00190 
00191    if (!strncasecmp("from-", data, 5)) {
00192       switch (redirecting_id_read(buf, len, data + 5, &chan->redirecting.from)) {
00193       case ID_FIELD_VALID:
00194       case ID_FIELD_INVALID:
00195          break;
00196 
00197       default:
00198          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
00199          break;
00200       }
00201    } else if (!strncasecmp("to-", data, 3)) {
00202       switch (redirecting_id_read(buf, len, data + 3, &chan->redirecting.to)) {
00203       case ID_FIELD_VALID:
00204       case ID_FIELD_INVALID:
00205          break;
00206 
00207       default:
00208          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
00209          break;
00210       }
00211    } else if (!strncasecmp("pres", data, 4)) {
00212       ast_copy_string(buf, ast_named_caller_presentation(chan->redirecting.from.number_presentation), len);
00213    } else if (!strncasecmp("reason", data, 6)) {
00214       ast_copy_string(buf, ast_redirecting_reason_name(chan->redirecting.reason), len);
00215    } else if (!strncasecmp("count", data, 5)) {
00216       snprintf(buf, len, "%d", chan->redirecting.count);
00217    } else {
00218       ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
00219    }
00220 
00221    ast_channel_unlock(chan);
00222 
00223    return 0;
00224 }
00225 
00226 
00227 
00228 
00229 /* ******************************************************************* */
00230 /*!
00231  * \internal
00232  * \brief Write new values to the party id struct
00233  *
00234  * \param id Party ID struct to write values
00235  * \param data Remaining function datatype string
00236  * \param value Value to assign to the party id.
00237  *
00238  * \retval ID_FIELD_VALID on success.
00239  * \retval ID_FIELD_INVALID on error with field value.
00240  * \retval ID_FIELD_UNKNOWN on unknown field name.
00241  */
00242 static enum ID_FIELD_STATUS redirecting_id_write(struct ast_party_id *id, char *data, const char *value)
00243 {
00244    char *val;
00245    enum ID_FIELD_STATUS status;
00246 
00247    status = ID_FIELD_VALID;
00248 
00249    if (!strncasecmp("all", data, 3)) {
00250       char name[256];
00251       char num[256];
00252 
00253       ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
00254       if (!(id->name = ast_strdup(name))) {
00255          return ID_FIELD_INVALID;
00256       }
00257       if (!(id->number = ast_strdup(num))) {
00258          return ID_FIELD_INVALID;
00259       }
00260    } else if (!strncasecmp("name", data, 4)) {
00261       id->name = ast_strdup(value);
00262       ast_trim_blanks(id->name);
00263    } else if (!strncasecmp("num", data, 3)) {
00264       id->number = ast_strdup(value);
00265       ast_trim_blanks(id->number);
00266    } else if (!strncasecmp("tag", data, 3)) {
00267       id->tag = ast_strdup(value);
00268       ast_trim_blanks(id->tag);
00269    } else if (!strncasecmp("ton", data, 3)) {
00270       val = ast_strdupa(value);
00271       ast_trim_blanks(val);
00272 
00273       if (('0' <= val[0]) && (val[0] <= '9')) {
00274          id->number_type = atoi(val);
00275       } else {
00276          ast_log(LOG_ERROR, "Unknown redirecting type of number '%s', value unchanged\n", val);
00277          status = ID_FIELD_INVALID;
00278       }
00279    } else if (!strncasecmp("pres", data, 4)) {
00280       int pres;
00281 
00282       val = ast_strdupa(value);
00283       ast_trim_blanks(val);
00284 
00285       if (('0' <= val[0]) && (val[0] <= '9')) {
00286          pres = atoi(val);
00287       } else {
00288          pres = ast_parse_caller_presentation(val);
00289       }
00290 
00291       if (pres < 0) {
00292          ast_log(LOG_ERROR, "Unknown redirecting number presentation '%s', value unchanged\n", val);
00293          status = ID_FIELD_INVALID;
00294       } else {
00295          id->number_presentation = pres;
00296       }
00297    } else {
00298       status = ID_FIELD_UNKNOWN;
00299    }
00300 
00301    return status;
00302 }
00303 
00304 
00305 
00306 
00307 /* ******************************************************************* */
00308 /*!
00309  * \internal
00310  * \brief Write new values to the redirecting information struct.
00311  *
00312  * \param chan Asterisk channel to update
00313  * \param cmd Not used
00314  * \param data Redirecting function datatype string
00315  * \param value Value to assign to the redirecting information struct.
00316  *
00317  * \retval 0 on success.
00318  * \retval -1 on error.
00319  */
00320 static int redirecting_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00321 {
00322    struct ast_party_redirecting redirecting;
00323    char *val;
00324    char *option;
00325    void (*set_it)(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
00326 
00327    if (!value || !chan) {
00328       return -1;
00329    }
00330 
00331    /* Determine if the update indication inhibit option is present */
00332    option = strchr(data, ',');
00333    if (option) {
00334       option = ast_skip_blanks(option + 1);
00335       switch (*option) {
00336       case 'i':
00337          set_it = ast_channel_set_redirecting;
00338          break;
00339 
00340       default:
00341          ast_log(LOG_ERROR, "Unknown redirecting option '%s'.\n", option);
00342          return 0;
00343       }
00344    }
00345    else {
00346       set_it = ast_channel_update_redirecting;
00347    }
00348 
00349    ast_channel_lock(chan);
00350    ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
00351    ast_channel_unlock(chan);
00352 
00353    value = ast_skip_blanks(value);
00354 
00355    if (!strncasecmp("from-", data, 5)) {
00356       switch (redirecting_id_write(&redirecting.from, data + 5, value)) {
00357       case ID_FIELD_VALID:
00358          set_it(chan, &redirecting);
00359          break;
00360 
00361       case ID_FIELD_INVALID:
00362          break;
00363 
00364       default:
00365          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
00366          break;
00367       }
00368       ast_party_redirecting_free(&redirecting);
00369    } else if (!strncasecmp("to-", data, 3)) {
00370       switch (redirecting_id_write(&redirecting.to, data + 3, value)) {
00371       case ID_FIELD_VALID:
00372          set_it(chan, &redirecting);
00373          break;
00374 
00375       case ID_FIELD_INVALID:
00376          break;
00377 
00378       default:
00379          ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
00380          break;
00381       }
00382       ast_party_redirecting_free(&redirecting);
00383    } else if (!strncasecmp("pres", data, 4)) {
00384       int pres;
00385 
00386       val = ast_strdupa(value);
00387       ast_trim_blanks(val);
00388 
00389       if (('0' <= val[0]) && (val[0] <= '9')) {
00390          pres = atoi(val);
00391       } else {
00392          pres = ast_parse_caller_presentation(val);
00393       }
00394 
00395       if (pres < 0) {
00396          ast_log(LOG_ERROR, "Unknown redirecting number presentation '%s', value unchanged\n", val);
00397       } else {
00398          redirecting.from.number_presentation = pres;
00399          redirecting.to.number_presentation = pres;
00400          set_it(chan, &redirecting);
00401       }
00402    } else if (!strncasecmp("reason", data, 6)) {
00403       int reason;
00404 
00405       val = ast_strdupa(value);
00406       ast_trim_blanks(val);
00407 
00408       if (('0' <= val[0]) && (val[0] <= '9')) {
00409          reason = atoi(val);
00410       } else {
00411          reason = ast_redirecting_reason_parse(val);
00412       }
00413 
00414       if (reason < 0) {
00415          ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val);
00416       } else {
00417          redirecting.reason = reason;
00418          set_it(chan, &redirecting);
00419       }
00420    } else if (!strncasecmp("count", data, 5)) {
00421       val = ast_strdupa(value);
00422       ast_trim_blanks(val);
00423 
00424       if (('0' <= val[0]) && (val[0] <= '9')) {
00425          redirecting.count = atoi(val);
00426          set_it(chan, &redirecting);
00427       } else {
00428          ast_log(LOG_ERROR, "Unknown redirecting count '%s', value unchanged\n", val);
00429       }
00430    } else {
00431       ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
00432    }
00433 
00434    return 0;
00435 }
00436 
00437 
00438 
00439 
00440 static struct ast_custom_function redirecting_function = {
00441    .name = "REDIRECTING",
00442    .read = redirecting_read,
00443    .write = redirecting_write,
00444 };
00445 
00446 
00447 
00448 
00449 /* ******************************************************************* */
00450 /*!
00451  * \internal
00452  * \brief Unload the function module
00453  *
00454  * \retval 0 on success.
00455  * \retval -1 on error.
00456  */
00457 static int unload_module(void)
00458 {
00459    return ast_custom_function_unregister(&redirecting_function);
00460 }
00461 
00462 
00463 
00464 
00465 /* ******************************************************************* */
00466 /*!
00467  * \internal
00468  * \brief Load and initialize the function module.
00469  *
00470  * \retval 0 on success.
00471  * \retval -1 on error.
00472  */
00473 static int load_module(void)
00474 {
00475    return ast_custom_function_register(&redirecting_function)
00476       ? AST_MODULE_LOAD_DECLINE
00477       : AST_MODULE_LOAD_SUCCESS;
00478 }
00479 
00480 
00481 
00482 
00483 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Redirecting data dialplan function");
00484 
00485 
00486 /* ------------------------------------------------------------------- */
00487 /* end func_redirecting.c */

Generated on Wed Jul 14 06:25:49 2010 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6