Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (.../branches/1.4) (revision 47644) +++ channels/chan_sip.c (.../team/murf/bug7433) (revision 47644) @@ -513,6 +513,7 @@ static struct ast_codec_pref default_prefs; /*!< Default codec prefs */ /* Global settings only apply to the channel */ +static int global_limitonpeers; /*!< Match call limit on peers only */ static int global_rtautoclear; static int global_notifyringing; /*!< Send notifications on ringing */ static int global_alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */ @@ -2941,7 +2942,7 @@ static int update_call_counter(struct sip_pvt *fup, int event) { char name[256]; - int *inuse, *call_limit, *inringing; + int *inuse=NULL, *call_limit=NULL, *inringing=NULL; int outgoing = ast_test_flag(&fup->flags[0], SIP_OUTGOING); struct sip_user *u = NULL; struct sip_peer *p = NULL; @@ -2950,22 +2951,25 @@ ast_log(LOG_DEBUG, "Updating call counter for %s call\n", outgoing ? "outgoing" : "incoming"); /* Test if we need to check call limits, in order to avoid realtime lookups if we do not need it */ - if (!ast_test_flag(&fup->flags[0], SIP_CALL_LIMIT)) - return 0; + /* Huh? If call_limit is 0, there is no devicestate tracking at all? */ + /* if (!ast_test_flag(&fup->flags[0], SIP_CALL_LIMIT)) + return 0; */ + ast_copy_string(name, fup->username, sizeof(name)); /* Check the list of users only for incoming calls */ - if (!outgoing && (u = find_user(name, 1)) ) { + if (global_limitonpeers == FALSE && !outgoing && (u = find_user(name, 1))) { inuse = &u->inUse; call_limit = &u->call_limit; inringing = NULL; - } else if ( (p = find_peer(fup->peername, NULL, 1) ) ) { /* Try to find peer */ + } else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1) ) ) { /* Try to find peer */ inuse = &p->inUse; call_limit = &p->call_limit; inringing = &p->inRinging; ast_copy_string(name, fup->peername, sizeof(name)); - } else { + } + if (!p && !u) { if (option_debug > 1) ast_log(LOG_DEBUG, "%s is not a local device, no call limit\n", name); return 0; @@ -8029,7 +8033,7 @@ /* If they put someone on hold, increment the value... otherwise decrement it */ if (hold) peer->onHold++; - else if (hold > 0) + else peer->onHold--; /* Request device state update */ @@ -10125,6 +10129,7 @@ ast_cli(fd, " Our auth realm %s\n", global_realm); ast_cli(fd, " Realm. auth: %s\n", authl ? "Yes": "No"); ast_cli(fd, " Always auth rejects: %s\n", global_alwaysauthreject ? "Yes" : "No"); + ast_cli(fd, " Call limit peers only: %s\n", global_limitonpeers ? "Yes" : "No"); ast_cli(fd, " User Agent: %s\n", global_useragent); ast_cli(fd, " MWI checking interval: %d secs\n", global_mwitime); ast_cli(fd, " Reg. context: %s\n", S_OR(global_regcontext, "(not set)")); @@ -13061,6 +13066,8 @@ parse_ok_contact(p, req); } else { /* Re-invite on existing call */ ast_clear_flag(&p->flags[0], SIP_OUTGOING); /* This is now an inbound dialog */ + /* aught not something be done here, to make sure the devicestate + * is proper in the sip_user struct? */ /* Handle SDP here if we already have an owner */ if (find_sdp(req)) { if (process_sdp(p, req)) { @@ -14928,7 +14935,7 @@ if (option_debug > 2) ast_log(LOG_DEBUG, "Checking device state for peer %s\n", host); - + if ((p = find_peer(host, NULL, 1))) { if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) { /* we have an address for the peer */ @@ -14938,19 +14945,18 @@ } else { /* qualify is not on, or the peer is responding properly */ /* check call limit */ - if (p->call_limit && (p->inUse == p->call_limit)) + if (p->call_limit && (p->inUse == p->call_limit)) { res = AST_DEVICE_BUSY; - else if (p->call_limit && p->inUse) + } else if (p->onHold) { + res = AST_DEVICE_ONHOLD; + } else if (p->inRinging && p->inRinging == p->inUse) { + res = AST_DEVICE_RINGING; + } else if (p->inRinging) { + res = AST_DEVICE_RINGINUSE; + } else if (p->inUse) { res = AST_DEVICE_INUSE; - else + } else { res = AST_DEVICE_NOT_INUSE; - if (p->onHold) - res = AST_DEVICE_ONHOLD; - else if (p->inRinging) { - if (p->inRinging == p->inUse) - res = AST_DEVICE_RINGING; - else - res = AST_DEVICE_RINGINUSE; } } } else { @@ -14960,8 +14966,9 @@ ASTOBJ_UNREF(p,sip_destroy_peer); } else { hp = ast_gethostbyname(host, &ahp); - if (hp) + if (hp) { res = AST_DEVICE_UNKNOWN; + } } return res; @@ -15852,6 +15859,7 @@ global_regcontext[0] = '\0'; expiry = DEFAULT_EXPIRY; global_notifyringing = DEFAULT_NOTIFYRINGING; + global_limitonpeers = FALSE; /*!< Match call limit on peers only */ global_alwaysauthreject = 0; global_allowsubscribe = FALSE; ast_copy_string(global_useragent, DEFAULT_USERAGENT, sizeof(global_useragent)); @@ -15975,6 +15983,8 @@ ast_copy_string(default_notifymime, v->value, sizeof(default_notifymime)); } else if (!strcasecmp(v->name, "notifyringing")) { global_notifyringing = ast_true(v->value); + } else if (!strcasecmp(v->name, "limitpeersonly")) { + global_limitonpeers = ast_true(v->value); } else if (!strcasecmp(v->name, "alwaysauthreject")) { global_alwaysauthreject = ast_true(v->value); } else if (!strcasecmp(v->name, "mohinterpret") Index: doc/queues-with-callback-members.txt =================================================================== --- doc/queues-with-callback-members.txt (.../branches/1.4) (revision 47644) +++ doc/queues-with-callback-members.txt (.../team/murf/bug7433) (revision 47644) @@ -522,3 +522,10 @@ In the above examples, some of the possible error checking has been omitted, to reduce clutter and make the examples clearer. +If SIP devices are being used with queues, you will want to +specify limitpeersonly=yes in the [general] section of the sip.conf +file; it will help keep devicestate visible and correct for your +sip extensions, with regards to "in use", "ringing", "not in use", etc, +with respect to queues. Queues use this information to determine +whether or not the agent is available for calling. + Index: main/devicestate.c =================================================================== --- main/devicestate.c (.../branches/1.4) (revision 47644) +++ main/devicestate.c (.../team/murf/bug7433) (revision 47644) @@ -117,11 +117,22 @@ if (!chan) return AST_DEVICE_UNKNOWN; + + switch (chan->_state) { - if (chan->_state == AST_STATE_RINGING) + case AST_STATE_RINGING: res = AST_DEVICE_RINGING; - else + break; + case AST_STATE_BUSY: + res = AST_DEVICE_BUSY; + break; + case AST_STATE_DOWN: + res = AST_DEVICE_NOT_INUSE; + break; + default: res = AST_DEVICE_INUSE; + break; + } ast_channel_unlock(chan); Index: configs/sip.conf.sample =================================================================== --- configs/sip.conf.sample (.../branches/1.4) (revision 47644) +++ configs/sip.conf.sample (.../team/murf/bug7433) (revision 47644) @@ -121,6 +121,12 @@ ; for peers and users as well ;callevents=no ; generate manager events when sip ua ; performs events (e.g. hold) +;limitpeersonly=no ; Apply all call limits ("limit=") only to peers, never + ; to users. This improves handling of call limits + ; and device states in certain situations. The user part + ; of a type=friend will still be affected by the call + ; limit, but Asterisk will only use one object for + ; counting the simultaneous calls. ;alwaysauthreject = yes ; When an incoming INVITE or REGISTER is to be rejected, ; for any reason, always reject with '401 Unauthorized' ; instead of letting the requester know whether there was