Sun May 20 06:33:55 2012

Asterisk developer's documentation


message.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2010, Digium, Inc.
00005  *
00006  * Russell Bryant <russell@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 Out-of-call text message support
00022  *
00023  * \author Russell Bryant <russell@digium.com>
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 361523 $")
00029 
00030 #include "asterisk/_private.h"
00031 
00032 #include "asterisk/module.h"
00033 #include "asterisk/datastore.h"
00034 #include "asterisk/pbx.h"
00035 #include "asterisk/strings.h"
00036 #include "asterisk/astobj2.h"
00037 #include "asterisk/app.h"
00038 #include "asterisk/taskprocessor.h"
00039 #include "asterisk/message.h"
00040 
00041 /*** DOCUMENTATION
00042    <function name="MESSAGE" language="en_US">
00043       <synopsis>
00044          Create a message or read fields from a message.
00045       </synopsis>
00046       <syntax argsep="/">
00047          <parameter name="argument" required="true">
00048          <para>Field of the message to get or set.</para>
00049          <enumlist>
00050             <enum name="to">
00051                <para>Read-only.  The destination of the message.  When processing an
00052                incoming message, this will be set to the destination listed as
00053                the recipient of the message that was received by Asterisk.</para>
00054             </enum>
00055             <enum name="from">
00056                <para>Read-only.  The source of the message.  When processing an
00057                incoming message, this will be set to the source of the message.</para>
00058             </enum>
00059             <enum name="body">
00060                <para>Read/Write.  The message body.  When processing an incoming
00061                message, this includes the body of the message that Asterisk
00062                received.  When MessageSend() is executed, the contents of this
00063                field are used as the body of the outgoing message.  The body
00064                will always be UTF-8.</para>
00065             </enum>
00066          </enumlist>
00067          </parameter>
00068       </syntax>
00069       <description>
00070          <para>This function will read from or write a value to a text message.
00071          It is used both to read the data out of an incoming message, as well as
00072          modify or create a message that will be sent outbound.</para>
00073       </description>
00074       <see-also>
00075          <ref type="application">MessageSend</ref>
00076       </see-also>
00077    </function>
00078    <function name="MESSAGE_DATA" language="en_US">
00079       <synopsis>
00080          Read or write custom data attached to a message.
00081       </synopsis>
00082       <syntax argsep="/">
00083          <parameter name="argument" required="true">
00084          <para>Field of the message to get or set.</para>
00085          </parameter>
00086       </syntax>
00087       <description>
00088          <para>This function will read from or write a value to a text message.
00089          It is used both to read the data out of an incoming message, as well as
00090          modify a message that will be sent outbound.</para>
00091          <note>
00092             <para>If you want to set an outbound message to carry data in the
00093             current message, do
00094             Set(MESSAGE_DATA(<replaceable>key</replaceable>)=${MESSAGE_DATA(<replaceable>key</replaceable>)}).</para>
00095          </note>
00096       </description>
00097       <see-also>
00098          <ref type="application">MessageSend</ref>
00099       </see-also>
00100    </function>
00101    <application name="MessageSend" language="en_US">
00102       <synopsis>
00103          Send a text message.
00104       </synopsis>
00105       <syntax>
00106          <parameter name="to" required="true">
00107             <para>A To URI for the message.</para>
00108          </parameter>
00109          <parameter name="from" required="false">
00110             <para>A From URI for the message if needed for the
00111             message technology being used to send this message.</para>
00112             <note>
00113                <para>For SIP the from parameter can be a configured peer name
00114                or in the form of "display-name" &lt;URI&gt;.</para>
00115             </note>
00116          </parameter>
00117       </syntax>
00118       <description>
00119          <para>Send a text message.  The body of the message that will be
00120          sent is what is currently set to <literal>MESSAGE(body)</literal>.</para>
00121 
00122          <para>This application sets the following channel variables:</para>
00123          <variablelist>
00124             <variable name="MESSAGE_SEND_STATUS">
00125                <para>This is the message delivery status returned by this application.</para>
00126                <value name="INVALID_PROTOCOL">
00127                   No handler for the technology part of the URI was found.
00128                </value>
00129                <value name="INVALID_URI">
00130                   The protocol handler reported that the URI was not valid.
00131                </value>
00132                <value name="SUCCESS">
00133                   Successfully passed on to the protocol handler, but delivery has not necessarily been guaranteed.
00134                </value>
00135                <value name="FAILURE">
00136                   The protocol handler reported that it was unabled to deliver the message for some reason.
00137                </value>
00138             </variable>
00139          </variablelist>
00140       </description>
00141    </application>
00142  ***/
00143 
00144 struct msg_data {
00145    AST_DECLARE_STRING_FIELDS(
00146       AST_STRING_FIELD(name);
00147       AST_STRING_FIELD(value);
00148    );
00149    unsigned int send:1; /* Whether to send out on outbound messages */
00150 };
00151 
00152 AST_LIST_HEAD_NOLOCK(outhead, msg_data);
00153 
00154 /*!
00155  * \brief A message.
00156  *
00157  * \todo Consider whether stringfields would be an appropriate optimization here.
00158  */
00159 struct ast_msg {
00160    struct ast_str *to;
00161    struct ast_str *from;
00162    struct ast_str *body;
00163    struct ast_str *context;
00164    struct ast_str *exten;
00165    struct ao2_container *vars;
00166 };
00167 
00168 struct ast_msg_tech_holder {
00169    const struct ast_msg_tech *tech;
00170    /*!
00171     * \brief A rwlock for this object
00172     *
00173     * a read/write lock must be used to protect the wrapper instead
00174     * of the ao2 lock. A rdlock must be held to read tech_holder->tech.
00175     */
00176    ast_rwlock_t tech_lock;
00177 };
00178 
00179 static struct ao2_container *msg_techs;
00180 
00181 static struct ast_taskprocessor *msg_q_tp;
00182 
00183 static const char app_msg_send[] = "MessageSend";
00184 
00185 static void msg_ds_destroy(void *data);
00186 
00187 static const struct ast_datastore_info msg_datastore = {
00188    .type = "message",
00189    .destroy = msg_ds_destroy,
00190 };
00191 
00192 static int msg_func_read(struct ast_channel *chan, const char *function,
00193       char *data, char *buf, size_t len);
00194 static int msg_func_write(struct ast_channel *chan, const char *function,
00195       char *data, const char *value);
00196 
00197 static struct ast_custom_function msg_function = {
00198    .name = "MESSAGE",
00199    .read = msg_func_read,
00200    .write = msg_func_write,
00201 };
00202 
00203 static int msg_data_func_read(struct ast_channel *chan, const char *function,
00204       char *data, char *buf, size_t len);
00205 static int msg_data_func_write(struct ast_channel *chan, const char *function,
00206       char *data, const char *value);
00207 
00208 static struct ast_custom_function msg_data_function = {
00209    .name = "MESSAGE_DATA",
00210    .read = msg_data_func_read,
00211    .write = msg_data_func_write,
00212 };
00213 
00214 static struct ast_frame *chan_msg_read(struct ast_channel *chan);
00215 static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr);
00216 static int chan_msg_indicate(struct ast_channel *chan, int condition,
00217       const void *data, size_t datalen);
00218 static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit);
00219 static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
00220       unsigned int duration);
00221 
00222 /*!
00223  * \internal
00224  * \brief A bare minimum channel technology
00225  *
00226  * This will not be registered as we never want anything to try
00227  * to create Message channels other than internally in this file.
00228  */
00229 static const struct ast_channel_tech msg_chan_tech_hack = {
00230    .type             = "Message",
00231    .description      = "Internal Text Message Processing",
00232    .read             = chan_msg_read,
00233    .write            = chan_msg_write,
00234    .indicate         = chan_msg_indicate,
00235    .send_digit_begin = chan_msg_send_digit_begin,
00236    .send_digit_end   = chan_msg_send_digit_end,
00237 };
00238 
00239 /*!
00240  * \internal
00241  * \brief ast_channel_tech read callback
00242  *
00243  * This should never be called.  However, we say that about chan_iax2's
00244  * read callback, too, and it seems to randomly get called for some
00245  * reason.  If it does, a simple NULL frame will suffice.
00246  */
00247 static struct ast_frame *chan_msg_read(struct ast_channel *chan)
00248 {
00249    return &ast_null_frame;
00250 }
00251 
00252 /*!
00253  * \internal
00254  * \brief ast_channel_tech write callback
00255  *
00256  * Throw all frames away.  We don't care about any of them.
00257  */
00258 static int chan_msg_write(struct ast_channel *chan, struct ast_frame *fr)
00259 {
00260    return 0;
00261 }
00262 
00263 /*!
00264  * \internal
00265  * \brief ast_channel_tech indicate callback
00266  *
00267  * The indicate callback is here just so it can return success.
00268  * We don't want any callers of ast_indicate() to think something
00269  * has failed.  We also don't want ast_indicate() itself to try
00270  * to generate inband tones since we didn't tell it that we took
00271  * care of it ourselves.
00272  */
00273 static int chan_msg_indicate(struct ast_channel *chan, int condition,
00274       const void *data, size_t datalen)
00275 {
00276    return 0;
00277 }
00278 
00279 /*!
00280  * \internal
00281  * \brief ast_channel_tech send_digit_begin callback
00282  *
00283  * This is here so that just in case a digit comes at a message channel
00284  * that the Asterisk core doesn't waste any time trying to generate
00285  * inband DTMF in audio.  It's a waste of resources.
00286  */
00287 static int chan_msg_send_digit_begin(struct ast_channel *chan, char digit)
00288 {
00289    return 0;
00290 }
00291 
00292 /*!
00293  * \internal
00294  * \brief ast_channel_tech send_digit_end callback
00295  *
00296  * This is here so that just in case a digit comes at a message channel
00297  * that the Asterisk core doesn't waste any time trying to generate
00298  * inband DTMF in audio.  It's a waste of resources.
00299  */
00300 static int chan_msg_send_digit_end(struct ast_channel *chan, char digit,
00301       unsigned int duration)
00302 {
00303    return 0;
00304 }
00305 
00306 static void msg_ds_destroy(void *data)
00307 {
00308    struct ast_msg *msg = data;
00309 
00310    ao2_ref(msg, -1);
00311 }
00312 
00313 static int msg_data_hash_fn(const void *obj, const int flags)
00314 {
00315    const struct msg_data *data = obj;
00316    return ast_str_case_hash(data->name);
00317 }
00318 
00319 static int msg_data_cmp_fn(void *obj, void *arg, int flags)
00320 {
00321    const struct msg_data *one = obj, *two = arg;
00322    return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP : 0;
00323 }
00324 
00325 static void msg_data_destructor(void *obj)
00326 {
00327    struct msg_data *data = obj;
00328    ast_string_field_free_memory(data);
00329 }
00330 
00331 static void msg_destructor(void *obj)
00332 {
00333    struct ast_msg *msg = obj;
00334 
00335    ast_free(msg->to);
00336    msg->to = NULL;
00337 
00338    ast_free(msg->from);
00339    msg->from = NULL;
00340 
00341    ast_free(msg->body);
00342    msg->body = NULL;
00343 
00344    ast_free(msg->context);
00345    msg->context = NULL;
00346 
00347    ast_free(msg->exten);
00348    msg->exten = NULL;
00349 
00350    ao2_ref(msg->vars, -1);
00351 }
00352 
00353 struct ast_msg *ast_msg_alloc(void)
00354 {
00355    struct ast_msg *msg;
00356 
00357    if (!(msg = ao2_alloc(sizeof(*msg), msg_destructor))) {
00358       return NULL;
00359    }
00360 
00361    if (!(msg->to = ast_str_create(32))) {
00362       ao2_ref(msg, -1);
00363       return NULL;
00364    }
00365 
00366    if (!(msg->from = ast_str_create(32))) {
00367       ao2_ref(msg, -1);
00368       return NULL;
00369    }
00370 
00371    if (!(msg->body = ast_str_create(128))) {
00372       ao2_ref(msg, -1);
00373       return NULL;
00374    }
00375 
00376    if (!(msg->context = ast_str_create(16))) {
00377       ao2_ref(msg, -1);
00378       return NULL;
00379    }
00380 
00381    if (!(msg->exten = ast_str_create(16))) {
00382       ao2_ref(msg, -1);
00383       return NULL;
00384    }
00385 
00386    if (!(msg->vars = ao2_container_alloc(1, msg_data_hash_fn, msg_data_cmp_fn))) {
00387       ao2_ref(msg, -1);
00388       return NULL;
00389    }
00390 
00391    ast_str_set(&msg->context, 0, "default");
00392 
00393    return msg;
00394 }
00395 
00396 struct ast_msg *ast_msg_destroy(struct ast_msg *msg)
00397 {
00398    ao2_ref(msg, -1);
00399 
00400    return NULL;
00401 }
00402 
00403 int ast_msg_set_to(struct ast_msg *msg, const char *fmt, ...)
00404 {
00405    va_list ap;
00406    int res;
00407 
00408    va_start(ap, fmt);
00409    res = ast_str_set_va(&msg->to, 0, fmt, ap);
00410    va_end(ap);
00411 
00412    return res < 0 ? -1 : 0;
00413 }
00414 
00415 int ast_msg_set_from(struct ast_msg *msg, const char *fmt, ...)
00416 {
00417    va_list ap;
00418    int res;
00419 
00420    va_start(ap, fmt);
00421    res = ast_str_set_va(&msg->from, 0, fmt, ap);
00422    va_end(ap);
00423 
00424    return res < 0 ? -1 : 0;
00425 }
00426 
00427 int ast_msg_set_body(struct ast_msg *msg, const char *fmt, ...)
00428 {
00429    va_list ap;
00430    int res;
00431 
00432    va_start(ap, fmt);
00433    res = ast_str_set_va(&msg->body, 0, fmt, ap);
00434    va_end(ap);
00435 
00436    return res < 0 ? -1 : 0;
00437 }
00438 
00439 int ast_msg_set_context(struct ast_msg *msg, const char *fmt, ...)
00440 {
00441    va_list ap;
00442    int res;
00443 
00444    va_start(ap, fmt);
00445    res = ast_str_set_va(&msg->context, 0, fmt, ap);
00446    va_end(ap);
00447 
00448    return res < 0 ? -1 : 0;
00449 }
00450 
00451 int ast_msg_set_exten(struct ast_msg *msg, const char *fmt, ...)
00452 {
00453    va_list ap;
00454    int res;
00455 
00456    va_start(ap, fmt);
00457    res = ast_str_set_va(&msg->exten, 0, fmt, ap);
00458    va_end(ap);
00459 
00460    return res < 0 ? -1 : 0;
00461 }
00462 
00463 const char *ast_msg_get_body(const struct ast_msg *msg)
00464 {
00465    return ast_str_buffer(msg->body);
00466 }
00467 
00468 static struct msg_data *msg_data_alloc(void)
00469 {
00470    struct msg_data *data;
00471 
00472    if (!(data = ao2_alloc(sizeof(*data), msg_data_destructor))) {
00473       return NULL;
00474    }
00475 
00476    if (ast_string_field_init(data, 32)) {
00477       ao2_ref(data, -1);
00478       return NULL;
00479    }
00480 
00481    return data;
00482 }
00483 
00484 static struct msg_data *msg_data_find(struct ao2_container *vars, const char *name)
00485 {
00486    struct msg_data tmp = {
00487       .name = name,
00488    };
00489    return ao2_find(vars, &tmp, OBJ_POINTER);
00490 }
00491 
00492 static int msg_set_var_full(struct ast_msg *msg, const char *name, const char *value, unsigned int outbound)
00493 {
00494    struct msg_data *data;
00495 
00496    if (!(data = msg_data_find(msg->vars, name))) {
00497       if (ast_strlen_zero(value)) {
00498          return 0;
00499       }
00500       if (!(data = msg_data_alloc())) {
00501          return -1;
00502       };
00503 
00504       ast_string_field_set(data, name, name);
00505       ast_string_field_set(data, value, value);
00506       data->send = outbound;
00507       ao2_link(msg->vars, data);
00508    } else {
00509       if (ast_strlen_zero(value)) {
00510          ao2_unlink(msg->vars, data);
00511       } else {
00512          ast_string_field_set(data, value, value);
00513          data->send = outbound;
00514       }
00515    }
00516 
00517    ao2_ref(data, -1);
00518 
00519    return 0;
00520 }
00521 
00522 static int msg_set_var_outbound(struct ast_msg *msg, const char *name, const char *value)
00523 {
00524    return msg_set_var_full(msg, name, value, 1);
00525 }
00526 
00527 int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
00528 {
00529    return msg_set_var_full(msg, name, value, 0);
00530 }
00531 
00532 const char *ast_msg_get_var(struct ast_msg *msg, const char *name)
00533 {
00534    struct msg_data *data;
00535    const char *val = NULL;
00536 
00537    if (!(data = msg_data_find(msg->vars, name))) {
00538       return NULL;
00539    }
00540 
00541    /* Yep, this definitely looks like val would be a dangling pointer
00542     * after the ref count is decremented.  As long as the message structure
00543     * is used in a thread safe manner, this will not be the case though.
00544     * The ast_msg holds a reference to this object in the msg->vars container. */
00545    val = data->value;
00546    ao2_ref(data, -1);
00547 
00548    return val;
00549 }
00550 
00551 struct ast_msg_var_iterator {
00552    struct ao2_iterator i;
00553    struct msg_data *current_used;
00554 };
00555 
00556 struct ast_msg_var_iterator *ast_msg_var_iterator_init(const struct ast_msg *msg)
00557 {
00558    struct ast_msg_var_iterator *i;
00559    if (!(i = ast_calloc(1, sizeof(*i)))) {
00560       return NULL;
00561    }
00562 
00563    i->i = ao2_iterator_init(msg->vars, 0);
00564 
00565    return i;
00566 }
00567 
00568 int ast_msg_var_iterator_next(const struct ast_msg *msg, struct ast_msg_var_iterator *i, const char **name, const char **value)
00569 {
00570    struct msg_data *data;
00571 
00572    /* Skip any that aren't marked for sending out */
00573    while ((data = ao2_iterator_next(&i->i)) && !data->send) {
00574       ao2_ref(data, -1);
00575    }
00576 
00577    if (!data) {
00578       return 0;
00579    }
00580 
00581    if (data->send) {
00582       *name = data->name;
00583       *value = data->value;
00584    }
00585 
00586    /* Leave the refcount to be cleaned up by the caller with
00587     * ast_msg_var_unref_current after they finish with the pointers to the data */
00588    i->current_used = data;
00589 
00590    return 1;
00591 }
00592 
00593 void ast_msg_var_unref_current(struct ast_msg_var_iterator *i) {
00594    if (i->current_used) {
00595       ao2_ref(i->current_used, -1);
00596    }
00597    i->current_used = NULL;
00598 }
00599 
00600 void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *i)
00601 {
00602    ao2_iterator_destroy(&i->i);
00603    ast_free(i);
00604 }
00605 
00606 static struct ast_channel *create_msg_q_chan(void)
00607 {
00608    struct ast_channel *chan;
00609    struct ast_datastore *ds;
00610 
00611    chan = ast_channel_alloc(1, AST_STATE_UP,
00612          NULL, NULL, NULL,
00613          NULL, NULL, NULL, 0,
00614          "%s", "Message/ast_msg_queue");
00615 
00616    if (!chan) {
00617       return NULL;
00618    }
00619 
00620    ast_channel_unlink(chan);
00621 
00622    ast_channel_tech_set(chan, &msg_chan_tech_hack);
00623 
00624    if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
00625       ast_hangup(chan);
00626       return NULL;
00627    }
00628 
00629    ast_channel_lock(chan);
00630    ast_channel_datastore_add(chan, ds);
00631    ast_channel_unlock(chan);
00632 
00633    return chan;
00634 }
00635 
00636 /*!
00637  * \internal
00638  * \brief Run the dialplan for message processing
00639  *
00640  * \pre The message has already been set up on the msg datastore
00641  *      on this channel.
00642  */
00643 static void msg_route(struct ast_channel *chan, struct ast_msg *msg)
00644 {
00645    struct ast_pbx_args pbx_args;
00646 
00647    ast_explicit_goto(chan, ast_str_buffer(msg->context), AS_OR(msg->exten, "s"), 1);
00648 
00649    memset(&pbx_args, 0, sizeof(pbx_args));
00650    pbx_args.no_hangup_chan = 1,
00651    ast_pbx_run_args(chan, &pbx_args);
00652 }
00653 
00654 /*!
00655  * \internal
00656  * \brief Clean up ast_channel after each message
00657  *
00658  * Reset various bits of state after routing each message so the same ast_channel
00659  * can just be reused.
00660  */
00661 static void chan_cleanup(struct ast_channel *chan)
00662 {
00663    struct ast_datastore *msg_ds, *ds;
00664    struct varshead *headp;
00665    struct ast_var_t *vardata;
00666 
00667    ast_channel_lock(chan);
00668 
00669    /*
00670     * Remove the msg datastore.  Free its data but keep around the datastore
00671     * object and just reuse it.
00672     */
00673    if ((msg_ds = ast_channel_datastore_find(chan, &msg_datastore, NULL)) && msg_ds->data) {
00674       ast_channel_datastore_remove(chan, msg_ds);
00675       ao2_ref(msg_ds->data, -1);
00676       msg_ds->data = NULL;
00677    }
00678 
00679    /*
00680     * Destroy all other datastores.
00681     */
00682    while ((ds = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
00683       ast_datastore_free(ds);
00684    }
00685 
00686    /*
00687     * Destroy all channel variables.
00688     */
00689    headp = ast_channel_varshead(chan);
00690    while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
00691       ast_var_delete(vardata);
00692    }
00693 
00694    /*
00695     * Restore msg datastore.
00696     */
00697    if (msg_ds) {
00698       ast_channel_datastore_add(chan, msg_ds);
00699    }
00700 
00701    ast_channel_unlock(chan);
00702 }
00703 
00704 AST_THREADSTORAGE(msg_q_chan);
00705 
00706 /*!
00707  * \internal
00708  * \brief Message queue task processor callback
00709  *
00710  * \retval 0 success
00711  * \retval -1 failure
00712  *
00713  * \note Even though this returns a value, the taskprocessor code ignores the value.
00714  */
00715 static int msg_q_cb(void *data)
00716 {
00717    struct ast_msg *msg = data;
00718    struct ast_channel **chan_p, *chan;
00719    struct ast_datastore *ds;
00720 
00721    if (!(chan_p = ast_threadstorage_get(&msg_q_chan, sizeof(struct ast_channel *)))) {
00722       return -1;
00723    }
00724    if (!*chan_p) {
00725       if (!(*chan_p = create_msg_q_chan())) {
00726          return -1;
00727       }
00728    }
00729    chan = *chan_p;
00730 
00731    ast_channel_lock(chan);
00732    if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00733       ast_channel_unlock(chan);
00734       return -1;
00735    }
00736    ao2_ref(msg, +1);
00737    ds->data = msg;
00738    ast_channel_unlock(chan);
00739 
00740    msg_route(chan, msg);
00741    chan_cleanup(chan);
00742 
00743    ao2_ref(msg, -1);
00744 
00745    return 0;
00746 }
00747 
00748 int ast_msg_queue(struct ast_msg *msg)
00749 {
00750    int res;
00751 
00752    res = ast_taskprocessor_push(msg_q_tp, msg_q_cb, msg);
00753    if (res == -1) {
00754       ao2_ref(msg, -1);
00755    }
00756 
00757    return res;
00758 }
00759 
00760 /*!
00761  * \internal
00762  * \brief Find or create a message datastore on a channel
00763  *
00764  * \pre chan is locked
00765  *
00766  * \param chan the relevant channel
00767  *
00768  * \return the channel's message datastore, or NULL on error
00769  */
00770 static struct ast_datastore *msg_datastore_find_or_create(struct ast_channel *chan)
00771 {
00772    struct ast_datastore *ds;
00773 
00774    if ((ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00775       return ds;
00776    }
00777 
00778    if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
00779       return NULL;
00780    }
00781 
00782    if (!(ds->data = ast_msg_alloc())) {
00783       ast_datastore_free(ds);
00784       return NULL;
00785    }
00786 
00787    ast_channel_datastore_add(chan, ds);
00788 
00789    return ds;
00790 }
00791 
00792 static int msg_func_read(struct ast_channel *chan, const char *function,
00793       char *data, char *buf, size_t len)
00794 {
00795    struct ast_datastore *ds;
00796    struct ast_msg *msg;
00797 
00798    ast_channel_lock(chan);
00799 
00800    if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00801       ast_channel_unlock(chan);
00802       ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
00803       return -1;
00804    }
00805 
00806    msg = ds->data;
00807    ao2_ref(msg, +1);
00808    ast_channel_unlock(chan);
00809 
00810    ao2_lock(msg);
00811 
00812    if (!strcasecmp(data, "to")) {
00813       ast_copy_string(buf, ast_str_buffer(msg->to), len);
00814    } else if (!strcasecmp(data, "from")) {
00815       ast_copy_string(buf, ast_str_buffer(msg->from), len);
00816    } else if (!strcasecmp(data, "body")) {
00817       ast_copy_string(buf, ast_msg_get_body(msg), len);
00818    } else {
00819       ast_log(LOG_WARNING, "Invalid argument to MESSAGE(): '%s'\n", data);
00820    }
00821 
00822    ao2_unlock(msg);
00823    ao2_ref(msg, -1);
00824 
00825    return 0;
00826 }
00827 
00828 static int msg_func_write(struct ast_channel *chan, const char *function,
00829       char *data, const char *value)
00830 {
00831    struct ast_datastore *ds;
00832    struct ast_msg *msg;
00833 
00834    ast_channel_lock(chan);
00835 
00836    if (!(ds = msg_datastore_find_or_create(chan))) {
00837       ast_channel_unlock(chan);
00838       return -1;
00839    }
00840 
00841    msg = ds->data;
00842    ao2_ref(msg, +1);
00843    ast_channel_unlock(chan);
00844 
00845    ao2_lock(msg);
00846 
00847    if (!strcasecmp(data, "to")) {
00848       ast_msg_set_to(msg, "%s", value);
00849    } else if (!strcasecmp(data, "from")) {
00850       ast_msg_set_from(msg, "%s", value);
00851    } else if (!strcasecmp(data, "body")) {
00852       ast_msg_set_body(msg, "%s", value);
00853    } else {
00854       ast_log(LOG_WARNING, "'%s' is not a valid write argument.\n", data);
00855    }
00856 
00857    ao2_unlock(msg);
00858    ao2_ref(msg, -1);
00859 
00860    return 0;
00861 }
00862 
00863 static int msg_data_func_read(struct ast_channel *chan, const char *function,
00864       char *data, char *buf, size_t len)
00865 {
00866    struct ast_datastore *ds;
00867    struct ast_msg *msg;
00868    const char *val;
00869 
00870    ast_channel_lock(chan);
00871 
00872    if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00873       ast_channel_unlock(chan);
00874       ast_log(LOG_ERROR, "No MESSAGE data found on the channel to read.\n");
00875       return -1;
00876    }
00877 
00878    msg = ds->data;
00879    ao2_ref(msg, +1);
00880    ast_channel_unlock(chan);
00881 
00882    ao2_lock(msg);
00883 
00884    if ((val = ast_msg_get_var(msg, data))) {
00885       ast_copy_string(buf, val, len);
00886    }
00887 
00888    ao2_unlock(msg);
00889    ao2_ref(msg, -1);
00890 
00891    return 0;
00892 }
00893 
00894 static int msg_data_func_write(struct ast_channel *chan, const char *function,
00895       char *data, const char *value)
00896 {
00897    struct ast_datastore *ds;
00898    struct ast_msg *msg;
00899 
00900    ast_channel_lock(chan);
00901 
00902    if (!(ds = msg_datastore_find_or_create(chan))) {
00903       ast_channel_unlock(chan);
00904       return -1;
00905    }
00906 
00907    msg = ds->data;
00908    ao2_ref(msg, +1);
00909    ast_channel_unlock(chan);
00910 
00911    ao2_lock(msg);
00912 
00913    msg_set_var_outbound(msg, data, value);
00914 
00915    ao2_unlock(msg);
00916    ao2_ref(msg, -1);
00917 
00918    return 0;
00919 }
00920 static int msg_tech_hash(const void *obj, const int flags)
00921 {
00922    struct ast_msg_tech_holder *tech_holder = (struct ast_msg_tech_holder *) obj;
00923    int res = 0;
00924 
00925    ast_rwlock_rdlock(&tech_holder->tech_lock);
00926    if (tech_holder->tech) {
00927       res = ast_str_case_hash(tech_holder->tech->name);
00928    }
00929    ast_rwlock_unlock(&tech_holder->tech_lock);
00930 
00931    return res;
00932 }
00933 
00934 static int msg_tech_cmp(void *obj, void *arg, int flags)
00935 {
00936    struct ast_msg_tech_holder *tech_holder = obj;
00937    const struct ast_msg_tech_holder *tech_holder2 = arg;
00938    int res = 1;
00939 
00940    ast_rwlock_rdlock(&tech_holder->tech_lock);
00941    /*
00942     * tech_holder2 is a temporary fake tech_holder.
00943     */
00944    if (tech_holder->tech) {
00945       res = strcasecmp(tech_holder->tech->name, tech_holder2->tech->name) ? 0 : CMP_MATCH | CMP_STOP;
00946    }
00947    ast_rwlock_unlock(&tech_holder->tech_lock);
00948 
00949    return res;
00950 }
00951 
00952 /*!
00953  * \internal
00954  * \brief MessageSend() application
00955  */
00956 static int msg_send_exec(struct ast_channel *chan, const char *data)
00957 {
00958    struct ast_datastore *ds;
00959    struct ast_msg *msg;
00960    char *tech_name;
00961    struct ast_msg_tech_holder *tech_holder = NULL;
00962    char *parse;
00963    int res = -1;
00964    AST_DECLARE_APP_ARGS(args,
00965       AST_APP_ARG(to);
00966       AST_APP_ARG(from);
00967    );
00968 
00969    if (ast_strlen_zero(data)) {
00970       ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
00971       pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
00972       return 0;
00973    }
00974 
00975    parse = ast_strdupa(data);
00976    AST_STANDARD_APP_ARGS(args, parse);
00977 
00978    if (ast_strlen_zero(args.to)) {
00979       ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
00980       pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
00981       return 0;
00982    }
00983 
00984    ast_channel_lock(chan);
00985 
00986    if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
00987       ast_channel_unlock(chan);
00988       ast_log(LOG_WARNING, "No message data found on channel to send.\n");
00989       pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
00990       return 0;
00991    }
00992 
00993    msg = ds->data;
00994    ao2_ref(msg, +1);
00995    ast_channel_unlock(chan);
00996 
00997    tech_name = ast_strdupa(args.to);
00998    tech_name = strsep(&tech_name, ":");
00999 
01000    {
01001       struct ast_msg_tech tmp_msg_tech = {
01002          .name = tech_name,
01003       };
01004       struct ast_msg_tech_holder tmp_tech_holder = {
01005          .tech = &tmp_msg_tech,
01006       };
01007 
01008       tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER);
01009    }
01010 
01011    if (!tech_holder) {
01012       ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
01013       pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
01014       goto exit_cleanup;
01015    }
01016 
01017    /*
01018     * The message lock is held here to safely allow the technology
01019     * implementation to access the message fields without worrying
01020     * that they could change.
01021     */
01022    ao2_lock(msg);
01023    ast_rwlock_rdlock(&tech_holder->tech_lock);
01024    if (tech_holder->tech) {
01025       res = tech_holder->tech->msg_send(msg, S_OR(args.to, ""),
01026                      S_OR(args.from, ""));
01027    }
01028    ast_rwlock_unlock(&tech_holder->tech_lock);
01029    ao2_unlock(msg);
01030 
01031    pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");
01032 
01033 exit_cleanup:
01034    if (tech_holder) {
01035       ao2_ref(tech_holder, -1);
01036       tech_holder = NULL;
01037    }
01038 
01039    ao2_ref(msg, -1);
01040 
01041    return 0;
01042 }
01043 
01044 int ast_msg_tech_register(const struct ast_msg_tech *tech)
01045 {
01046    struct ast_msg_tech_holder tmp_tech_holder = {
01047       .tech = tech,
01048    };
01049    struct ast_msg_tech_holder *tech_holder;
01050 
01051    if ((tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER))) {
01052       ao2_ref(tech_holder, -1);
01053       ast_log(LOG_ERROR, "Message technology already registered for '%s'\n",
01054             tech->name);
01055       return -1;
01056    }
01057 
01058    if (!(tech_holder = ao2_alloc(sizeof(*tech_holder), NULL))) {
01059       return -1;
01060    }
01061 
01062    ast_rwlock_init(&tech_holder->tech_lock);
01063    tech_holder->tech = tech;
01064 
01065    ao2_link(msg_techs, tech_holder);
01066 
01067    ao2_ref(tech_holder, -1);
01068    tech_holder = NULL;
01069 
01070    ast_verb(3, "Message technology handler '%s' registered.\n", tech->name);
01071 
01072    return 0;
01073 }
01074 
01075 int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
01076 {
01077    struct ast_msg_tech_holder tmp_tech_holder = {
01078       .tech = tech,
01079    };
01080    struct ast_msg_tech_holder *tech_holder;
01081 
01082    tech_holder = ao2_find(msg_techs, &tmp_tech_holder, OBJ_POINTER | OBJ_UNLINK);
01083 
01084    if (!tech_holder) {
01085       ast_log(LOG_ERROR, "No '%s' message technology found.\n", tech->name);
01086       return -1;
01087    }
01088 
01089    ast_rwlock_wrlock(&tech_holder->tech_lock);
01090    tech_holder->tech = NULL;
01091    ast_rwlock_unlock(&tech_holder->tech_lock);
01092 
01093    ao2_ref(tech_holder, -1);
01094    tech_holder = NULL;
01095 
01096    ast_verb(3, "Message technology handler '%s' unregistered.\n", tech->name);
01097 
01098    return 0;
01099 }
01100 
01101 /*
01102  * \internal
01103  * \brief Initialize stuff during Asterisk startup.
01104  *
01105  * Cleanup isn't a big deal in this function.  If we return non-zero,
01106  * Asterisk is going to exit.
01107  *
01108  * \retval 0 success
01109  * \retval non-zero failure
01110  */
01111 int ast_msg_init(void)
01112 {
01113    int res;
01114 
01115    msg_q_tp = ast_taskprocessor_get("ast_msg_queue", TPS_REF_DEFAULT);
01116    if (!msg_q_tp) {
01117       return -1;
01118    }
01119 
01120    msg_techs = ao2_container_alloc(17, msg_tech_hash, msg_tech_cmp);
01121    if (!msg_techs) {
01122       return -1;
01123    }
01124 
01125    res = __ast_custom_function_register(&msg_function, NULL);
01126    res |= __ast_custom_function_register(&msg_data_function, NULL);
01127    res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL);
01128 
01129    return res;
01130 }

Generated on Sun May 20 06:33:55 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6