parking_controller.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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. /*! \file
  19. *
  20. * \brief Parking Entry, Exit, and other assorted controls.
  21. *
  22. * \author Jonathan Rose <jrose@digium.com>
  23. */
  24. #include "asterisk.h"
  25. #include "asterisk/logger.h"
  26. #include "res_parking.h"
  27. #include "asterisk/astobj2.h"
  28. #include "asterisk/utils.h"
  29. #include "asterisk/manager.h"
  30. #include "asterisk/test.h"
  31. #include "asterisk/features.h"
  32. #include "asterisk/bridge_basic.h"
  33. struct ast_bridge *parking_lot_get_bridge(struct parking_lot *lot)
  34. {
  35. struct ast_bridge *lot_bridge;
  36. if (lot->parking_bridge) {
  37. ao2_ref(lot->parking_bridge, +1);
  38. return lot->parking_bridge;
  39. }
  40. lot_bridge = bridge_parking_new(lot);
  41. if (!lot_bridge) {
  42. return NULL;
  43. }
  44. /* The parking lot needs a reference to the bridge as well. */
  45. lot->parking_bridge = lot_bridge;
  46. ao2_ref(lot->parking_bridge, +1);
  47. return lot_bridge;
  48. }
  49. int parking_channel_set_roles(struct ast_channel *chan, struct parking_lot *lot, int force_ringing)
  50. {
  51. if (ast_channel_add_bridge_role(chan, "holding_participant")) {
  52. return -1;
  53. }
  54. if (force_ringing) {
  55. if (ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "ringing")) {
  56. return -1;
  57. }
  58. } else {
  59. if (ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold")) {
  60. return -1;
  61. }
  62. if (!ast_strlen_zero(lot->cfg->mohclass)) {
  63. if (ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", lot->cfg->mohclass)) {
  64. return -1;
  65. }
  66. }
  67. }
  68. return 0;
  69. }
  70. struct parking_limits_pvt {
  71. struct parked_user *user;
  72. };
  73. int unpark_parked_user(struct parked_user *pu)
  74. {
  75. if (pu->lot) {
  76. ao2_unlink(pu->lot->parked_users, pu);
  77. parking_lot_remove_if_unused(pu->lot);
  78. return 0;
  79. }
  80. return -1;
  81. }
  82. int parking_lot_get_space(struct parking_lot *lot, int target_override)
  83. {
  84. int original_target;
  85. int current_target;
  86. struct ao2_iterator i;
  87. struct parked_user *user;
  88. int wrap;
  89. if (lot->cfg->parkfindnext) {
  90. /* Use next_space if the lot already has next_space set; otherwise use lot start. */
  91. original_target = lot->next_space ? lot->next_space : lot->cfg->parking_start;
  92. } else {
  93. original_target = lot->cfg->parking_start;
  94. }
  95. if (target_override >= lot->cfg->parking_start && target_override <= lot->cfg->parking_stop) {
  96. original_target = target_override;
  97. } else if (target_override > -1) {
  98. ast_log(LOG_WARNING, "Preferred parking spot %d is out of bounds (%d-%d)\n", target_override, lot->cfg->parking_start, lot->cfg->parking_stop);
  99. }
  100. current_target = original_target;
  101. wrap = lot->cfg->parking_start;
  102. i = ao2_iterator_init(lot->parked_users, 0);
  103. while ((user = ao2_iterator_next(&i))) {
  104. /* Increment the wrap on each pass until we find an empty space */
  105. if (wrap == user->parking_space) {
  106. wrap += 1;
  107. }
  108. if (user->parking_space < current_target) {
  109. /* It's lower than the anticipated target, so we haven't reached the target yet. */
  110. ao2_ref(user, -1);
  111. continue;
  112. }
  113. if (user->parking_space > current_target) {
  114. /* The current target is usable because all items below have been read and the next target is higher than the one we want. */
  115. ao2_ref(user, -1);
  116. break;
  117. }
  118. /* We found one already parked here. */
  119. current_target += 1;
  120. ao2_ref(user, -1);
  121. }
  122. ao2_iterator_destroy(&i);
  123. if (current_target <= lot->cfg->parking_stop) {
  124. return current_target;
  125. }
  126. if (wrap <= lot->cfg->parking_stop) {
  127. return wrap;
  128. }
  129. return -1;
  130. }
  131. static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)
  132. {
  133. int *target = arg;
  134. struct parked_user *user = obj;
  135. if (user->parking_space == *target) {
  136. return CMP_MATCH;
  137. }
  138. return 0;
  139. }
  140. struct parked_user *parking_lot_inspect_parked_user(struct parking_lot *lot, int target)
  141. {
  142. struct parked_user *user;
  143. if (target < 0) {
  144. user = ao2_callback(lot->parked_users, 0, NULL, NULL);
  145. } else {
  146. user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target);
  147. }
  148. if (!user) {
  149. return NULL;
  150. }
  151. return user;
  152. }
  153. struct parked_user *parking_lot_retrieve_parked_user(struct parking_lot *lot, int target)
  154. {
  155. RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup);
  156. if (target < 0) {
  157. user = ao2_callback(lot->parked_users, 0, NULL, NULL);
  158. } else {
  159. user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target);
  160. }
  161. if (!user) {
  162. return NULL;
  163. }
  164. ao2_lock(user);
  165. if (user->resolution != PARK_UNSET) {
  166. /* Abandon. Something else has resolved the parked user before we got to it. */
  167. ao2_unlock(user);
  168. return NULL;
  169. }
  170. ao2_unlink(lot->parked_users, user);
  171. user->resolution = PARK_ANSWERED;
  172. ao2_unlock(user);
  173. parking_lot_remove_if_unused(user->lot);
  174. /* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */
  175. ao2_ref(user, +1);
  176. return user;
  177. }
  178. void parked_call_retrieve_enable_features(struct ast_channel *chan, struct parking_lot *lot, int recipient_mode)
  179. {
  180. /* Enabling features here should be additive to features that are already on the channel. */
  181. struct ast_flags feature_flags = { 0 };
  182. struct ast_flags *existing_features;
  183. ast_channel_lock(chan);
  184. existing_features = ast_bridge_features_ds_get(chan);
  185. if (existing_features) {
  186. feature_flags = *existing_features;
  187. }
  188. if (lot->cfg->parkedcalltransfers & recipient_mode) {
  189. ast_set_flag(&feature_flags, AST_FEATURE_REDIRECT);
  190. }
  191. if (lot->cfg->parkedcallreparking & recipient_mode) {
  192. ast_set_flag(&feature_flags, AST_FEATURE_PARKCALL);
  193. }
  194. if (lot->cfg->parkedcallhangup & recipient_mode) {
  195. ast_set_flag(&feature_flags, AST_FEATURE_DISCONNECT);
  196. }
  197. if (lot->cfg->parkedcallrecording & recipient_mode) {
  198. ast_set_flag(&feature_flags, AST_FEATURE_AUTOMIXMON);
  199. }
  200. ast_bridge_features_ds_set(chan, &feature_flags);
  201. ast_channel_unlock(chan);
  202. return;
  203. }
  204. void flatten_dial_string(char *dialstring)
  205. {
  206. int i;
  207. for (i = 0; dialstring[i]; i++) {
  208. if (dialstring[i] == '/') {
  209. /* The underscore is the flattest character of all. */
  210. dialstring[i] = '_';
  211. }
  212. }
  213. }
  214. int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
  215. {
  216. struct ast_channel *chan = pu->chan;
  217. char *peername_flat = ast_strdupa(pu->parker_dial_string);
  218. /* Flatten the peername so that it can be used for performing the timeout PBX operations */
  219. flatten_dial_string(peername_flat);
  220. if (lot->cfg->comebacktoorigin) {
  221. if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername_flat, 1, NULL)) {
  222. ast_async_goto(chan, PARK_DIAL_CONTEXT, peername_flat, 1);
  223. return 0;
  224. } else {
  225. ast_log(LOG_ERROR, "Can not start %s at %s,%s,1 because extension does not exist. Terminating call.\n",
  226. ast_channel_name(chan), PARK_DIAL_CONTEXT, peername_flat);
  227. return -1;
  228. }
  229. }
  230. if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername_flat, 1, NULL)) {
  231. ast_async_goto(chan, lot->cfg->comebackcontext, peername_flat, 1);
  232. return 0;
  233. }
  234. if (ast_exists_extension(chan, lot->cfg->comebackcontext, "s", 1, NULL)) {
  235. ast_verb(2, "Could not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan),
  236. lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
  237. ast_async_goto(chan, lot->cfg->comebackcontext, "s", 1);
  238. return 0;
  239. }
  240. ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's@default'\n",
  241. ast_channel_name(chan),
  242. lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
  243. ast_async_goto(chan, "default", "s", 1);
  244. return 0;
  245. }