CI: Various updates to buildAsterisk.sh
[asterisk/asterisk.git] / main / parking.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Jonathan Rose <jrose@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 /*! \file
20  *
21  * \brief Parking Core
22  *
23  * \author Jonathan Rose <jrose@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 #include "asterisk/_private.h"
29 #include "asterisk/astobj2.h"
30 #include "asterisk/pbx.h"
31 #include "asterisk/bridge.h"
32 #include "asterisk/parking.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/_private.h"
35 #include "asterisk/module.h"
36
37 /*! \brief Message type for parked calls */
38 STASIS_MESSAGE_TYPE_DEFN(ast_parked_call_type);
39
40 /*! \brief Topic for parking lots */
41 static struct stasis_topic *parking_topic;
42
43 /*! \brief The container for the parking provider */
44 static AO2_GLOBAL_OBJ_STATIC(parking_provider);
45
46 static void parking_stasis_cleanup(void)
47 {
48         STASIS_MESSAGE_TYPE_CLEANUP(ast_parked_call_type);
49         ao2_cleanup(parking_topic);
50         parking_topic = NULL;
51 }
52
53 int ast_parking_stasis_init(void)
54 {
55         if (STASIS_MESSAGE_TYPE_INIT(ast_parked_call_type)) {
56                 return -1;
57         }
58
59         parking_topic = stasis_topic_create("ast_parking");
60         if (!parking_topic) {
61                 return -1;
62         }
63         ast_register_cleanup(parking_stasis_cleanup);
64         return 0;
65 }
66
67 struct stasis_topic *ast_parking_topic(void)
68 {
69         return parking_topic;
70 }
71
72 /*! \brief Destructor for parked_call_payload objects */
73 static void parked_call_payload_destructor(void *obj)
74 {
75         struct ast_parked_call_payload *park_obj = obj;
76
77         ao2_cleanup(park_obj->parkee);
78         ao2_cleanup(park_obj->retriever);
79         ast_string_field_free_memory(park_obj);
80 }
81
82 struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type,
83                 struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string,
84                 struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
85                 unsigned int parkingspace, unsigned long int timeout,
86                 unsigned long int duration)
87 {
88         RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
89
90         payload = ao2_alloc(sizeof(*payload), parked_call_payload_destructor);
91         if (!payload) {
92                 return NULL;
93         }
94
95         if (ast_string_field_init(payload, 32)) {
96                 return NULL;
97         }
98
99         payload->event_type = event_type;
100
101         ao2_ref(parkee_snapshot, +1);
102         payload->parkee = parkee_snapshot;
103
104         if (retriever_snapshot) {
105                 ao2_ref(retriever_snapshot, +1);
106                 payload->retriever = retriever_snapshot;
107         }
108
109         if (parkinglot) {
110                 ast_string_field_set(payload, parkinglot, parkinglot);
111         }
112
113         if (parker_dial_string) {
114                 ast_string_field_set(payload, parker_dial_string, parker_dial_string);
115         }
116
117         payload->parkingspace = parkingspace;
118         payload->timeout = timeout;
119         payload->duration = duration;
120
121         /* Bump the ref count by one since RAII_VAR is going to eat one when we leave. */
122         ao2_ref(payload, +1);
123         return payload;
124 }
125
126 int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
127 {
128         RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
129                 ao2_global_obj_ref(parking_provider), ao2_cleanup);
130
131         if (!table || !table->parking_park_bridge_channel) {
132                 return -1;
133         }
134
135         if (table->module) {
136                 SCOPED_MODULE_USE(table->module);
137                 return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
138         }
139
140         return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
141 }
142
143 int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker,
144         const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
145         struct transfer_channel_data *parked_channel_data)
146 {
147         RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
148                 ao2_global_obj_ref(parking_provider), ao2_cleanup);
149
150         if (!table || !table->parking_blind_transfer_park) {
151                 return -1;
152         }
153
154         if (table->module) {
155                 SCOPED_MODULE_USE(table->module);
156                 return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
157         }
158
159         return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
160 }
161
162 int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
163 {
164         RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
165                 ao2_global_obj_ref(parking_provider), ao2_cleanup);
166
167         if (!table || !table->parking_park_call) {
168                 return -1;
169         }
170
171         if (table->module) {
172                 SCOPED_MODULE_USE(table->module);
173                 return table->parking_park_call(parker, exten, length);
174         }
175
176         return table->parking_park_call(parker, exten, length);
177 }
178
179 int ast_parking_is_exten_park(const char *context, const char *exten)
180 {
181         RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
182                 ao2_global_obj_ref(parking_provider), ao2_cleanup);
183
184         if (!table || !table->parking_is_exten_park) {
185                 return -1;
186         }
187
188         if (table->module) {
189                 SCOPED_MODULE_USE(table->module);
190                 return table->parking_is_exten_park(context, exten);
191         }
192
193         return table->parking_is_exten_park(context, exten);
194 }
195
196 int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table)
197 {
198         RAII_VAR(struct ast_parking_bridge_feature_fn_table *, wrapper,
199                 ao2_global_obj_ref(parking_provider), ao2_cleanup);
200
201         if (fn_table->module_version != PARKING_MODULE_VERSION) {
202                 ast_log(AST_LOG_WARNING, "Parking module provided incorrect parking module "
203                         "version: %u (expected: %d)\n", fn_table->module_version, PARKING_MODULE_VERSION);
204                 return -1;
205         }
206
207         if (wrapper) {
208                 ast_log(AST_LOG_WARNING, "Parking provider already registered by %s!\n",
209                         wrapper->module_name);
210                 return -1;
211         }
212
213         wrapper = ao2_alloc(sizeof(*wrapper), NULL);
214         if (!wrapper) {
215                 return -1;
216         }
217         *wrapper = *fn_table;
218
219         ao2_global_obj_replace_unref(parking_provider, wrapper);
220         return 0;
221 }
222
223 int ast_parking_unregister_bridge_features(const char *module_name)
224 {
225         RAII_VAR(struct ast_parking_bridge_feature_fn_table *, wrapper,
226                 ao2_global_obj_ref(parking_provider), ao2_cleanup);
227
228         if (!wrapper) {
229                 return -1;
230         }
231
232         if (strcmp(wrapper->module_name, module_name)) {
233                 ast_log(AST_LOG_WARNING, "%s has not registered the parking provider\n", module_name);
234                 return -1;
235         }
236
237         ao2_global_obj_release(parking_provider);
238         return 0;
239 }
240
241 int ast_parking_provider_registered(void)
242 {
243         RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
244                 ao2_global_obj_ref(parking_provider), ao2_cleanup);
245
246         return !!table;
247 }