Index: main/features.c =================================================================== --- main/features.c (revision 226458) +++ main/features.c (working copy) @@ -332,6 +332,7 @@ /*! \brief Structure for parking lots which are put in a container. */ struct ast_parkinglot { char name[AST_MAX_CONTEXT]; + char parkext[AST_MAX_CONTEXT]; /*!< Parkingextension */ char parking_con[AST_MAX_EXTENSION]; /*!< Context for which parking is made accessible */ char parking_con_dial[AST_MAX_EXTENSION]; /*!< Context for dialback for parking (KLUDGE) */ int parking_start; /*!< First available extension for parking */ @@ -568,6 +569,7 @@ * * Create thread and attributes, call bridge_call_thread */ + static void bridge_call_thread_launch(void *data) { pthread_t thread; @@ -679,29 +681,25 @@ struct parkeduser *pu; }; -static struct parkeduser *park_space_reserve(struct ast_channel *chan, - struct ast_channel *peer, struct ast_park_call_args *args) +static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args, struct ast_parkinglot *arg_parkinglot) { struct parkeduser *pu; int i, parking_space = -1, parking_range; - const char *parkinglotname = NULL; const char *parkingexten; - struct ast_parkinglot *parkinglot = NULL; - - if (peer) - parkinglotname = findparkinglotname(peer); + struct ast_parkinglot *parkinglot = arg_parkinglot; - if (parkinglotname) { - if (option_debug) - ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname); - parkinglot = find_parkinglot(parkinglotname); - } + /* if we don't have a specified parkinglot by arguments: */ if (!parkinglot) - parkinglot = default_parkinglot; + parkinglot = find_parkinglot(findparkinglotname(chan)); /* find parkinglot for chan */ + if (!parkinglot){ + parkinglot = default_parkinglot; /* no parkinglot found? use default one */ + } + parkinglot_addref(parkinglot); - if (option_debug) + if (option_debug){ ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name); + } /* Allocate memory for parking data */ if (!(pu = ast_calloc(1, sizeof(*pu)))) { @@ -777,8 +775,9 @@ return NULL; } /* Set pointer for next parking */ - if (parkinglot->parkfindnext) + if (parkinglot->parkfindnext){ parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1; + } snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); } @@ -794,22 +793,27 @@ /* Park a call */ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) { + /* chan = transferee */ + /* peer = transferer */ + struct ast_context *con; int parkingnum_copy; struct parkeduser *pu = args->pu; const char *event_from; - if (pu == NULL) - pu = park_space_reserve(chan, peer, args); - if (pu == NULL) - return 1; /* Continue execution if possible */ + if (pu == NULL){ + pu = park_space_reserve(chan, peer, args, NULL); + } + if (pu == NULL){ + return 1; /* Error */ + } snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); - + chan->appl = "Parked Call"; chan->data = NULL; - pu->chan = chan; + pu->chan = chan; /* assign channel */ /* Put the parked channel on hold if we have two different channels */ if (chan != peer) { @@ -821,14 +825,14 @@ !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); } } - + pu->start = ast_tvnow(); pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime; parkingnum_copy = pu->parkingnum; if (args->extout) *(args->extout) = pu->parkingnum; - if (peer) { + if (peer) { /* This is so ugly that it hurts, but implementing get_base_channel() on local channels could have ugly side effects. We could have transferer<->local,1<->local,2<->parking and we need the callback name to be that of transferer. Since local,1/2 have the same @@ -875,9 +879,9 @@ /* If parking a channel directly, don't quiet yet get parking running on it. * All parking lot entries are put into the parking lot with notquiteyet on. */ - if (peer != chan) + if (peer != chan){ pu->notquiteyet = 0; - + } /* Wake up the (presumably select()ing) thread */ pthread_kill(parking_thread, SIGURG); ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); @@ -951,22 +955,26 @@ return park_call_full(chan, peer, &args); } -static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args) +static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args, struct ast_parkinglot *parkinglot) { struct ast_channel *chan; struct ast_frame *f; int park_status; struct ast_park_call_args park_args = {0,}; + /* transferee = rchan */ + /* transferer = peer */ + if (!args) { args = &park_args; args->timeout = timeout; args->extout = extout; } - if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) { - if (peer) + if ((args->pu = park_space_reserve(peer, rchan, args, parkinglot)) == NULL) { /* create parkinglot */ + if (peer){ /* if error */ ast_stream_and_wait(peer, "beeperr", ""); + } return AST_FEATURE_RETURN_PARKFAILED; } @@ -980,6 +988,7 @@ chan->readformat = rchan->readformat; chan->writeformat = rchan->writeformat; ast_channel_masquerade(chan, rchan); + ast_string_field_set(chan,parkinglot,rchan->parkinglot); /* set the parkinglot */ /* Setup the extensions and such */ set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); @@ -995,7 +1004,9 @@ if (!play_announcement && args == &park_args) { args->orig_chan_name = ast_strdupa(chan->name); } - + /* park call */ + /* chan = transferee */ + /* peer = transferer */ park_status = park_call_full(chan, peer, args); if (park_status == 1) { /* would be nice to play "invalid parking extension" */ @@ -1009,17 +1020,17 @@ /* Park call via masquraded channel */ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) { - return masq_park_call(rchan, peer, timeout, extout, 0, NULL); + return masq_park_call(rchan, peer, timeout, extout, 0, NULL, NULL); } -static int masq_park_call_announce_args(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args) +static int masq_park_call_announce_args(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args, struct ast_parkinglot *parkinglot) { - return masq_park_call(rchan, peer, 0, NULL, 1, args); + return masq_park_call(rchan, peer, 0, NULL, 1, args, NULL); } -static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) +static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, struct ast_parkinglot *parkinglot) { - return masq_park_call(rchan, peer, timeout, extout, 1, NULL); + return masq_park_call(rchan, peer, timeout, extout, 1, NULL, parkinglot); } /*! @@ -1057,7 +1068,14 @@ struct ast_channel *parker; struct ast_channel *parkee; int res = 0; + struct ast_parkinglot* parkinglot = NULL; + if (data){ + parkinglot = (struct ast_parkinglot *) data; + if (option_debug) + ast_log(LOG_NOTICE, "Parkinglot specified for builtin_parkcall: %s\n", parkinglot->name); + } + set_peers(&parker, &parkee, peer, chan, sense); /* we used to set chan's exten and priority to "s" and 1 here, but this generates (in some cases) an invalid @@ -1073,7 +1091,7 @@ res = ast_safe_sleep(chan, 1000); if (!res) { /* one direction used to call park_call.... */ - res = masq_park_call_announce(parkee, parker, 0, NULL); + res = masq_park_call_announce(parkee, parker, 0, NULL, parkinglot); /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ } @@ -1382,44 +1400,57 @@ const char *transferer_real_context; char xferto[256]; int res, parkstatus = 0; + struct ao2_iterator iter; + struct ast_parkinglot *parkinglot = NULL; - set_peers(&transferer, &transferee, peer, chan, sense); - transferer_real_context = real_ctx(transferer, transferee); - /* Start autoservice on chan while we talk to the originator */ - ast_autoservice_start(transferee); - ast_indicate(transferee, AST_CONTROL_HOLD); + memset(xferto, 0, sizeof(xferto)); /* zeroing out */ + set_peers(&transferer, &transferee, peer, chan, sense); /* set transferer who pressed # and transferee who is goint to be parked */ + + transferer_real_context = real_ctx(transferer, transferee); /* set the right context, in which the peer will be parked */ - memset(xferto, 0, sizeof(xferto)); + ast_autoservice_start(transferee); /* Start autoservice on chan while we talk to the originator */ + ast_indicate(transferee, AST_CONTROL_HOLD); /* indicate HOLD to transferee (play MOH) */ /* Transfer */ res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); - if (res < 0) { + if (res < 0) { /* error occured */ finishup(transferee); - return -1; /* error ? */ + return -1; } - if (res > 0) /* If they've typed a digit already, handle it */ + if (res > 0){ /* If they've typed a digit already, handle it */ xferto[0] = (char) res; + } ast_stopstream(transferer); - res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); - if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ - finishup(transferee); + res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); /* Read extension from DTMF and store it into xferto */ + if (res < 0) { /* hangup -> error occured */ + finishup(transferee); /* indicate transferee UNHOLD (stop MOH) and stop autoservice */ return res; } - if (!strcmp(xferto, ast_parking_ext())) { + + /* check whether xferto is a valid parking extension in parkinglots or not */ + iter = ao2_iterator_init(parkinglots, 0); + while ((parkinglot = ao2_iterator_next(&iter))) { + if (!strcmp(xferto,parkinglot->parkext)) { + break; /* found it */ + } + ao2_ref(parkinglot, -1); + } + + if (parkinglot) { /* found a proper parkinglot */ res = finishup(transferee); - if (res) + if (res){ /* error ? */ res = -1; - else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) { /* success */ + } + else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, parkinglot))) { /* success */ /* We return non-zero, but tell the PBX not to hang the channel when the thread dies -- We have to be careful now though. We are responsible for hanging up the channel, else it will never be hung up! */ - return 0; } else { ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus); } - /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ + /* typed-in extension is not a parking extension, maybe it's present in dialplan? -> check! */ } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); @@ -1464,7 +1495,7 @@ } else { ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); } - if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { + if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { /* Play 'extension does not exist' */ finishup(transferee); return -1; } @@ -1527,6 +1558,8 @@ struct ast_party_connected_line connected_line; struct ast_datastore *features_datastore; struct ast_dial_features *dialfeatures = NULL; + struct ao2_iterator iter; + struct ast_parkinglot *parkinglot; ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); set_peers(&transferer, &transferee, peer, chan, sense); @@ -1541,6 +1574,7 @@ finishup(transferee); return res; } + if (res > 0) /* If they've typed a digit already, handle it */ xferto[0] = (char) res; @@ -1567,13 +1601,22 @@ return AST_FEATURE_RETURN_SUCCESS; } - /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of - * the different variables for handling this properly with a builtin_atxfer */ - if (!strcmp(xferto, ast_parking_ext())) { - finishup(transferee); - return builtin_parkcall(chan, peer, config, code, sense, data); - } + /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of + * the different variables for handling this properly with a builtin_atxfer */ + /* if there are more possible parkingextensions to choose from, you need to figure out the proper parkinglot + * and pass it to builtin_parkcall */ + + iter = ao2_iterator_init(parkinglots, 0); + while ((parkinglot = ao2_iterator_next(&iter))) { /* look for all parkinglots */ + if (!strcmp(xferto, parkinglot->parkext)) { + finishup(transferee); + data = (void *)parkinglot; + return builtin_parkcall(chan, peer, config, code, sense, data); + } + ao2_ref(parkinglot, -1); + } + l = strlen(xferto); snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ @@ -1892,7 +1935,6 @@ #define FEATURES_COUNT ARRAY_LEN(builtin_features) AST_RWLOCK_DEFINE_STATIC(features_lock); - static struct ast_call_feature builtin_features[] = { { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" }, { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" }, @@ -2920,7 +2962,7 @@ * However, we don't think the feature has quite yet timed out, so just * go back into the bridge. */ continue; - } + } } else { if (config->feature_timer <=0) { /* We ran out of time */ @@ -3487,23 +3529,28 @@ return NULL; /* Never reached */ } + /*! \brief Find parkinglot by name */ struct ast_parkinglot *find_parkinglot(const char *name) { - struct ast_parkinglot *parkinglot = NULL; - struct ast_parkinglot tmp_parkinglot; - + + struct ao2_iterator iter; + struct ast_parkinglot *parkinglot; + if (ast_strlen_zero(name)) return NULL; - ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name)); + iter = ao2_iterator_init(parkinglots,0); - parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER); - - if (parkinglot && option_debug) - ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name); - - return parkinglot; + while ((parkinglot = ao2_iterator_next(&iter))) { + if (!strncasecmp(parkinglot->name,name,sizeof(parkinglot->parking_con))){ + if (option_debug){ + ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name); + } + return parkinglot; + } + } + return NULL; } AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS @@ -3521,6 +3568,8 @@ char *orig_chan_name = ast_strdupa(chan->name); char orig_exten[AST_MAX_EXTENSION]; int orig_priority = chan->priority; +// struct ao2_iterator iter; +// struct ast_parkinglot *curlot; /* Data is unused at the moment but could contain a parking lot context eventually */ @@ -3584,7 +3633,7 @@ ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); args.flags = flags.flags; - res = masq_park_call_announce_args(chan, chan, &args); + res = masq_park_call_announce_args(chan, chan, &args, NULL); /* Continue on in the dialplan */ if (res == 1) { ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); @@ -3599,7 +3648,7 @@ } /*! \brief Pickup parked call */ -static int park_exec_full(struct ast_channel *chan, const char *data, struct ast_parkinglot *parkinglot) +static int park_exec_full(struct ast_channel *chan, const char *data) { int res = 0; struct ast_channel *peer=NULL; @@ -3607,11 +3656,21 @@ struct ast_context *con; int park = 0; struct ast_bridge_config config; + struct ao2_iterator iter; + struct ast_parkinglot* parkinglot; - if (data) - park = atoi((char *) data); + if (data){ + park = atoi((char *) data); /* char to int */ + } - parkinglot = find_parkinglot(findparkinglotname(chan)); + iter = ao2_iterator_init(parkinglots, 0); /* searching for the proper parkinglot */ + while ((parkinglot = ao2_iterator_next(&iter))) { + ao2_ref(parkinglot, -1); + if (park >= parkinglot->parking_start && park <= parkinglot->parking_stop){ /* found parkinglot */ + break; + } + } + if (!parkinglot) parkinglot = default_parkinglot; @@ -3743,13 +3802,12 @@ if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); } - res = ast_bridge_call(chan, peer, &config); pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); ast_cdr_setdestchan(chan->cdr, peer->name); - /* Simulate the PBX hanging up */ + /* Simulate the PBX hanging up */ ast_hangup(peer); return -1; } else { @@ -3765,7 +3823,7 @@ static int park_exec(struct ast_channel *chan, const char *data) { - return park_exec_full(chan, data, default_parkinglot); + return park_exec_full(chan, data); } /*! \brief Unreference parkinglot object. If no more references, @@ -3814,6 +3872,25 @@ ao2_unlink(parkinglots, ruin); } +/*! + * \brief Add parking hints for all defined parking lots + * \param context + * \param start starting parkinglot number + * \param stop ending parkinglot number +*/ +static void park_add_hints(char *context, int start, int stop) +{ + int numext; + char device[AST_MAX_EXTENSION]; + char exten[10]; + + for (numext = start; numext <= stop; numext++) { + snprintf(exten, sizeof(exten), "%d", numext); + snprintf(device, sizeof(device), "park:%s@%s", exten, context); + ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); + } +} + /*! \brief Build parkinglot from configuration and chain it in */ static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *var) { @@ -3825,11 +3902,7 @@ int start = 0, end = 0; int oldparkinglot = 0; - parkinglot = find_parkinglot(name); - if (parkinglot) - oldparkinglot = 1; - else - parkinglot = create_parkinglot(name); + parkinglot = create_parkinglot(name); if (!parkinglot) return NULL; @@ -3838,10 +3911,31 @@ if (option_debug) ast_log(LOG_DEBUG, "Building parking lot %s\n", name); - + + if (!var) { /* Default parking lot */ + ast_copy_string(parkinglot->parkext, "700", sizeof(parkinglot->parkext)); + ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con)); + ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial)); + ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass)); + } else { + /* copy the values from default parkinglot to the new one */ + ast_copy_string(parkinglot->parking_con_dial, default_parkinglot->parking_con_dial, sizeof(parkinglot->parking_con_dial)); + parkinglot->parkfindnext = default_parkinglot->parkfindnext; + parkinglot->parkingtime = default_parkinglot->parkingtime; + ast_copy_string(parkinglot->mohclass, default_parkinglot->mohclass, sizeof(parkinglot->mohclass)); + parkinglot->parkaddhints = default_parkinglot->parkaddhints; + parkinglot->parkedcalltransfers = default_parkinglot->parkedcalltransfers; + parkinglot->parkedcallreparking = default_parkinglot->parkedcallreparking; + parkinglot->parkedcallhangup = default_parkinglot->parkedcallhangup; + parkinglot->parkedcallrecording = default_parkinglot->parkedcallrecording; + } + /* Do some config stuff */ while(confvar) { - if (!strcasecmp(confvar->name, "context")) { + if (!strcasecmp(confvar->name, "parkext")){ + ast_copy_string(parkinglot->parkext, confvar->value, sizeof(parkinglot->parkext)); + } + else if (!strcasecmp(confvar->name, "context")) { ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con)); } else if (!strcasecmp(confvar->name, "parkingtime")) { if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) { @@ -3859,20 +3953,53 @@ } } else if (!strcasecmp(confvar->name, "findslot")) { parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next")); + } else if (!strcasecmp(confvar->name, "parkedmusicclass")) { + ast_copy_string(parkinglot->mohclass, confvar->value, sizeof(parkinglot->mohclass)); + } else if (!strcasecmp(confvar->name, "parkinghints")) { + parkinglot->parkaddhints = ast_true(confvar->value); + } else if (!strcasecmp(confvar->name, "parkedcalltransfers")){ + if (!strcasecmp(confvar->value, "both")) + parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; + else if (!strcasecmp(confvar->value, "caller")) + parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; + else if (!strcasecmp(confvar->value, "callee")) + parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; + } else if (!strcasecmp(confvar->name, "parkedcallreparking")) { + if (!strcasecmp(confvar->value, "both")) + parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; + else if (!strcasecmp(confvar->value, "caller")) + parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; + else if (!strcasecmp(confvar->value, "callee")) + parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; + } else if (!strcasecmp(confvar->name, "parkedcallhangup")) { + if (!strcasecmp(confvar->value, "both")) + parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; + else if (!strcasecmp(confvar->value, "caller")) + parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; + else if (!strcasecmp(confvar->value, "callee")) + parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; + } else if (!strcasecmp(confvar->name, "parkedcallrecording")) { + if (!strcasecmp(confvar->value, "both")) + parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; + else if (!strcasecmp(confvar->value, "caller")) + parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; + else if (!strcasecmp(confvar->value, "callee")) + parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; } confvar = confvar->next; } + + /* if there's no parkext specified - set to default */ + if (ast_strlen_zero(parkinglot->parkext)){ + ast_log(LOG_NOTICE,"no parkext specified for %s - setting it to %s\n",parkinglot->name, "700"); + ast_copy_string(parkinglot->parkext,"700",sizeof(parkinglot->parkext)); + } + /* make sure parkingtime is set if not specified */ if (parkinglot->parkingtime == 0) { parkinglot->parkingtime = DEFAULT_PARK_TIME; } - if (!var) { /* Default parking lot */ - ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con)); - ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial)); - ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass)); - } - /* Check for errors */ if (ast_strlen_zero(parkinglot->parking_con)) { ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name); @@ -3887,12 +4014,16 @@ /* Add a parking extension into the context */ if (!error && !oldparkinglot) { - if (!ast_strlen_zero(ast_parking_ext())) { - if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1) + if (!ast_strlen_zero(parkinglot->parkext)) { + if (ast_add_extension2(con, 1, parkinglot->parkext, 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1) error = 1; } } + /* Add parking hints */ + if (parkinglot->parkaddhints) + park_add_hints(parkinglot->parking_con, parkinglot->parking_start, parkinglot->parking_stop); + ao2_unlock(parkinglot); if (error) { @@ -3914,25 +4045,6 @@ } -/*! - * \brief Add parking hints for all defined parking lots - * \param context - * \param start starting parkinglot number - * \param stop ending parkinglot number -*/ -static void park_add_hints(char *context, int start, int stop) -{ - int numext; - char device[AST_MAX_EXTENSION]; - char exten[10]; - - for (numext = start; numext <= stop; numext++) { - snprintf(exten, sizeof(exten), "%d", numext); - snprintf(device, sizeof(device), "park:%s@%s", exten, context); - ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); - } -} - static int load_config(void) { int start = 0, end = 0; @@ -3943,8 +4055,6 @@ struct ast_variable *var = NULL; struct feature_group *fg = NULL; struct ast_flags config_flags = { 0 }; - char old_parking_ext[AST_MAX_EXTENSION]; - char old_parking_con[AST_MAX_EXTENSION] = ""; char *ctg; static const char * const categories[] = { /* Categories in features.conf that are not @@ -3954,22 +4064,29 @@ "featuremap", "applicationmap" }; + struct ao2_iterator iter; + struct ast_parkinglot *curlot; + /* delete existing parkinglots */ + iter = ao2_iterator_init(parkinglots, 0); + while ((curlot = ao2_iterator_next(&iter))) { + parkinglot_destroy(curlot); + ao2_ref(curlot, -1); + } + default_parkinglot = NULL; + + default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); if (default_parkinglot) { - strcpy(old_parking_con, default_parkinglot->parking_con); - strcpy(old_parking_ext, parking_ext); - } else { - default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); - if (default_parkinglot) { - ao2_lock(default_parkinglot); - default_parkinglot->parking_start = 701; - default_parkinglot->parking_stop = 750; - default_parkinglot->parking_offset = 0; - default_parkinglot->parkfindnext = 0; - default_parkinglot->parkingtime = DEFAULT_PARK_TIME; - ao2_unlock(default_parkinglot); - } + ao2_lock(default_parkinglot); + ast_copy_string(default_parkinglot->parkext,"700",sizeof(default_parkinglot->parkext)); + default_parkinglot->parking_start = 701; + default_parkinglot->parking_stop = 750; + default_parkinglot->parking_offset = 0; + default_parkinglot->parkfindnext = 0; + default_parkinglot->parkingtime = DEFAULT_PARK_TIME; + ao2_unlock(default_parkinglot); } + if (default_parkinglot) { if (option_debug) ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n"); @@ -3977,10 +4094,9 @@ ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n"); return -1; } - /* Reset to defaults */ - strcpy(parking_ext, "700"); + strcpy(default_parkinglot->parkext,"700"); strcpy(pickup_ext, "*8"); courtesytone[0] = '\0'; strcpy(xfersound, "beep"); @@ -4010,7 +4126,7 @@ } for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { if (!strcasecmp(var->name, "parkext")) { - ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); + ast_copy_string(default_parkinglot->parkext, var->value, sizeof(default_parkinglot->parkext)); } else if (!strcasecmp(var->name, "context")) { ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con)); } else if (!strcasecmp(var->name, "parkingtime")) { @@ -4123,7 +4239,6 @@ if (remap_feature(var->name, var->value)) ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); } - /* Map a key combination to an application*/ ast_unregister_features(); for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { @@ -4157,20 +4272,20 @@ continue; } AST_RWLIST_UNLOCK(&feature_list); - + if (!(feature = ast_calloc(1, sizeof(*feature)))) - continue; + continue; ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); ast_copy_string(feature->app, app, FEATURE_APP_LEN); ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); - + if (app_args) ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); if (moh_class) ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); - + ast_copy_string(feature->exten, exten, sizeof(feature->exten)); feature->operation = feature_exec_app; ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); @@ -4212,14 +4327,16 @@ while ((ctg = ast_category_browse(cfg, ctg))) { /* Is this a parkinglot definition ? */ if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { - ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); - if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) + ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); + if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) /* Build a new parkinglot */ ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); else + { ast_debug(1, "Configured parking context %s\n", ctg); + } continue; } - /* No, check if it's a group */ + /* No, check if it's a group */ for (i = 0; i < ARRAY_LEN(categories); i++) { if (!strcasecmp(categories[i], ctg)) break; @@ -4251,22 +4368,15 @@ ast_config_destroy(cfg); - /* Remove the old parking extension */ - if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { - if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0)) - notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); - ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); - } - if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) { ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con); return -1; } - res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); + res = ast_add_extension2(con, 1, default_parkinglot->parkext, 1, NULL, NULL, parkcall, NULL, NULL, registrar); if (default_parkinglot->parkaddhints) park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop); if (!res) - notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE); + notify_metermaids(default_parkinglot->parkext, default_parkinglot->parking_con, AST_DEVICE_INUSE); return res; } @@ -4329,9 +4439,11 @@ while ((curlot = ao2_iterator_next(&iter))) { ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); ast_cli(a->fd, "------------\n"); - ast_cli(a->fd,"%-22s: %s\n", "Parking extension", parking_ext); + ast_cli(a->fd,"%-22s: %s\n", "Parking extension", curlot->parkext); ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con); ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop); + ast_cli(a->fd,"%-22s: %d\n", "Parkingtime", curlot->parkingtime); + ast_cli(a->fd,"%-22s: %s\n", "MusicOnHold class", curlot->mohclass); ast_cli(a->fd,"\n"); ao2_ref(curlot, -1); } @@ -4349,7 +4461,7 @@ /* Reload configuration */ res = load_config(); - + //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); return res; } @@ -5125,3 +5237,4 @@ return res; } +