res_parking: Add parking_devicestate.c left out from previous commit
[asterisk/asterisk.git] / res / parking / parking_devicestate.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 Call Parking Device State Management
22  *
23  * \author Jonathan Rose <jrose@digium.com>
24  */
25
26 #include "asterisk.h"
27 #include "asterisk/logger.h"
28 #include "res_parking.h"
29 #include "asterisk/devicestate.h"
30
31 struct parking_lot_extension_inuse_search {
32         char *context;
33         int exten;
34 };
35
36 static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)
37 {
38         int *target = arg;
39         struct parked_user *user = obj;
40         if (user->parking_space == *target) {
41                 return CMP_MATCH;
42         }
43
44         return 0;
45 }
46
47 static int parking_lot_search_context_extension_inuse(void *obj, void *arg, int flags)
48 {
49         struct parking_lot *lot = obj;
50         struct parking_lot_extension_inuse_search *search = arg;
51         RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup);
52
53         if (strcmp(lot->cfg->parking_con, search->context)) {
54                 return 0;
55         }
56
57         if ((search->exten < lot->cfg->parking_start) || (search->exten > lot->cfg->parking_stop)) {
58                 return 0;
59         }
60
61         user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &search->exten);
62         if (!user) {
63                 return 0;
64         }
65
66         ao2_lock(user);
67         if (user->resolution != PARK_UNSET) {
68                 /* The parked user isn't in an answerable state. */
69                 ao2_unlock(user);
70                 return 0;
71         }
72         ao2_unlock(user);
73
74         return CMP_MATCH;
75 }
76
77 static enum ast_device_state metermaidstate(const char *data)
78 {
79         struct ao2_container *global_lots = get_parking_lot_container();
80         RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
81         char *context;
82         char *exten;
83         struct parking_lot_extension_inuse_search search = {};
84
85         context = ast_strdupa(data);
86
87         exten = strsep(&context, "@");
88
89         if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
90                 return AST_DEVICE_INVALID;
91         }
92
93         search.context = context;
94         if (sscanf(exten, "%d", &search.exten) != 1) {
95                 return AST_DEVICE_INVALID;
96         }
97
98         ast_debug(4, "Checking state of exten %d in context %s\n", search.exten, context);
99
100         lot = ao2_callback(global_lots, 0, parking_lot_search_context_extension_inuse, &data);
101         if (!lot) {
102                 return AST_DEVICE_NOT_INUSE;
103         }
104
105         return AST_DEVICE_INUSE;
106 }
107
108 void parking_notify_metermaids(int exten, const char *context, enum ast_device_state state)
109 {
110         ast_debug(4, "Notification of state change to metermaids %d@%s\n to state '%s'\n",
111                 exten, context, ast_devstate2str(state));
112
113         ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%d@%s", exten, context);
114 }
115
116 void unload_parking_devstate(void)
117 {
118         ast_devstate_prov_del("Park");
119 }
120
121 int load_parking_devstate(void)
122 {
123         return ast_devstate_prov_add("Park", metermaidstate);
124 }