Asterisk - The Open Source Telephony Project GIT-master-0bf3178
res_pjsip_notify.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Kevin Harwell <kharwell@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <support_level>core</support_level>
23 ***/
24
25#include "asterisk.h"
26
27#include <pjsip.h>
28#include <pjsip_ua.h>
29
30#include "asterisk/app.h"
31#include "asterisk/cli.h"
32#include "asterisk/config.h"
33#include "asterisk/manager.h"
34#include "asterisk/module.h"
35#include "asterisk/pbx.h"
36#include "asterisk/res_pjsip.h"
38#include "asterisk/sorcery.h"
39
40/*** DOCUMENTATION
41 <manager name="PJSIPNotify" language="en_US">
42 <synopsis>
43 Send a NOTIFY to either an endpoint, an arbitrary URI, or inside a SIP dialog.
44 </synopsis>
45 <syntax>
46 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
47 <parameter name="Endpoint" required="false">
48 <para>The endpoint to which to send the NOTIFY.</para>
49 </parameter>
50 <parameter name="URI" required="false">
51 <para>Abritrary URI to which to send the NOTIFY.</para>
52 </parameter>
53 <parameter name="channel" required="false">
54 <para>Channel name to send the NOTIFY. Must be a PJSIP channel.</para>
55 </parameter>
56 <parameter name="Option" required="false">
57 <para>The config section name from <literal>pjsip_notify.conf</literal> to use.</para>
58 <para>One of Option or Variable must be specified.</para>
59 </parameter>
60 <parameter name="Variable" required="false">
61 <para>Appends variables as headers/content to the NOTIFY. If the variable is
62 named <literal>Content</literal>, then the value will compose the body
63 of the message if another variable sets <literal>Content-Type</literal>.
64 <replaceable>name</replaceable>=<replaceable>value</replaceable></para>
65 <para>One of Option or Variable must be specified.</para>
66 </parameter>
67 </syntax>
68 <description>
69 <para>Sends a NOTIFY to an endpoint, an arbitrary URI, or inside a SIP dialog.</para>
70 <para>All parameters for this event must be specified in the body of this
71 request via multiple <literal>Variable: name=value</literal> sequences.</para>
72 <note><para>One (and only one) of <literal>Endpoint</literal>,
73 <literal>URI</literal>, or <literal>Channel</literal> must be specified.
74 If <literal>URI</literal> is used, the default outbound endpoint will be used
75 to send the message. If the default outbound endpoint isn't configured, this command
76 can not send to an arbitrary URI.</para></note>
77 </description>
78 </manager>
79 <configInfo name="res_pjsip_notify" language="en_US">
80 <synopsis>Module that supports sending NOTIFY requests to endpoints from external sources</synopsis>
81 <configFile name="pjsip_notify.conf">
82 <configObject name="general">
83 <synopsis>Unused, but reserved.</synopsis>
84 </configObject>
85 <configObject name="notify">
86 <synopsis>Configuration of a NOTIFY request.</synopsis>
87 <description>
88 <para>Each key-value pair in a <literal>notify</literal>
89 configuration section defines either a SIP header to send
90 in the request or a line of content in the request message
91 body. A key of <literal>Content</literal> is treated
92 as part of the message body and is appended in sequential
93 order; any other header is treated as part of the SIP
94 request.</para>
95 </description>
96 <configOption name="">
97 <synopsis>A key/value pair to add to a NOTIFY request.</synopsis>
98 <description>
99 <para>If the key is <literal>Content</literal>,
100 it will be treated as part of the message body. Otherwise,
101 it will be added as a header in the NOTIFY request.</para>
102 <para>The following headers are reserved and cannot be
103 specified:</para>
104 <enumlist>
105 <enum name="Call-ID" />
106 <enum name="Contact" />
107 <enum name="CSeq" />
108 <enum name="To" />
109 <enum name="From" />
110 <enum name="Record-Route" />
111 <enum name="Route" />
112 <enum name="Via" />
113 </enumlist>
114 </description>
115 </configOption>
116 </configObject>
117 </configFile>
118 </configInfo>
119 ***/
120
121#define CONTENT_TYPE_SIZE 64
122#define CONTENT_SIZE 512
123
124/*!
125 * \internal
126 * \brief The configuration file containing NOTIFY payload types to send.
127 */
128static const char notify_config[] = "pjsip_notify.conf";
129
131 const char *name;
132 const char *value;
133 char buf[0];
134};
135
137 /*! Contains header and/or content information */
139 /*! The name of the notify option */
140 char name[0];
141};
142
143static int notify_option_hash(const void *obj, int flags)
144{
145 const struct notify_option *option = obj;
146 return ast_str_case_hash(flags & OBJ_KEY ? obj : option->name);
147}
148
149static int notify_option_cmp(void *obj, void *arg, int flags)
150{
151 struct notify_option *option1 = obj;
152 struct notify_option *option2 = arg;
153 const char *key = flags & OBJ_KEY ? arg : option2->name;
154
155 return strcasecmp(option1->name, key) ? 0 : CMP_MATCH;
156}
157
158static void notify_option_destroy(void *obj)
159{
160 struct notify_option *option = obj;
161 ao2_cleanup(option->items);
162}
163
164static void *notify_option_alloc(const char *category)
165{
166 int category_size = strlen(category) + 1;
167
168 struct notify_option *option = ao2_alloc(
169 sizeof(*option) + category_size, notify_option_destroy);
170
171 if (!option) {
172 return NULL;
173 }
174
175 ast_copy_string(option->name, category, category_size);
176
177 if (!(option->items = ao2_container_alloc_list(
180 ao2_cleanup(option);
181 return NULL;
182 }
183
184 return option;
185}
186
187static void *notify_option_find(struct ao2_container *container, const char *category)
188{
189 return ao2_find(container, category, OBJ_KEY);
190}
191
192static int notify_option_handler(const struct aco_option *opt,
193 struct ast_variable *var, void *obj)
194{
195 struct notify_option *option = obj;
196
197 int name_size = strlen(var->name) + 1;
198 int value_size = strlen(var->value) + 1;
199
201 ao2_alloc(sizeof(*item) + name_size + value_size,
202 NULL), ao2_cleanup);
203
204 item->name = item->buf;
205 item->value = item->buf + name_size;
206
207 ast_copy_string(item->buf, var->name, name_size);
208 ast_copy_string(item->buf + name_size, var->value, value_size);
209
210 if (!ao2_link(option->items, item)) {
211 return -1;
212 }
213
214 return 0;
215}
216
219};
220
221static void notify_cfg_destroy(void *obj)
222{
223 struct notify_cfg *cfg = obj;
225}
226
227static void *notify_cfg_alloc(void)
228{
229 struct notify_cfg *cfg;
230
231 if (!(cfg = ao2_alloc(sizeof(*cfg), notify_cfg_destroy))) {
232 return NULL;
233 }
234
237 if (!cfg->notify_options) {
238 ao2_cleanup(cfg);
239 return NULL;
240 }
241
242 return cfg;
243}
244
245static struct aco_type notify_option = {
246 .type = ACO_ITEM,
247 .name = "notify",
248 .category_match = ACO_BLACKLIST_EXACT,
249 .category = "general",
250 .item_offset = offsetof(struct notify_cfg, notify_options),
251 .item_alloc = notify_option_alloc,
252 .item_find = notify_option_find
253};
254
256
257static struct aco_file module_conf = {
259 .types = ACO_TYPES(&notify_option),
260};
261
263
265 .files = ACO_FILES(&module_conf)
266);
267
268/*!
269 * \internal
270 * \brief Structure to hold task data for notifications.
271 */
273 /*! The endpoint being notified */
275 /*! The info of headers, types and content */
276 void *info;
277 /*! Function to help build notify request */
278 void (*build_notify)(pjsip_tx_data *, void *);
279};
280
281/*!
282 * \internal
283 * \brief Destroy the notify CLI data releasing any resources.
284 */
285static void notify_cli_data_destroy(void *obj)
286{
287 struct notify_data *data = obj;
288
289 ao2_cleanup(data->endpoint);
290 ao2_cleanup(data->info);
291}
292
293/*!
294 * \internal
295 * \brief Structure to hold task data for notifications (URI variant)
296 */
298 char *uri;
299 void *info;
300 void (*build_notify)(pjsip_tx_data *, void *);
301};
302
303/*!
304 * \internal
305 * \brief Structure to hold task data for notifications (channel variant)
306 */
309 void *info;
310 void (*build_notify)(pjsip_tx_data *, void *);
311};
312
313static void notify_cli_uri_data_destroy(void *obj)
314{
315 struct notify_uri_data *data = obj;
316
317 ast_free(data->uri);
318 ao2_cleanup(data->info);
319}
320
322{
323 struct notify_channel_data *data = obj;
324
325 ao2_cleanup(data->info);
326 ao2_cleanup(data->session);
327}
328
329/*!
330 * \internal
331 * \brief Destroy the notify CLI data releasing any resources (URI variant)
332 */
333static void build_cli_notify(pjsip_tx_data *tdata, void *info);
334
335/*!
336 * \internal
337 * \brief Construct a notify data object for CLI.
338 */
340 struct ast_sip_endpoint *endpoint, void *info)
341{
342 struct notify_data *data = ao2_alloc(sizeof(*data),
344 if (!data) {
345 return NULL;
346 }
347
348 data->endpoint = endpoint;
349 ao2_ref(data->endpoint, +1);
350
351 data->info = info;
352 ao2_ref(data->info, +1);
353
355
356 return data;
357}
358
359/*!
360 * \internal
361 * \brief Construct a notify URI data object for CLI.
362 */
364 const char *uri, void *info)
365{
366 struct notify_uri_data *data = ao2_alloc(sizeof(*data),
368
369 if (!data) {
370 return NULL;
371 }
372
373 data->uri = ast_strdup(uri);
374 if (!data->uri) {
375 ao2_ref(data, -1);
376 return NULL;
377 }
378
379 data->info = info;
380 ao2_ref(data->info, +1);
381
383
384 return data;
385}
386
387/*!
388 * \internal
389 * \brief Construct a notify URI data object for CLI.
390 */
392 struct ast_sip_session *session, void *info)
393{
394 struct notify_channel_data *data = ao2_alloc_options(sizeof(*data),
396
397 if (!data) {
398 return NULL;
399 }
400
401 data->session = session;
402 data->info = info;
403 ao2_ref(data->info, +1);
404
406
407 return data;
408}
409
410/*!
411 * \internal
412 * \brief Destroy the notify AMI data releasing any resources.
413 */
414static void notify_ami_data_destroy(void *obj)
415{
416 struct notify_data *data = obj;
417 struct ast_variable *info = data->info;
418
419 ao2_cleanup(data->endpoint);
421}
422
423/*!
424 * \internal
425 * \brief Destroy the notify AMI URI data releasing any resources.
426 */
427static void notify_ami_uri_data_destroy(void *obj)
428{
429 struct notify_uri_data *data = obj;
430 struct ast_variable *info = data->info;
431
432 ast_free(data->uri);
434}
435
436/*!
437 * \internal
438 * \brief Destroy the notify AMI channel data releasing any resources.
439 */
441{
442 struct notify_channel_data *data = obj;
443 struct ast_variable *info = data->info;
444
445 ao2_cleanup(data->session);
447}
448
449static void build_ami_notify(pjsip_tx_data *tdata, void *info);
450
451/*!
452 * \internal
453 * \brief Construct a notify data object for AMI.
454 */
456 struct ast_sip_endpoint *endpoint, void *info)
457{
458 struct notify_data *data = ao2_alloc(sizeof(*data),
460 if (!data) {
461 return NULL;
462 }
463
464 data->endpoint = endpoint;
465 ao2_ref(data->endpoint, +1);
466
467 data->info = info;
469
470 return data;
471}
472
473/*!
474 * \internal
475 * \brief Construct a notify URI data object for AMI.
476 */
478 const char *uri, void *info)
479{
480 struct notify_uri_data *data = ao2_alloc(sizeof(*data),
482 if (!data) {
483 return NULL;
484 }
485
486 data->uri = ast_strdup(uri);
487 if (!data->uri) {
488 ao2_ref(data, -1);
489 return NULL;
490 }
491
492 data->info = info;
494
495 return data;
496}
497
498/*!
499 * \internal
500 * \brief Construct a notify channel data object for AMI.
501 */
503 struct ast_sip_session *session, void *info)
504{
505 struct notify_channel_data *data;
506
509 if (!data) {
510 return NULL;
511 }
512
513 data->session = session;
514 data->info = info;
516
517 return data;
518}
519
520/*!
521 * \internal
522 * \brief Checks if the given header name is not allowed.
523 *
524 * \details Some headers are not allowed to be set by the user within the
525 * scope of a NOTIFY request. If the given var header name is
526 * found in the "not allowed" list then return true.
527 */
528static int not_allowed(const char *name)
529{
530 int i;
531 static const char *names[] = {
532 "Call-ID",
533 "Contact",
534 "CSeq",
535 "To",
536 "From",
537 "Record-Route",
538 "Route",
539 "Request-URI",
540 "Via",
541 };
542
543 for (i = 0; i < ARRAY_LEN(names); ++i) {
544 if (!strcasecmp(name, names[i])) {
545 return 1;
546 }
547 }
548 return 0;
549}
550
551/*!
552 * \internal
553 * \brief Check if the given header can be added to a message more than once.
554 */
555static int multiple_headers_allowed(const char *name)
556{
557 /* This can be extended to include additional headers */
558 return strcasecmp("Event", name);
559}
560
561/*!
562 * \internal
563 * \brief If a content type was specified add it and the content body to the
564 * NOTIFY request.
565 */
566static void build_notify_body(pjsip_tx_data *tdata, struct ast_str *content_type,
567 struct ast_str *content)
568{
569 if (content_type) {
570 char *p;
571 struct ast_sip_body body;
572
573 if (content) {
574 body.body_text = ast_str_buffer(content);
575 }
576
577 body.type = ast_str_buffer(content_type);
578 if ((p = strchr(body.type, '/'))) {
579 *p++ = '\0';
580 body.subtype = p;
581 }
582 ast_sip_add_body(tdata, &body);
583 }
584}
585
586/*!
587 * \internal
588 * \brief Build the NOTIFY request adding content or header info.
589 */
590static void build_notify(pjsip_tx_data *tdata, const char *name, const char *value,
591 struct ast_str **content_type, struct ast_str **content)
592{
593 if (not_allowed(name)) {
594 ast_log(LOG_WARNING, "Cannot specify %s header, "
595 "ignoring\n", name);
596 return;
597 }
598
599 if (!strcasecmp(name, "Content-type")) {
600 if (!(*content_type)) {
601 *content_type = ast_str_create(CONTENT_TYPE_SIZE);
602 }
603 ast_str_set(content_type, 0,"%s", value);
604 } else if (!strcasecmp(name, "Content")) {
605 if (!(*content)) {
606 *content = ast_str_create(CONTENT_SIZE);
607 }
608
609 if (ast_str_strlen(*content)) {
610 ast_str_append(content, 0, "\r\n");
611 }
612 ast_str_append(content, 0, "%s", value);
613 } else {
614 /* See if there is an existing one */
616 pj_str_t hdr_name;
617 pj_cstr(&hdr_name, name);
618
619 if (pjsip_msg_find_hdr_by_name(tdata->msg, &hdr_name, NULL)) {
620 ast_log(LOG_ERROR, "Only one '%s' header can be added to a NOTIFY, "
621 "ignoring \"%s: %s\"\n", name, name, value);
622 return;
623 }
624 }
625
627 }
628}
629
630/*!
631 * \internal
632 * \brief Build the NOTIFY request from CLI info adding header and content
633 * when specified.
634 */
635static void build_cli_notify(pjsip_tx_data *tdata, void *info)
636{
637 struct notify_option *option = info;
638 RAII_VAR(struct ast_str *, content_type, NULL, ast_free);
639 RAII_VAR(struct ast_str *, content, NULL, ast_free);
640
641 struct notify_option_item *item;
642 struct ao2_iterator i = ao2_iterator_init(option->items, 0);
643
644 while ((item = ao2_iterator_next(&i))) {
645 build_notify(tdata, item->name, item->value,
646 &content_type, &content);
648 }
650
651 build_notify_body(tdata, content_type, content);
652}
653
654/*!
655 * \internal
656 * \brief Build the NOTIFY request from AMI info adding header and content
657 * when specified.
658 */
659static void build_ami_notify(pjsip_tx_data *tdata, void *info)
660{
661 struct ast_variable *vars = info;
662 RAII_VAR(struct ast_str *, content_type, NULL, ast_free);
663 RAII_VAR(struct ast_str *, content, NULL, ast_free);
664 struct ast_variable *i;
665
666 for (i = vars; i; i = i->next) {
667 if (!strcasecmp(i->name, "Content-Length")) {
668 ast_log(LOG_NOTICE, "It is not necessary to specify Content-Length, ignoring.\n");
669 continue;
670 }
671 build_notify(tdata, i->name, i->value,
672 &content_type, &content);
673 }
674
675 build_notify_body(tdata, content_type, content);
676}
677
678/*!
679 * \internal
680 * \brief Build and send a NOTIFY request to a contact.
681 */
682static int notify_contact(void *obj, void *arg, int flags)
683{
684 struct ast_sip_contact *contact = obj;
685 struct notify_data *data = arg;
686 pjsip_tx_data *tdata;
687
688 if (ast_sip_create_request("NOTIFY", NULL, data->endpoint,
689 NULL, contact, &tdata)) {
690 ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for "
691 "contact %s\n", contact->uri);
692 return -1;
693 }
694
695 ast_sip_add_header(tdata, "Subscription-State", "terminated");
696 data->build_notify(tdata, data->info);
697
698 if (ast_sip_send_request(tdata, NULL, data->endpoint, NULL, NULL)) {
699 ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for "
700 "contact %s\n", contact->uri);
701 return -1;
702 }
703
704 return 0;
705}
706
707/*!
708 * \internal
709 * \brief Send a NOTIFY request to the endpoint.
710 *
711 * \details Iterates over an endpoint's AORs sending a NOTIFY request
712 * with the appropriate payload information to each contact.
713 */
714static int notify_endpoint(void *obj)
715{
716 RAII_VAR(struct notify_data *, data, obj, ao2_cleanup);
717 char *aor_name, *aors;
718
719 if (ast_strlen_zero(data->endpoint->aors)) {
720 ast_log(LOG_WARNING, "Unable to NOTIFY - "
721 "endpoint has no configured AORs\n");
722 return -1;
723 }
724
725 aors = ast_strdupa(data->endpoint->aors);
726
727 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
728 RAII_VAR(struct ast_sip_aor *, aor,
730 RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
731
732 if (!aor || !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
733 continue;
734 }
735
736 ao2_callback(contacts, OBJ_NODATA, notify_contact, data);
737 }
738
739 return 0;
740}
741
742/*!
743 * \internal
744 * \brief Send a notify request to the URI.
745 */
746static int notify_uri(void *obj)
747{
748 RAII_VAR(struct notify_uri_data *, data, obj, ao2_cleanup);
751 pjsip_tx_data *tdata;
752
753 if (!endpoint) {
754 ast_log(LOG_WARNING, "No default outbound endpoint set, can not send "
755 "NOTIFY requests to arbitrary URIs.\n");
756 return -1;
757 }
758
759 if (ast_strlen_zero(data->uri)) {
760 ast_log(LOG_WARNING, "Unable to NOTIFY - URI is blank.\n");
761 return -1;
762 }
763
764 if (ast_sip_create_request("NOTIFY", NULL, endpoint,
765 data->uri, NULL, &tdata)) {
766 ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for "
767 "uri %s\n", data->uri);
768 return -1;
769 }
770
771 ast_sip_add_header(tdata, "Subscription-State", "terminated");
772
773 data->build_notify(tdata, data->info);
774
775 if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) {
776 ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for "
777 "uri %s\n", data->uri);
778 return -1;
779 }
780
781 return 0;
782}
783
784/*!
785 * \internal
786 * \brief Send a notify request to a channel.
787 */
788static int notify_channel(void *obj)
789{
790 RAII_VAR(struct notify_channel_data *, data, obj, ao2_cleanup);
791 pjsip_tx_data *tdata;
792 struct pjsip_dialog *dlg;
793
794 if (!data->session->channel
795 || !data->session->inv_session
796 || data->session->inv_session->state < PJSIP_INV_STATE_EARLY
797 || data->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
798 return -1;
799 }
800
801 ast_debug(1, "Sending notify on channel %s\n", ast_channel_name(data->session->channel));
802
803 dlg = data->session->inv_session->dlg;
804
805 if (ast_sip_create_request("NOTIFY", dlg, NULL, NULL, NULL, &tdata)) {
806 return -1;
807 }
808
809 ast_sip_add_header(tdata, "Subscription-State", "terminated");
810 data->build_notify(tdata, data->info);
811
812 if (ast_sip_send_request(tdata, dlg, NULL, NULL, NULL)) {
813 return -1;
814 }
815
816 return 0;
817}
818
826
827typedef struct notify_data *(*task_data_create)(
828 struct ast_sip_endpoint *, void *info);
829
830typedef struct notify_uri_data *(*task_uri_data_create)(
831 const char *uri, void *info);
832
833typedef struct notify_channel_data *(*task_channel_data_create)(
834 struct ast_sip_session *session, void *info);
835
836/*!
837 * \internal
838 * \brief Send a NOTIFY request to the endpoint within a threaded task.
839 */
840static enum notify_result push_notify(const char *endpoint_name, void *info,
841 task_data_create data_create)
842{
844 struct notify_data *data;
845
847 ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
848 return INVALID_ENDPOINT;
849 }
850
851 if (!(data = data_create(endpoint, info))) {
852 return ALLOC_ERROR;
853 }
854
856 ao2_cleanup(data);
857 return TASK_PUSH_ERROR;
858 }
859
860 return SUCCESS;
861}
862
863/*!
864 * \internal
865 * \brief Send a NOTIFY request to the URI within an threaded task.
866 */
867static enum notify_result push_notify_uri(const char *uri, void *info,
868 task_uri_data_create data_create)
869{
870 struct notify_uri_data *data;
871
872 if (!(data = data_create(uri, info))) {
873 return ALLOC_ERROR;
874 }
875
876 if (ast_sip_push_task(NULL, notify_uri, data)) {
877 ao2_cleanup(data);
878 return TASK_PUSH_ERROR;
879 }
880
881 return SUCCESS;
882}
883
884/*!
885 * \internal
886 * \brief Send a NOTIFY request in a channel within an threaded task.
887 */
888static enum notify_result push_notify_channel(const char *channel_name, void *info,
889 task_channel_data_create data_create)
890{
891 struct notify_channel_data *data;
892 struct ast_channel *ch;
893 struct ast_sip_session *session;
894 struct ast_sip_channel_pvt *ch_pvt;
895
896 /* note: this increases the refcount of the channel */
897 ch = ast_channel_get_by_name(channel_name);
898 if (!ch) {
899 ast_debug(1, "No channel found with name %s", channel_name);
900 return INVALID_CHANNEL;
901 }
902
903 if (strcmp(ast_channel_tech(ch)->type, "PJSIP")) {
904 ast_log(LOG_WARNING, "Channel was a non-PJSIP channel: %s\n", channel_name);
906 return INVALID_CHANNEL;
907 }
908
910 ch_pvt = ast_channel_tech_pvt(ch);
911 session = ch_pvt->session;
912
913 if (!session || !session->inv_session
914 || session->inv_session->state < PJSIP_INV_STATE_EARLY
915 || session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
916 ast_debug(1, "No active session for channel %s\n", channel_name);
919 return INVALID_CHANNEL;
920 }
921
922 ao2_ref(session, +1);
924
925 /* don't keep a reference to the channel, we've got a reference to the session */
927
928 /*
929 * data_create will take ownership of the session,
930 * and take care of releasing the ref.
931 */
932 data = data_create(session, info);
933 if (!data) {
934 ao2_ref(session, -1);
935 return ALLOC_ERROR;
936 }
937
938 if (ast_sip_push_task(session->serializer, notify_channel, data)) {
939 ao2_ref(data, -1);
940 return TASK_PUSH_ERROR;
941 }
942
943 return SUCCESS;
944}
945
946/*!
947 * \internal
948 * \brief Do completion on the endpoint.
949 */
950static char *cli_complete_endpoint(const char *word)
951{
952 int wordlen = strlen(word);
953 struct ao2_container * endpoints;
954 struct ast_sip_endpoint *endpoint;
955 struct ao2_iterator i;
956
958 "endpoint", word, wordlen);
959 if (endpoints == NULL) {
960 return NULL;
961 }
962
964 while ((endpoint = ao2_iterator_next(&i))) {
967 ao2_cleanup(endpoint);
968 }
970
971 ao2_ref(endpoints, -1);
972
973 return NULL;
974}
975
976/*!
977 * \internal
978 * \brief Do completion on the notify CLI command.
979 */
980static char *cli_complete_notify(struct ast_cli_args *a)
981{
982 char *c = NULL;
983
984 if (a->pos == 3) {
985 int which = 0;
986 int wordlen = strlen(a->word);
987
988 RAII_VAR(struct notify_cfg *, cfg,
990 struct notify_option *option;
991
992 /* do completion for notify type */
993 struct ao2_iterator i = ao2_iterator_init(cfg->notify_options, 0);
994 while ((option = ao2_iterator_next(&i))) {
995 if (!strncasecmp(a->word, option->name, wordlen) && ++which > a->n) {
996 c = ast_strdup(option->name);
997 }
998
999 ao2_cleanup(option);
1000 if (c) {
1001 break;
1002 }
1003 }
1005 return c;
1006 }
1007
1008 if (a->pos == 4) {
1009 int wordlen = strlen(a->word);
1010
1011 if (ast_strlen_zero(a->word)) {
1012 if (a->n == 0) {
1013 c = ast_strdup("endpoint");
1014 } else if (a->n == 1) {
1015 c = ast_strdup("uri");
1016 } else if (a->n == 2) {
1017 c = ast_strdup("channel");
1018 }
1019 } else if (a->n == 0) {
1020 if (!strncasecmp(a->word, "endpoint", wordlen)) {
1021 c = ast_strdup("endpoint");
1022 } else if (!strncasecmp(a->word, "uri", wordlen)) {
1023 c = ast_strdup("uri");
1024 } else if (!strncasecmp(a->word, "channel", wordlen)) {
1025 c = ast_strdup("channel");
1026 }
1027 }
1028
1029 return c;
1030 }
1031
1032 if (a->pos > 4) {
1033 if (!strcasecmp(a->argv[4], "endpoint")) {
1034 return cli_complete_endpoint(a->word);
1035 } else if (!strcasecmp(a->argv[4], "channel")) {
1036 return ast_complete_channels(a->line, a->word, a->pos, a->n, 5);
1037 }
1038 }
1039 return NULL;
1040}
1041
1042/*!
1043 * \internal
1044 * \brief CLI command to send a SIP notify to an endpoint.
1045 *
1046 * \details Attempts to match the "type" given in the CLI command to a
1047 * configured one. If found, sends a NOTIFY to the endpoint
1048 * with the associated payload.
1049 */
1050static char *cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1051{
1052 RAII_VAR(struct notify_cfg *, cfg, NULL, ao2_cleanup);
1053 RAII_VAR(struct notify_option *, option, NULL, ao2_cleanup);
1054
1055 int i;
1056 int using_uri = 0;
1057 int using_channel = 0;
1058
1059 switch (cmd) {
1060 case CLI_INIT:
1061 e->command = "pjsip send notify";
1062 e->usage =
1063 "Usage: pjsip send notify <type> {endpoint|uri|channel} <peer> [<peer>...]\n"
1064 " Send a NOTIFY request to an endpoint\n"
1065 " Message types are defined in pjsip_notify.conf\n";
1066 return NULL;
1067 case CLI_GENERATE:
1068 return cli_complete_notify(a);
1069 }
1070
1071 if (a->argc < 6) {
1072 return CLI_SHOWUSAGE;
1073 }
1074
1075 if (!strcasecmp(a->argv[4], "uri")) {
1076 using_uri = 1;
1077 } else if (!strcasecmp(a->argv[4], "channel")) {
1078 using_channel = 1;
1079 } else if (strcasecmp(a->argv[4], "endpoint")) {
1080 return CLI_SHOWUSAGE;
1081 }
1082
1084
1085 if (!(option = notify_option_find(cfg->notify_options, a->argv[3])))
1086 {
1087 ast_cli(a->fd, "Unable to find notify type '%s'\n",
1088 a->argv[3]);
1089 return CLI_FAILURE;
1090 }
1091
1092 for (i = 5; i < a->argc; ++i) {
1093 enum notify_result result;
1094 ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n",
1095 a->argv[3], a->argv[i]);
1096
1097 if (using_uri) {
1099 } else if (using_channel) {
1101 } else {
1102 result = push_notify(a->argv[i], option, notify_cli_data_create);
1103 }
1104 switch(result) {
1105 case INVALID_ENDPOINT:
1106 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", a->argv[i]);
1107 break;
1108 case INVALID_CHANNEL:
1109 ast_cli(a->fd, "Unable to find channel %s\n", a->argv[i]);
1110 break;
1111 case ALLOC_ERROR:
1112 ast_cli(a->fd, "Unable to allocate NOTIFY task data\n");
1113 return CLI_FAILURE;
1114 case TASK_PUSH_ERROR:
1115 ast_cli(a->fd, "Unable to push NOTIFY task\n");
1116 return CLI_FAILURE;
1117 default:
1118 break;
1119 }
1120 }
1121
1122 return CLI_SUCCESS;
1123}
1124
1125static struct ast_cli_entry cli_options[] = {
1126 AST_CLI_DEFINE(cli_notify, "Send a NOTIFY request to a SIP endpoint")
1127};
1128
1133};
1134
1135static void manager_send_response(struct mansession *s, const struct message *m, enum notify_type type, enum notify_result res, struct ast_variable *vars, const char *endpoint_name)
1136{
1137 switch (res) {
1138 case INVALID_CHANNEL:
1139 if (type == NOTIFY_CHANNEL) {
1141 astman_send_error(s, m, "Channel not found");
1142 } else {
1143 /* Shouldn't be possible. */
1144 ast_assert(0);
1145 }
1146 break;
1147 case INVALID_ENDPOINT:
1148 if (type == NOTIFY_ENDPOINT) {
1150 astman_send_error_va(s, m, "Unable to retrieve endpoint %s", endpoint_name);
1151 } else {
1152 /* Shouldn't be possible. */
1153 ast_assert(0);
1154 }
1155 break;
1156 case ALLOC_ERROR:
1158 astman_send_error(s, m, "Unable to allocate NOTIFY task data");
1159 break;
1160 case TASK_PUSH_ERROR:
1161 /* Don't need to destroy vars since it is handled by cleanup in push_notify, push_notify_uri, etc. */
1162 astman_send_error(s, m, "Unable to push Notify task");
1163 break;
1164 case SUCCESS:
1165 astman_send_ack(s, m, "NOTIFY sent");
1166 break;
1167 }
1168}
1169
1170/*!
1171 * \internal
1172 * \brief Completes SIPNotify AMI command in Endpoint mode.
1173 */
1175 const struct message *m, const char *endpoint_name)
1176{
1177 RAII_VAR(struct notify_cfg *, cfg, NULL, ao2_cleanup);
1178 RAII_VAR(struct notify_option *, option, NULL, ao2_cleanup);
1179 struct ast_variable *vars = NULL;
1180 enum notify_result res;
1181 const char *option_name = astman_get_header(m, "Option");
1182
1183 if (!ast_strlen_zero(option_name) && (cfg = ao2_global_obj_ref(globals)) && !(option = notify_option_find(cfg->notify_options, option_name))) {
1184 astman_send_error_va(s, m, "Unable to find notify type '%s'\n", option_name);
1185 return;
1186 }
1187 if (!option) {
1189 }
1190
1191 if (!strncasecmp(endpoint_name, "sip/", 4)) {
1192 endpoint_name += 4;
1193 }
1194
1195 if (!strncasecmp(endpoint_name, "pjsip/", 6)) {
1196 endpoint_name += 6;
1197 }
1198
1199 if (option) {
1200 res = push_notify(endpoint_name, option, notify_cli_data_create); /* The CLI version happens to be suitable for options. */
1201 } else {
1202 res = push_notify(endpoint_name, vars, notify_ami_data_create);
1203 }
1204
1205 manager_send_response(s, m, NOTIFY_ENDPOINT, res, vars, endpoint_name);
1206}
1207
1208/*!
1209 * \internal
1210 * \brief Completes SIPNotify AMI command in URI mode.
1211 */
1212static void manager_notify_uri(struct mansession *s,
1213 const struct message *m, const char *uri)
1214{
1215 RAII_VAR(struct notify_cfg *, cfg, NULL, ao2_cleanup);
1216 RAII_VAR(struct notify_option *, option, NULL, ao2_cleanup);
1217 enum notify_result res;
1218 const char *option_name = astman_get_header(m, "Option");
1219 struct ast_variable *vars = NULL;
1220
1221 if (!ast_strlen_zero(option_name) && (cfg = ao2_global_obj_ref(globals)) && !(option = notify_option_find(cfg->notify_options, option_name))) {
1222 astman_send_error_va(s, m, "Unable to find notify type '%s'\n", option_name);
1223 return;
1224 }
1225 if (!option) {
1227 }
1228
1229 if (option) {
1230 res = push_notify_uri(uri, option, notify_cli_uri_data_create);
1231 } else {
1233 }
1234
1235 manager_send_response(s, m, NOTIFY_URI, res, vars, NULL);
1236}
1237
1238/*!
1239 * \internal
1240 * \brief Completes SIPNotify AMI command in channel mode.
1241 */
1243 const struct message *m, const char *channel)
1244{
1245 enum notify_result res;
1246 struct ast_variable *vars = NULL;
1247
1250
1251 manager_send_response(s, m, NOTIFY_CHANNEL, res, vars, NULL);
1252}
1253
1254/*!
1255 * \internal
1256 * \brief AMI entry point to send a SIP notify to an endpoint.
1257 */
1258static int manager_notify(struct mansession *s, const struct message *m)
1259{
1260 const char *endpoint_name = astman_get_header(m, "Endpoint");
1261 const char *uri = astman_get_header(m, "URI");
1262 const char *channel = astman_get_header(m, "Channel");
1263 const char *variables = astman_get_header(m, "Variable");
1264 const char *option = astman_get_header(m, "Option");
1265 int count = 0;
1266
1267 if (!ast_strlen_zero(endpoint_name)) {
1268 ++count;
1269 }
1270 if (!ast_strlen_zero(uri)) {
1271 ++count;
1272 }
1273 if (!ast_strlen_zero(channel)) {
1274 ++count;
1275 }
1276
1277 if ((!ast_strlen_zero(option) && !ast_strlen_zero(variables)) || (ast_strlen_zero(option) && ast_strlen_zero(variables))) {
1278 astman_send_error(s, m,
1279 "PJSIPNotify requires either an Option or Variable(s)."
1280 "You must use only one of them.");
1281 } else if (1 < count) {
1282 astman_send_error(s, m,
1283 "PJSIPNotify requires either an endpoint name, a SIP URI, or a channel. "
1284 "You must use only one of them.");
1285 } else if (!ast_strlen_zero(endpoint_name)) {
1286 manager_notify_endpoint(s, m, endpoint_name);
1287 } else if (!ast_strlen_zero(uri)) {
1288 manager_notify_uri(s, m, uri);
1289 } else if (!ast_strlen_zero(channel)) {
1290 manager_notify_channel(s, m, channel);
1291 } else {
1292 astman_send_error(s, m,
1293 "PJSIPNotify requires either an endpoint name, a SIP URI, or a channel.");
1294 }
1295
1296 return 0;
1297}
1298
1299/*! \brief Convert headers string such as "Event=hold&Event=answer&..." into ast variable list*/
1300/* Caller has to call ast_variables_destroy() to free the list*/
1301static struct ast_variable *headers_to_variables(const char *headers)
1302{
1303 struct ast_variable *varlist = NULL;
1304 struct ast_variable *var;
1305 char *cur;
1306 char *header;
1307
1308 cur = (char *)headers;
1309
1310 while( (header = strsep(&cur, "&")) ) {
1311 char *name;
1312 char *value;
1313
1314 name = value = header;
1315 strsep(&value, "=");
1316
1317 if (!value || ast_strlen_zero(name)) {
1318 continue;
1319 }
1320
1322 var->next = varlist;
1323 varlist = var;
1324 }
1325 return varlist;
1326}
1327
1328/*! \brief Application entry point to send a SIP notify to an endpoint. */
1329static int app_notify(struct ast_channel *chan, const char *data)
1330{
1331 RAII_VAR(struct notify_cfg *, cfg, NULL, ao2_cleanup);
1332 RAII_VAR(struct notify_option *, option, NULL, ao2_cleanup);
1333
1334 struct ast_variable *varlist = NULL;
1335 char *tmp;
1336 int res;
1338 AST_APP_ARG(to);
1339 AST_APP_ARG(headers);
1340 );
1341
1342
1343 if (ast_strlen_zero(data)) {
1344 ast_log(LOG_WARNING, "PJSIPNotify requires arguments (to, &header=...)\n");
1345 return -1;
1346 }
1347
1348 tmp = ast_strdupa(data);
1351
1352 if (!(option = notify_option_find(cfg->notify_options, args.headers))) {
1353 /* If the app is passed a list of headers, use the notify_ami_*_data_create
1354 functions as the option data is handled the same way as the ami command. */
1355 varlist = headers_to_variables(args.headers);
1356 if (ast_strlen_zero(args.to)) {
1358 } else {
1360 }
1361 } else {
1362 /* If the app is passed a configured notify option, use the notify_cli_*_data_create
1363 functions as the option data is handled the same way as the cli command. */
1364 if (ast_strlen_zero(args.to)) {
1366 } else {
1368 }
1369 }
1370
1371 switch (res) {
1372 case INVALID_CHANNEL:
1373 case INVALID_ENDPOINT:
1374 case ALLOC_ERROR:
1375 res = -1;
1376 ast_variables_destroy(varlist);
1377 break;
1378 case TASK_PUSH_ERROR:
1379 /* Don't need to destroy vars since it is handled by cleanup in push_notify_channel */
1380 res = -1;
1381 break;
1382 case SUCCESS:
1383 res = 0;
1384 break;
1385 }
1386
1387 return res;
1388}
1389
1390static int load_module(void)
1391{
1392 if (aco_info_init(&notify_cfg)) {
1394 }
1395
1397 "", notify_option_handler, 0);
1398
1399 if (aco_process_config(&notify_cfg, 0)) {
1402 }
1403
1407
1409}
1410
1411static int reload_module(void)
1412{
1415 }
1416
1417 return 0;
1418}
1419
1420static int unload_module(void)
1421{
1422 ast_manager_unregister("PJSIPNotify");
1423 ast_unregister_application("PJSIPNotify");
1427
1428 return 0;
1429}
1430
1431AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "CLI/AMI PJSIP NOTIFY Support",
1432 .support_level = AST_MODULE_SUPPORT_CORE,
1433 .load = load_module,
1435 .unload = unload_module,
1436 .load_pri = AST_MODPRI_APP_DEPEND,
1437 .requires = "res_pjsip",
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
#define OBJ_KEY
Definition: astobj2.h:1151
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition: astobj2.h:1044
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
@ AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW
Allow objects with duplicate keys in container.
Definition: astobj2.h:1181
static int tmp()
Definition: bt_open.c:389
static PGresult * result
Definition: cel_pgsql.c:84
static struct console_pvt globals
static const char type[]
Definition: chan_ooh323.c:109
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2968
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
#define ast_channel_unlock(chan)
Definition: channel.h:2969
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2768
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1872
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
@ ACO_PREFIX
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define ACO_FILES(...)
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
@ ACO_ITEM
@ ACO_BLACKLIST_EXACT
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
static const char name[]
Definition: format_mp3.c:68
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1969
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt,...)
Send error in manager transaction (with va_args support)
Definition: manager.c:1974
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2001
struct ast_variable * astman_get_variables_order(const struct message *m, enum variable_orders order)
Get a linked list of the Variable: headers with order specified.
Definition: manager.c:1721
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7608
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * strsep(char **str, const char *delims)
Configuration File Parser.
#define ast_variable_new(name, value, filename)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
static struct ao2_container * endpoints
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
@ ORDER_NATURAL
Definition: manager.h:288
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
def info(msg)
Core PBX routines and definitions.
static int reload(void)
struct ao2_container * container
Definition: res_fax.c:501
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition: location.c:147
int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending a SIP request.
Definition: res_pjsip.c:1979
struct ast_sip_endpoint * ast_sip_default_outbound_endpoint(void)
Retrieve the default outbound endpoint.
int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body)
Add a body to an outbound SIP message.
Definition: res_pjsip.c:2052
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
Definition: res_pjsip.c:1435
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition: res_pjsip.c:2008
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
struct ao2_container * ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
Retrieve all contacts currently available for an AOR.
Definition: location.c:247
AO2_GLOBAL_OBJ_STATIC(globals)
static void build_notify_body(pjsip_tx_data *tdata, struct ast_str *content_type, struct ast_str *content)
static void * notify_option_find(struct ao2_container *container, const char *category)
static void notify_ami_channel_data_destroy(void *obj)
static void * notify_cfg_alloc(void)
static int notify_option_cmp(void *obj, void *arg, int flags)
static struct notify_channel_data * notify_cli_channel_data_create(struct ast_sip_session *session, void *info)
static void * notify_option_alloc(const char *category)
static void notify_ami_data_destroy(void *obj)
static int not_allowed(const char *name)
static enum notify_result push_notify_channel(const char *channel_name, void *info, task_channel_data_create data_create)
struct notify_channel_data *(* task_channel_data_create)(struct ast_sip_session *session, void *info)
static struct aco_type * notify_options[]
static void manager_notify_endpoint(struct mansession *s, const struct message *m, const char *endpoint_name)
CONFIG_INFO_STANDARD(notify_cfg, globals, notify_cfg_alloc,.files=ACO_FILES(&module_conf))
static void build_cli_notify(pjsip_tx_data *tdata, void *info)
static struct notify_data * notify_cli_data_create(struct ast_sip_endpoint *endpoint, void *info)
static struct aco_file module_conf
static struct notify_uri_data * notify_ami_uri_data_create(const char *uri, void *info)
struct notify_uri_data *(* task_uri_data_create)(const char *uri, void *info)
static char * cli_complete_endpoint(const char *word)
static char * cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void manager_notify_channel(struct mansession *s, const struct message *m, const char *channel)
static struct notify_data * notify_ami_data_create(struct ast_sip_endpoint *endpoint, void *info)
static int notify_contact(void *obj, void *arg, int flags)
static void build_notify(pjsip_tx_data *tdata, const char *name, const char *value, struct ast_str **content_type, struct ast_str **content)
static enum notify_result push_notify_uri(const char *uri, void *info, task_uri_data_create data_create)
static int reload_module(void)
static void build_ami_notify(pjsip_tx_data *tdata, void *info)
static int notify_uri(void *obj)
static int app_notify(struct ast_channel *chan, const char *data)
Application entry point to send a SIP notify to an endpoint.
static struct ast_variable * headers_to_variables(const char *headers)
Convert headers string such as "Event=hold&Event=answer&..." into ast variable list.
static int notify_channel(void *obj)
static int multiple_headers_allowed(const char *name)
static int manager_notify(struct mansession *s, const struct message *m)
notify_result
@ TASK_PUSH_ERROR
@ ALLOC_ERROR
@ SUCCESS
@ INVALID_ENDPOINT
@ INVALID_CHANNEL
static char * cli_complete_notify(struct ast_cli_args *a)
static struct ast_cli_entry cli_options[]
static int notify_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int notify_endpoint(void *obj)
static void notify_cli_uri_data_destroy(void *obj)
static void notify_cfg_destroy(void *obj)
static void notify_cli_channel_data_destroy(void *obj)
static struct notify_channel_data * notify_ami_channel_data_create(struct ast_sip_session *session, void *info)
static int load_module(void)
static void notify_ami_uri_data_destroy(void *obj)
static int unload_module(void)
static struct notify_uri_data * notify_cli_uri_data_create(const char *uri, void *info)
static void manager_send_response(struct mansession *s, const struct message *m, enum notify_type type, enum notify_result res, struct ast_variable *vars, const char *endpoint_name)
static int notify_option_hash(const void *obj, int flags)
static enum notify_result push_notify(const char *endpoint_name, void *info, task_data_create data_create)
#define CONTENT_TYPE_SIZE
static void notify_cli_data_destroy(void *obj)
static void notify_option_destroy(void *obj)
struct notify_data *(* task_data_create)(struct ast_sip_endpoint *, void *info)
static const char notify_config[]
notify_type
@ NOTIFY_CHANNEL
@ NOTIFY_ENDPOINT
@ NOTIFY_URI
static void manager_notify_uri(struct mansession *s, const struct message *m, const char *uri)
#define CONTENT_SIZE
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
struct ao2_container * ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
Retrieve multiple objects whose id begins with the specified prefix.
Definition: sorcery.c:1989
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
The representation of a single configuration file to be processed.
const char * filename
Type information about a category-level configurable object.
const char * name
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
A SIP address of record.
Definition: res_pjsip.h:475
SIP body description.
Definition: res_pjsip.h:2324
const char * type
Definition: res_pjsip.h:2326
const char * body_text
Definition: res_pjsip.h:2330
const char * subtype
Definition: res_pjsip.h:2328
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
Contact associated with an address of record.
Definition: res_pjsip.h:389
const ast_string_field uri
Definition: res_pjsip.h:411
An entity with which Asterisk communicates.
Definition: res_pjsip.h:958
A structure describing a SIP session.
struct ast_sip_endpoint * endpoint
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:326
struct ao2_container * notify_options
struct ast_sip_session * session
void(* build_notify)(pjsip_tx_data *, void *)
struct ast_sip_endpoint * endpoint
void(* build_notify)(pjsip_tx_data *, void *)
struct ao2_container * items
void(* build_notify)(pjsip_tx_data *, void *)
int value
Definition: syslog.c:37
static struct aco_type item
Definition: test_config.c:1463
const char * args
static struct test_val a
static struct test_val c
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666