} else {
ao2_unlock(q);
ao2_ref(member, -1);
+ ao2_iterator_destroy(&mem_iter);
return QUEUE_NORMAL;
}
break;
}
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
return result;
if ((slash_pos = strchr(interface, '/')))
if ((slash_pos = strchr(slash_pos + 1, '/')))
*slash_pos = '\0';
-
if (!strcasecmp(interface, sc->dev))
break;
}
int ret = 0;
ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
- queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : F_AO2I_DONTLOCK);
+ queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : AO2_ITERATOR_DONTLOCK);
while ((q = ao2_iterator_next(&queue_iter))) {
ao2_lock(q);
mem_iter = ao2_iterator_init(q->members, 0);
break;
}
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
return ret;
}
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
/* Create a new member */
if (!found) {
}
ao2_ref(cur, -1);
}
+ ao2_iterator_destroy(&mem_iter);
}
/*! \brief Free queue's member list then its string fields */
m->dead = 1;
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
rt_handle_member_record(q, interface,
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
m->dead = 1;
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
rt_handle_member_record(q, interface,
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
ao2_unlock(queues);
ast_config_destroy(member_config);
break;
}
}
+ ao2_iterator_destroy(&mem_iter);
return avl;
}
break;
}
}
+ ao2_iterator_destroy(&queue_iter);
return found;
}
ao2_unlock(qtmp);
ao2_ref(qtmp, -1);
}
+ ao2_iterator_destroy(&queue_iter);
} else {
ao2_lock(q);
time(&member->lastcall);
if (!tmp) {
ao2_ref(cur, -1);
ao2_unlock(qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
goto out;
if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
ao2_ref(cur, -1);
ao2_unlock(qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
free(tmp);
if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
ao2_ref(cur, -1);
ao2_unlock(&qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
free(tmp);
if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
ao2_ref(cur, -1);
ao2_unlock(qe->parent);
+ ao2_iterator_destroy(&memi);
if (use_weight)
ao2_unlock(queues);
free(tmp);
ast_free(tmp);
}
}
+ ao2_iterator_destroy(&memi);
if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
/* Application arguments have higher timeout priority (behaviour for <=1.6) */
mem_iter = ao2_iterator_init(q->members, 0);
while ((mem = ao2_iterator_next(&mem_iter))) {
- if (!strcasecmp(interface, mem->interface))
+ if (!strcasecmp(interface, mem->interface)) {
+ ao2_iterator_destroy(&mem_iter);
return mem;
+ }
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
return NULL;
}
}
value_len += res;
}
+ ao2_iterator_destroy(&mem_iter);
if (value_len && !cur_member) {
if (ast_db_put(pm_family, pm_queue->name, value))
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
return found ? RESULT_SUCCESS : RESULT_FAILURE;
}
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
if (foundinterface) {
return RESULT_SUCCESS;
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
} else if (!strcasecmp(option, "free")) {
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
} else /* must be "count" */
count = q->membercount;
ao2_unlock(q);
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_unref(q);
} else
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_unref(q);
} else
ao2_lock(queues);
use_weight=0;
/* Mark all queues as dead for the moment */
- queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
+ queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
while ((q = ao2_iterator_next(&queue_iter))) {
if (!q->realtime) {
q->dead = 1;
}
}
- queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
+ queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
ao2_lock(queues);
while ((q = ao2_iterator_next(&queue_iter))) {
float sl;
do_print(s, fd, out->str);
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
}
if (!q->head)
do_print(s, fd, " No Callers");
ao2_unlock(q);
queue_unref(q); /* Unref the iterator's reference */
}
+ ao2_iterator_destroy(&queue_iter);
ao2_unlock(queues);
if (!found) {
if (argc == 3)
}
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
return ret;
}
}
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
for (qe = q->head; qe; qe = qe->next) {
if ((now - qe->start) > qlongestholdtime) {
qlongestholdtime = now - qe->start;
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
astman_append(s,
"Event: QueueSummaryComplete\r\n"
"%s"
}
ao2_ref(mem, -1);
}
+ ao2_iterator_destroy(&mem_iter);
/* List Queue Entries */
pos = 1;
for (qe = q->head; qe; qe = qe->next) {
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
astman_append(s,
"Event: QueueStatusComplete\r\n"
tmp = ast_strdup(m->interface);
ao2_ref(m, -1);
queue_unref(q);
+ ao2_iterator_destroy(&mem_iter);
+ ao2_iterator_destroy(&queue_iter);
return tmp;
}
ao2_ref(m, -1);
}
+ ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_unref(q);
}
+ ao2_iterator_destroy(&queue_iter);
return NULL;
}
ao2_unlink(queues, q);
queue_unref(q);
}
+ ao2_iterator_destroy(&q_iter);
ao2_ref(queues, -1);
devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
ast_unload_realtime("queue_members");
console_pvt_unlock(pvt);
unref_pvt(pvt);
}
+ ao2_iterator_destroy(&i);
ast_cli(a->fd, "=============================================================\n\n");
if (++x > a->n && !strncasecmp(pvt->name, a->word, strlen(a->word)))
res = ast_strdup(pvt->name);
unref_pvt(pvt);
- if (res)
+ if (res) {
+ ao2_iterator_destroy(&i);
return res;
+ }
}
+ ao2_iterator_destroy(&i);
}
return NULL;
}
}
unref_pvt(pvt);
}
+ ao2_iterator_destroy(&i);
}
/*!
stop_stream(pvt);
unref_pvt(pvt);
}
+ ao2_iterator_destroy(&i);
}
static int unload_module(void)
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
if (!peer) {
peer = realtime_peer(NULL, &sin);
}
ao2_ref(peercnt, -1);
}
+ ao2_iterator_destroy(&i);
if (a->argc == 4) {
ast_cli(a->fd, "\nNon-CallToken Validation Limit: %d\nNon-CallToken Validated: %d\n", global_maxcallno_nonval, total_nonval_callno_used);
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
return res;
}
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
return res;
}
user->contexts ? user->contexts->context : DEFAULT_CONTEXT,
user->ha ? "Yes" : "No", pstr);
}
+ ao2_iterator_destroy(&i);
if (havepattern)
regfree(®exbuf);
peer->encmethods ? "(E)" : " ", status, term);
total_peers++;
}
+ ao2_iterator_destroy(&i);
if (!s)
ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
}
peer_unref(p);
}
+ ao2_iterator_destroy(&i);
}
return res;
astman_append(s, "Status: %s\r\n\r\n", status);
peer_count++;
}
+ ao2_iterator_destroy(&i);
astman_append(s, "Event: PeerlistComplete\r\n%sListItems: %d\r\n\r\n", idtext, peer_count);
return RESULT_SUCCESS;
}
user_unref(user);
}
+ ao2_iterator_destroy(&i);
user = best;
if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
user = realtime_user(iaxs[callno]->username, sin);
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
if (!peer) {
/* We checked our list and didn't find one. It's unlikely, but possible,
that we're trying to authenticate *to* a realtime peer */
}
user_unref(user);
}
+ ao2_iterator_destroy(&i);
}
/* Prune peers who still are supposed to be deleted */
}
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
}
static void set_config_destroy(void)
iax2_poke_peer(peer, 0);
peer_unref(peer);
}
+ ao2_iterator_destroy(&i);
}
static int reload_config(void)
{
ast_cli(a->fd, FORMAT, "* Peer name", "In use", "Limit");
i = ao2_iterator_init(peers, 0);
-
while ((peer = ao2_t_iterator_next(&i, "iterate thru peer table"))) {
ao2_lock(peer);
if (peer->call_limit)
ao2_unlock(peer);
unref_peer(peer, "toss iterator pointer");
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
#undef FORMAT
ao2_unlock(user);
unref_peer(user, "sip show users");
}
+ ao2_iterator_destroy(&user_iter);
if (havepattern)
regfree(®exbuf);
peerarray[total_peers++] = peer;
ao2_unlock(peer);
}
+ ao2_iterator_destroy(&i);
qsort(peerarray, total_peers, sizeof(struct sip_peer *), peercomparefunc);
ao2_unlock(pi);
unref_peer(pi, "toss iterator peer ptr");
}
+ ao2_iterator_destroy(&i);
if (pruned) {
ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, 0,
"initiating callback to remove marked peers");
ao2_unlock(user);
unref_peer(user, "complete sip user");
}
+ ao2_iterator_destroy(&user_iter);
return result;
}
/*! \brief Support routine for 'sip show user' CLI */
}
i = ao2_iterator_init(dialogs, 0);
-
while ((cur = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
sip_pvt_lock(cur);
if (!strncasecmp(word, cur->callid, wordlen) && ++which > state) {
sip_pvt_unlock(cur);
dialog_unref(cur, "drop ref in iterator loop");
}
+ ao2_iterator_destroy(&i);
return c;
}
break;
}
}
+ ao2_iterator_destroy(&i);
return result;
}
char *result = NULL;
int wordlen = strlen(word);
int which = 0;
- struct ao2_iterator i;
- struct sip_peer *peer;
-
- i = ao2_iterator_init(peers, 0);
- while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
- if (!strncasecmp(word, peer->name, wordlen) &&
- (!flags2 || ast_test_flag(&peer->flags[1], flags2)) &&
- ++which > state && peer->expire > 0)
- result = ast_strdup(peer->name);
- if (result) {
- unref_peer(peer, "toss iterator peer ptr before break");
- break;
- }
- unref_peer(peer, "toss iterator peer ptr");
+ struct ao2_iterator i;
+ struct sip_peer *peer;
+
+ i = ao2_iterator_init(peers, 0);
+ while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
+ if (!strncasecmp(word, peer->name, wordlen) &&
+ (!flags2 || ast_test_flag(&peer->flags[1], flags2)) &&
+ ++which > state && peer->expire > 0)
+ result = ast_strdup(peer->name);
+ if (result) {
+ unref_peer(peer, "toss iterator peer ptr before break");
+ break;
+ }
+ unref_peer(peer, "toss iterator peer ptr");
}
+ ao2_iterator_destroy(&i);
return result;
}
len = strlen(a->argv[3]);
i = ao2_iterator_init(dialogs, 0);
-
while ((cur = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
sip_pvt_lock(cur);
ao2_t_ref(cur, -1, "toss dialog ptr set by iterator_next");
}
+ ao2_iterator_destroy(&i);
if (!found)
ast_cli(a->fd, "No such SIP Call ID starting with '%s'\n", a->argv[3]);
sip_pvt_unlock(cur);
ao2_t_ref(cur, -1, "toss dialog ptr from iterator_next");
}
+ ao2_iterator_destroy(&i);
if (!found)
ast_cli(a->fd, "No such SIP Call ID starting with '%s'\n", a->argv[3]);
ignored (or generate errors)
*/
i = ao2_iterator_init(dialogs, 0);
-
while ((p_old = ao2_t_iterator_next(&i, "iterate thru dialogs"))) {
if (p_old == p) {
ao2_t_ref(p_old, -1, "toss dialog ptr from iterator_next before continue");
sip_pvt_unlock(p_old);
ao2_t_ref(p_old, -1, "toss dialog ptr from iterator_next");
}
+ ao2_iterator_destroy(&i);
}
if (!p->expiry)
p->needdestroy = 1;
struct ao2_iterator i;
struct sip_peer *peer;
- i = ao2_iterator_init(peers, 0);
-
if (!speerobjs) /* No peers, just give up */
return;
+ i = ao2_iterator_init(peers, 0);
while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) {
ao2_lock(peer);
ms += 100;
ao2_unlock(peer);
unref_peer(peer, "toss iterator peer ptr");
}
+ ao2_iterator_destroy(&i);
}
/*! \brief Send all known registrations */
ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
ao2_t_ref(p, -1, "toss dialog ptr from iterator_next");
}
+ ao2_iterator_destroy(&i);
ast_mutex_lock(&monlock);
if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
dialog_unlink_all(p, TRUE, TRUE);
ao2_t_ref(p, -1, "throw away iterator result");
}
+ ao2_iterator_destroy(&i);
/* Free memory for local network address mask */
ast_free_ha(localaddr);
}
ao2_ref(entry, -1);
}
+ ao2_iterator_destroy(&i);
return res;
}
... do something on o ...
ao2_ref(o, -1);
}
+
+ ao2_iterator_destroy(&i);
\endcode
The difference with the callback is that the control
/*! \brief
*
*
- * When we need to walk through a container, we use
+ * When we need to walk through a container, we use an
* ao2_iterator to keep track of the current position.
*
* Because the navigation is typically done without holding the
- * lock on the container across the loop,
- * objects can be inserted or deleted or moved
- * while we work. As a consequence, there is no guarantee that
- * the we manage to touch all the elements on the list, or it
- * is possible that we touch the same object multiple times.
+ * lock on the container across the loop, objects can be inserted or deleted
+ * or moved while we work. As a consequence, there is no guarantee that
+ * we manage to touch all the elements in the container, and it is possible
+ * that we touch the same object multiple times.
+ *
* However, within the current hash table container, the following is true:
* - It is not possible to miss an object in the container while iterating
* unless it gets added after the iteration begins and is added to a bucket
* ao2_iterator_next() has its refcount incremented,
* and the reference must be explicitly released when done with it.
*
+ * In addition, ao2_iterator_init() will hold a reference to the container
+ * being iterated, which will be freed when ao2_iterator_destroy() is called
+ * to free up the resources used by the iterator (if any).
+ *
* Example:
*
* \code
* ao2_ref(o, -1);
* }
*
+ * ao2_iterator_destroy(&i);
+ *
* \endcode
*
*/
/*! \brief
- * The Astobj2 iterator
+ * The astobj2 iterator
*
* \note You are not supposed to know the internals of an iterator!
* We would like the iterator to be opaque, unfortunately
* - a bucket number;
* - the object_id, which is also the container version number
* when the object was inserted. This identifies the object
- * univoquely, however reaching the desired object requires
+ * uniquely, however reaching the desired object requires
* scanning a list.
* - a pointer, and a container version when we saved the pointer.
* If the container has not changed its version number, then we
* can safely follow the pointer to reach the object in constant time.
*
* Details are in the implementation of ao2_iterator_next()
- * A freshly-initialized iterator has bucket=0, version = 0.
+ * A freshly-initialized iterator has bucket=0, version=0.
*/
struct ao2_iterator {
/*! the container */
struct ao2_container *c;
/*! operation flags */
int flags;
-#define F_AO2I_DONTLOCK 1 /*!< don't lock when iterating */
/*! current bucket */
int bucket;
/*! container version */
unsigned int version;
};
-/* the flags field can contain F_AO2I_DONTLOCK, which will prevent
- ao2_iterator_next calls from locking the container while it
- searches for the next pointer */
+/*! Flags that can be passed to ao2_iterator_init() to modify the behavior
+ * of the iterator.
+ */
+enum ao2_iterator_flags {
+ /*! Prevents ao2_iterator_next() from locking the container
+ * while retrieving the next object from it.
+ */
+ AO2_ITERATOR_DONTLOCK = (1 << 0),
+};
+/*!
+ * \brief Create an iterator for a container
+ *
+ * \param c the container
+ * \param flags one or more flags from ao2_iterator_flags
+ *
+ * \retval the constructed iterator
+ *
+ * \note This function does \b not take a pointer to an iterator;
+ * rather, it returns an iterator structure that should be
+ * assigned to (overwriting) an existing iterator structure
+ * allocated on the stack or on the heap.
+ *
+ * This function will take a reference on the container being iterated.
+ *
+ */
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags);
+/*!
+ * \brief Destroy a container iterator
+ *
+ * \param i the iterator to destroy
+ *
+ * \retval none
+ *
+ * This function will release the container reference held by the iterator
+ * and any other resources it may be holding.
+ *
+ */
+void ao2_iterator_destroy(struct ao2_iterator *i);
+
#ifdef REF_DEBUG
#define ao2_t_iterator_next(arg1, arg2) _ao2_iterator_next_debug((arg1), (arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
.c = c,
.flags = flags
};
+
+ ao2_ref(c, +1);
return a;
}
+/*!
+ * destroy an iterator
+ */
+void ao2_iterator_destroy(struct ao2_iterator *i)
+{
+ ao2_ref(i->c, -1);
+ i->c = NULL;
+}
+
/*
* move to the next element in the container.
*/
if (INTERNAL_OBJ(a->c) == NULL)
return NULL;
- if (!(a->flags & F_AO2I_DONTLOCK))
+ if (!(a->flags & AO2_ITERATOR_DONTLOCK))
ao2_lock(a->c);
/* optimization. If the container is unchanged and
_ao2_ref_debug(ret, 1, tag, file, line, funcname);
}
- if (!(a->flags & F_AO2I_DONTLOCK))
+ if (!(a->flags & AO2_ITERATOR_DONTLOCK))
ao2_unlock(a->c);
return ret;
_ao2_ref(ret, 1);
}
- if (!(a->flags & F_AO2I_DONTLOCK))
+ if (!(a->flags & AO2_ITERATOR_DONTLOCK))
ao2_unlock(a->c);
return ret;
return CLI_SHOWUSAGE;
i = ao2_iterator_init(mohclasses, 0);
-
for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
int x;
ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
}
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
}
return CLI_SHOWUSAGE;
i = ao2_iterator_init(mohclasses, 0);
-
for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
ast_cli(a->fd, "Class: %s\n", class->name);
ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format));
}
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
}
break;
}
}
+ ao2_iterator_destroy(&aoi);
if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
ret = ast_strdup("all");
}
ast_mutex_unlock(¤t->lock);
ao2_ref(current, -1);
}
+ ao2_iterator_destroy(&aoi2);
} else {
/* Should only ever be one of these */
struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
ast_cli(a->fd, " Pooled: No\n Connected: %s\n", current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
ao2_ref(current, -1);
}
+ ao2_iterator_destroy(&aoi2);
}
ast_cli(a->fd, "\n");
}
ao2_ref(class, -1);
}
+ ao2_iterator_destroy(&aoi);
return CLI_SUCCESS;
}
class->delme = 1;
ao2_ref(class, -1);
}
+ ao2_iterator_destroy(&aoi);
load_odbc_config();
* b) the object has already been destroyed.
*/
}
+ ao2_iterator_destroy(&aoi2);
ao2_unlink(class_container, class); /* unlink C-ref from container (reference handled implicitly) */
/* At this point, either
* a) there's an outstanding O-ref, which holds an outstanding C-ref, or
}
ao2_ref(class, -1); /* C-ref-- (by iterator) */
}
+ ao2_iterator_destroy(&aoi);
/* Empty the cache; it will get rebuilt the next time the tables are needed. */
AST_RWLIST_WRLOCK(&odbc_tables);
ao2_unlink(users, user);
user = unref_user(user);
}
+ ao2_iterator_destroy(&i);
}
/*! \brief Build and return a user structure based on gathered config data */
ao2_unlink(http_routes, route);
route = unref_route(route);
}
+ ao2_iterator_destroy(&i);
}
/*! \brief Delete all phone profiles, freeing their memory */
ao2_unlink(profiles, profile);
profile = unref_profile(profile);
}
+ ao2_iterator_destroy(&i);
}
/*! \brief A dialplan function that can be used to print a string for each phoneprov user */
ast_build_string(&buf, &len, "%s", expand_buf);
user = unref_user(user);
}
+ ao2_iterator_destroy(&i);
return 0;
}
ast_cli(a->fd, FORMAT, route->uri, route->file->template);
route = unref_route(route);
}
+ ao2_iterator_destroy(&i);
ast_cli(a->fd, "\nDynamic routes\n\n");
ast_cli(a->fd, FORMAT, "Relative URI", "Template");
ast_cli(a->fd, FORMAT, route->uri, route->file->template);
route = unref_route(route);
}
+ ao2_iterator_destroy(&i);
return CLI_SUCCESS;
}