diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 8f473a4fad596cbf5f249903aa2103181b843945..d53984377200580496b5a4a2fce3826a95e4794d 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -363,6 +363,15 @@ enum sla_trunk_state { SLA_TRUNK_STATE_ONHOLD, }; +enum sla_hold_access { + /*! This means that any station can put it on hold, and any station + * can retrieve the call from hold. */ + SLA_HOLD_OPEN, + /*! This means that only the station that put the call on hold may + * retrieve it from hold. */ + SLA_HOLD_PRIVATE, +}; + struct sla_trunk_ref; struct sla_station { @@ -382,6 +391,9 @@ struct sla_station { * is set for a specific trunk on this station, that will take * priority over this value. */ unsigned int ring_delay; + /*! This option uses the values in the sla_hold_access enum and sets the + * access control type for hold on this station. */ + unsigned int hold_access:1; }; struct sla_station_ref { @@ -408,6 +420,9 @@ struct sla_trunk { /*! If set to 1, no station will be able to join an active call with * this trunk. */ unsigned int barge_disabled:1; + /*! This option uses the values in the sla_hold_access enum and sets the + * access control type for hold on this trunk. */ + unsigned int hold_access:1; }; struct sla_trunk_ref { @@ -993,6 +1008,23 @@ static const char meetme_usage[] = "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n" " Executes a command for the conference or on a conferee\n"; +static const char *sla_hold_str(unsigned int hold_access) +{ + const char *hold = "Unknown"; + + switch (hold_access) { + case SLA_HOLD_OPEN: + hold = "Open"; + break; + case SLA_HOLD_PRIVATE: + hold = "Private"; + default: + break; + } + + return hold; +} + static int sla_show_trunks(int fd, int argc, char **argv) { const struct sla_trunk *trunk; @@ -1014,11 +1046,13 @@ static int sla_show_trunks(int fd, int argc, char **argv) "=== ==> AutoContext: %s\n" "=== ==> RingTimeout: %s\n" "=== ==> BargeAllowed: %s\n" + "=== ==> HoldAccess: %s\n" "=== ==> Stations ...\n", trunk->name, trunk->device, S_OR(trunk->autocontext, "(none)"), ring_timeout, - trunk->barge_disabled ? "No" : "Yes"); + trunk->barge_disabled ? "No" : "Yes", + sla_hold_str(trunk->hold_access)); AST_RWLIST_RDLOCK(&sla_stations); AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) ast_cli(fd, "=== ==> Station name: %s\n", station_ref->station->name); @@ -1075,13 +1109,15 @@ static int sla_show_stations(int fd, int argc, char **argv) ast_cli(fd, "=== ---------------------------------------------------------\n" "=== Station Name: %s\n" "=== ==> Device: %s\n" - "=== ==> AutoContext: %s\n" - "=== ==> RingTimeout: %s\n" - "=== ==> RingDelay: %s\n" - "=== ==> Trunks ...\n", - station->name, station->device, - S_OR(station->autocontext, "(none)"), - ring_timeout, ring_delay); + "=== ==> AutoContext: %s\n" + "=== ==> RingTimeout: %s\n" + "=== ==> RingDelay: %s\n" + "=== ==> HoldAccess: %s\n" + "=== ==> Trunks ...\n", + station->name, station->device, + S_OR(station->autocontext, "(none)"), + ring_timeout, ring_delay, + sla_hold_str(station->hold_access)); AST_RWLIST_RDLOCK(&sla_trunks); AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { if (trunk_ref->ring_timeout) { @@ -3080,12 +3116,32 @@ static struct sla_station *sla_find_station(const char *name) return station; } +static int sla_check_station_hold_access(const struct sla_trunk *trunk) +{ + struct sla_station_ref *station_ref; + struct sla_trunk_ref *trunk_ref; + + /* For each station that has this call on hold, check for private hold. */ + AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) { + AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) { + if (trunk_ref->trunk != trunk) + continue; + if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD && trunk_ref->chan && + station_ref->station->hold_access == SLA_HOLD_PRIVATE) + return 1; + return 0; + } + } + + return 0; +} + /*! \brief Find a trunk reference on a station by name * \param station the station * \param name the trunk's name * \return a pointer to the station's trunk reference. If the trunk - * is not found, or if it is not idle and barge is disabled, - * then NULL will be returned. + * is not found, it is not idle and barge is disabled, or if + * it is on hold and private hold is set, then NULL will be returned. */ static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station, const char *name) @@ -3095,8 +3151,14 @@ static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) { if (strcasecmp(trunk_ref->trunk->name, name)) continue; - if (trunk_ref->trunk->barge_disabled && trunk_ref->state != SLA_TRUNK_STATE_IDLE) + + if ( (trunk_ref->trunk->barge_disabled + && trunk_ref->state != SLA_TRUNK_STATE_IDLE) || + (trunk_ref->trunk->hold_stations + && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE) || + sla_check_station_hold_access(trunk_ref->trunk) ) trunk_ref = NULL; + break; } @@ -4033,7 +4095,12 @@ static int sla_station_exec(struct ast_channel *chan, void *data) AST_RWLIST_UNLOCK(&sla_trunks); if (!trunk_ref) { - ast_log(LOG_NOTICE, "No trunks available for call.\n"); + if (ast_strlen_zero(trunk_name)) + ast_log(LOG_NOTICE, "No trunks available for call.\n"); + else { + ast_log(LOG_NOTICE, "Can't join existing call on trunk " + "'%s' due to access controls.\n", trunk_name); + } pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION"); return 0; } @@ -4366,7 +4433,16 @@ static int sla_build_trunk(struct ast_config *cfg, const char *cat) } } else if (!strcasecmp(var->name, "barge")) trunk->barge_disabled = ast_false(var->value); - else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) { + else if (!strcasecmp(var->name, "hold")) { + if (!strcasecmp(var->value, "private")) + trunk->hold_access = SLA_HOLD_PRIVATE; + else if (!strcasecmp(var->value, "open")) + trunk->hold_access = SLA_HOLD_OPEN; + else { + ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n", + var->value, trunk->name); + } + } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) { ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", var->name, var->lineno, SLA_CONFIG_FILE); } @@ -4492,6 +4568,16 @@ static int sla_build_station(struct ast_config *cfg, const char *cat) var->value, station->name); station->ring_delay = 0; } + } else if (!strcasecmp(var->name, "hold")) { + if (!strcasecmp(var->value, "private")) + station->hold_access = SLA_HOLD_PRIVATE; + else if (!strcasecmp(var->value, "open")) + station->hold_access = SLA_HOLD_OPEN; + else { + ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n", + var->value, station->name); + } + } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) { ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n", var->name, var->lineno, SLA_CONFIG_FILE); diff --git a/configs/sla.conf.sample b/configs/sla.conf.sample index 83129732b7a59e4b749851ea6f18c7ac93a9c478..55312cb65eced5adbe340e8d93f0a3318ed729d4 100644 --- a/configs/sla.conf.sample +++ b/configs/sla.conf.sample @@ -13,23 +13,31 @@ ; ---- Trunk Declarations ------------- ; -;[line1] ; Provide a name for this trunk. -;type=trunk ; This line is what marks this entry as a trunk. +;[line1] ; Provide a name for this trunk. +;type=trunk ; This line is what marks this entry as a trunk. ; -;device=Zap/3 ; Map this trunk declaration to a specific device. - ; NOTE: At this point, this *must* be a zap channel! +;device=Zap/3 ; Map this trunk declaration to a specific device. + ; NOTE: At this point, this *must* be a zap channel! -;autocontext=line1 ; This supports automatic generation of the dialplan entries - ; if the autocontext option is used. Each trunk should have - ; a unique context name. Then, in zapata.conf, this device - ; should be configured to have incoming calls go to this context. +;autocontext=line1 ; This supports automatic generation of the dialplan entries + ; if the autocontext option is used. Each trunk should have + ; a unique context name. Then, in zapata.conf, this device + ; should be configured to have incoming calls go to this context. -;ringtimeout=30 ; Set how long to allow this trunk to ring on an inbound call before hanging - ; it up as an unanswered call. The value is in seconds. +;ringtimeout=30 ; Set how long to allow this trunk to ring on an inbound call before hanging + ; it up as an unanswered call. The value is in seconds. -;barge=no ; If this option is set to "no", then no station will be - ; allowed to join a call that is in progress. The default - ; value is "yes". +;barge=no ; If this option is set to "no", then no station will be + ; allowed to join a call that is in progress. The default + ; value is "yes". + +;hold=private ; This option configure hold permissions for this trunk. + ; "open" - This means that any station can put this trunk + ; on hold, and any station can retrieve it from + ; hold. This is the default. + ; "private" - This means that once a station puts the + ; trunk on hold, no other station will be + ; allowed to retrieve the call from hold. ;[line2] ;type=trunk @@ -50,37 +58,50 @@ ; ---- Station Declarations ------------ -;type=station ; This line indicates that this entry is a station. - -;autocontext=sla_stations ; This supports automatic generation of the dialplan entries if - ; the autocontext option is used. All stations can use the same - ; context without conflict. The device for this station should - ; have its context configured to the same one listed here. - -;ringtimeout=10 ; Set a timeout for how long to allow the station to ring for an - ; incoming call, in seconds. - -;ringdelay=10 ; Set a time for how long to wait before beginning to ring this station - ; once there is an incoming call, in seconds. - -;trunk=line1 ; Individually list all of the trunks that will appear on this station. This - ; order is significant. It should be the same order as they appear on the - ; phone. The order here defines the order of preference that the trunks will - ; be used. +;type=station ; This line indicates that this entry is a station. + +;autocontext=sla_stations ; This supports automatic generation of the dialplan entries if + ; the autocontext option is used. All stations can use the same + ; context without conflict. The device for this station should + ; have its context configured to the same one listed here. + +;ringtimeout=10 ; Set a timeout for how long to allow the station to ring for an + ; incoming call, in seconds. + +;ringdelay=10 ; Set a time for how long to wait before beginning to ring this station + ; once there is an incoming call, in seconds. + +;hold=private ; This option configure hold permissions for this station. Note + ; that if private hold is set in the trunk entry, that will override + ; anything here. However, if a trunk has open hold access, but this + ; station is set to private hold, then the private hold will be in + ; effect. + ; "open" - This means that once this station puts a call + ; on hold, any other station is allowed to retrieve + ; it. This is the default. + ; "private" - This means that once this station puts a + ; call on hold, no other station will be + ; allowed to retrieve the call from hold. + + +;trunk=line1 ; Individually list all of the trunks that will appear on this station. This + ; order is significant. It should be the same order as they appear on the + ; phone. The order here defines the order of preference that the trunks will + ; be used. ;trunk=line2 -;trunk=line3,ringdelay=5 ; A ring delay for the station can also be specified for a specific trunk. - ; If a ring delay is specified both for the whole station and for a specific - ; trunk on a station, the setting for the specific trunk will take priority. - ; This value is in seconds. +;trunk=line3,ringdelay=5 ; A ring delay for the station can also be specified for a specific trunk. + ; If a ring delay is specified both for the whole station and for a specific + ; trunk on a station, the setting for the specific trunk will take priority. + ; This value is in seconds. -;trunk=line4,ringtimeout=5 ; A ring timeout for the station can also be specified for a specific trunk. - ; If a ring timeout is specified both for the whole station and for a specific - ; trunk on a station, the setting for the specific trunk will take priority. - ; This value is in seconds. +;trunk=line4,ringtimeout=5 ; A ring timeout for the station can also be specified for a specific trunk. + ; If a ring timeout is specified both for the whole station and for a specific + ; trunk on a station, the setting for the specific trunk will take priority. + ; This value is in seconds. -;[station1](station) ; Define a station that uses the configuration from the template "station". -;device=SIP/station1 ; Each station must be mapped to a device. +;[station1](station) ; Define a station that uses the configuration from the template "station". +;device=SIP/station1 ; Each station must be mapped to a device. ; ;[station2](station) ;device=SIP/station2