Index: channels/chan_dahdi.c =================================================================== --- channels/chan_dahdi.c (revision 241226) +++ channels/chan_dahdi.c (working copy) @@ -11623,7 +11623,7 @@ tmp->callgroup = conf->chan.callgroup; tmp->pickupgroup= conf->chan.pickupgroup; if (conf->chan.vars) { - tmp->vars = ast_variable_new(conf->chan.vars->name, conf->chan.vars->value, ""); + tmp->vars = conf->chan.vars; } tmp->cid_rxgain = conf->chan.cid_rxgain; tmp->rxgain = conf->chan.rxgain; Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 241226) +++ channels/chan_sip.c (working copy) @@ -15322,8 +15322,8 @@ struct ao2_iterator i; /* the last argument is left-aligned, so we don't need a size anyways */ -#define FORMAT2 "%-25.25s %-15.15s %-3.3s %-10.10s %-3.3s %-8s %-10s %s\n" -#define FORMAT "%-25.25s %-15.15s %-3.3s %-3.3s %-3.3s %-8d %-10s %s\n" +#define FORMAT2 "%-25.25s %-15.15s %-3.3s %-10.10s %-3.3s %-8s %-17s %s %s\n" +#define FORMAT "%-25.25s %-15.15s %-3.3s %-10.10s %-3.3s %-8d %-17s %s %s\n" char name[256]; int total_peers = 0; @@ -15363,7 +15363,7 @@ } if (!s) /* Normal list */ - ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Forcerport", "ACL", "Port", "Status", (realtimepeers ? "Realtime" : "")); + ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Forcerport", "ACL", "Port", "Status", (realtimepeers ? "Realtime" : ""), "Callerid"); i = ao2_iterator_init(peers, 0); @@ -15393,6 +15393,7 @@ for(k=0; k < total_peers; k++) { char status[20] = ""; char srch[2000]; + char cbuf[256]; char pstatus; peer = peerarray[k]; @@ -15426,7 +15427,8 @@ ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */ peer->ha ? " A " : " ", /* permit/deny */ ntohs(peer->addr.sin_port), status, - realtimepeers ? (peer->is_realtime ? "Cached RT":"") : ""); + realtimepeers ? (peer->is_realtime ? "Cached RT":"") : "", + ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "")); if (!s) {/* Normal CLI list */ ast_cli(fd, FORMAT, name, @@ -15434,9 +15436,9 @@ peer->host_dynamic ? " D " : " ", /* Dynamic or not? */ ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */ peer->ha ? " A " : " ", /* permit/deny */ - ntohs(peer->addr.sin_port), status, - realtimepeers ? (peer->is_realtime ? "Cached RT":"") : ""); + realtimepeers ? (peer->is_realtime ? "Cached RT":"") : "", + ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "")); } else { /* Manager format */ /* The names here need to be the same as other channels */ astman_append(s, @@ -15452,7 +15454,8 @@ "TextSupport: %s\r\n" "ACL: %s\r\n" "Status: %s\r\n" - "RealtimeDevice: %s\r\n\r\n", + "RealtimeDevice: %s\r\n" + "Callerid: %s\r\n\r\n", idtext, peer->name, peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "-none-", @@ -15463,7 +15466,8 @@ ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT) ? "yes" : "no", /* TEXTSUPPORT=yes? */ peer->ha ? "yes" : "no", /* permit/deny */ status, - realtimepeers ? (peer->is_realtime ? "yes":"no") : "no"); + realtimepeers ? (peer->is_realtime ? "yes":"no") : "no", + ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "")); } ao2_unlock(peer); unref_peer(peer, "toss iterator peer ptr"); @@ -17403,10 +17407,21 @@ } else if (!ast_strlen_zero(c = get_header(req, "X-ClientCode"))) { /* Client code (from SNOM phone) */ if (ast_test_flag(&p->flags[0], SIP_USECLIENTCODE)) { - if (p->owner && p->owner->cdr) - ast_cdr_setuserfield(p->owner, c); - if (p->owner && ast_bridged_channel(p->owner) && ast_bridged_channel(p->owner)->cdr) - ast_cdr_setuserfield(ast_bridged_channel(p->owner), c); + struct ast_channel *chan = p->owner; + + if (chan) { + pbx_builtin_setvar_helper(chan, "SIPCLIENTCODE", c); + manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", + "Channel: %s\r\nChanneltype: %s\r\nUniqueid: %s\r\nX-ClientCode: %s\r\n", + chan->name, "SIP", chan->uniqueid, c); + if (chan->cdr) { + ast_cdr_setuserfield(chan, c); + } + chan = ast_bridged_channel(p->owner); + if (chan && chan->cdr) { + ast_cdr_setuserfield(chan, c); + } + } transmit_response(p, "200 OK", req); } else { transmit_response(p, "403 Forbidden", req); Index: apps/app_directed_pickup.c =================================================================== --- apps/app_directed_pickup.c (revision 241226) +++ apps/app_directed_pickup.c (working copy) @@ -79,6 +79,13 @@ + + + + + This will pickup a specified channel if ringing. @@ -303,24 +310,65 @@ return res; } +/* Find channel for pick up specified by partial channel name */ +static int find_by_part(void *obj, void *arg, void *data, int flags) +{ + struct ast_channel *c = obj; + const char *part = data; + int res; + + ast_channel_lock(c); + res = (!memcmp(c->name, part, strlen(part))) && can_pickup(c); + ast_channel_unlock(c); + + return res ? CMP_MATCH | CMP_STOP : 0; +} + +/* Attempt to pick up specified by partial channel name */ +static int pickup_by_part(struct ast_channel *chan, const char *part) +{ + struct ast_channel *target; + int res = -1; + + if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) { + ast_channel_lock(target); + res = pickup_do(chan, target); + ast_channel_unlock(target); + target = ast_channel_unref(target); + } + + return res; +} + /* application entry point for PickupChan() */ static int pickupchan_exec(struct ast_channel *chan, const char *data) { int res = 0; - char *tmp = ast_strdupa(data); char *pickup = NULL; + char *parse; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(channel); + AST_APP_ARG(options); + ); + parse = ast_strdupa(data); + AST_STANDARD_APP_ARGS(args, parse); - if (ast_strlen_zero(data)) { + if (ast_strlen_zero(args.channel)) { ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n"); return -1; } /* Parse channel */ - while (!ast_strlen_zero(tmp) && (pickup = strsep(&tmp, "&"))) { + while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) { if (!strncasecmp(chan->name, pickup, strlen(pickup))) { ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup); } else { - if (!pickup_by_channel(chan, pickup)) { + if (!strcmp(args.options, "p")) { + if (!pickup_by_part(chan, pickup)) { + break; + } + } + else if (!pickup_by_channel(chan, pickup)) { break; } ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup); Index: apps/app_dial.c =================================================================== --- apps/app_dial.c (revision 241226) +++ apps/app_dial.c (working copy) @@ -798,6 +798,18 @@ /* Before processing channel, go ahead and check for forwarding */ ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name); + manager_event(EVENT_FLAG_CALL, "Forward", + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "CallerIDNum: %s\r\n" + "CallerIDName: %s\r\n" + "Destination: %s/%s\r\n" + "Via: %s\r\n", + in->name, in->uniqueid, + in->cid.cid_num ? in->cid.cid_num : "unknown", + in->cid.cid_name ? in->cid.cid_name : "unknown", + tech, stuff, + c->name); /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */ if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) { ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff); Index: apps/app_queue.c =================================================================== --- apps/app_queue.c (revision 241226) +++ apps/app_queue.c (working copy) @@ -724,6 +724,9 @@ /* The maximum length of each persistent member queue database entry */ #define PM_MAX_LEN 8192 +/*! \brief queues.conf keep statistics on reoads option */ +static int queue_keep_stats = 0; + /*! \brief queues.conf [general] option */ static int queue_persistent_members = 0; @@ -1366,13 +1369,11 @@ } /*! \brief allocate space for new queue member and set fields based on parameters passed */ -static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface) +static struct member *create_queue_member(const char *interface, const char *membername, const char *state_interface) { struct member *cur; if ((cur = ao2_alloc(sizeof(*cur), NULL))) { - cur->penalty = penalty; - cur->paused = paused; ast_copy_string(cur->interface, interface, sizeof(cur->interface)); if (!ast_strlen_zero(state_interface)) ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); @@ -1890,9 +1891,11 @@ /* Create a new member */ if (!found) { - if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { + if ((m = create_queue_member(interface, membername, state_interface))) { m->dead = 0; m->realtime = 1; + m->penalty = penalty; + m->paused = paused; ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", ""); ao2_link(q->members, m); @@ -4893,7 +4896,9 @@ ao2_lock(q); if ((old_member = interface_exists(q, interface)) == NULL) { - if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { + if ((new_member = create_queue_member(interface, membername, state_interface))) { + new_member->penalty = penalty; + new_member->paused = paused; new_member->dynamic = 1; ao2_link(q->members, new_member); q->membercount++; @@ -6151,6 +6156,9 @@ static void queue_set_global_params(struct ast_config *cfg) { const char *general_val = NULL; + queue_keep_stats = 0; + if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats"))) + queue_keep_stats = ast_true(general_val); queue_persistent_members = 0; if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) queue_persistent_members = ast_true(general_val); @@ -6231,7 +6239,16 @@ /* Find the old position in the list */ ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); - if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { + if ((newm = create_queue_member(interface, membername, state_interface))) { + newm->penalty = penalty; + if (cur) { + newm->paused = cur->paused; + newm->status = cur->status; + newm->lastcall = cur->lastcall; + if (queue_keep_stats) { + newm->calls = cur->calls; + } + } ao2_link(q->members, newm); ao2_ref(newm, -1); } @@ -7068,6 +7085,9 @@ if (!header_found) { ast_set_flag(&mask, AST_FLAGS_ALL); + if (queue_keep_stats) { + ast_clear_flag(&mask, QUEUE_RESET_STATS); + } } if (!reload_handler(1, &mask, queuename)) { @@ -7586,6 +7606,9 @@ ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); } else if (!strcasecmp(a->argv[2], "all")) { ast_set_flag(&mask, AST_FLAGS_ALL); + if (queue_keep_stats) { + ast_clear_flag(&mask, QUEUE_RESET_STATS); + } } if (a->argc == 3) { @@ -7738,6 +7761,10 @@ static int reload(void) { struct ast_flags mask = {AST_FLAGS_ALL,}; + + if (queue_keep_stats) { + ast_clear_flag(&mask, QUEUE_RESET_STATS); + } ast_unload_realtime("queue_members"); reload_handler(1, &mask, NULL); return 0;