[asterisk-commits] snuffy: branch snuffy/ao2_jabber r141154 - in /team/snuffy/ao2_jabber: includ...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Sep 5 06:57:23 CDT 2008
Author: snuffy
Date: Fri Sep 5 06:57:23 2008
New Revision: 141154
URL: http://svn.digium.com/view/asterisk?view=rev&rev=141154
Log:
Compiles at least res_jabber. Lots o work to do
Modified:
team/snuffy/ao2_jabber/include/asterisk/astobj2.h
team/snuffy/ao2_jabber/include/asterisk/jabber.h
team/snuffy/ao2_jabber/res/res_jabber.c
Modified: team/snuffy/ao2_jabber/include/asterisk/astobj2.h
URL: http://svn.digium.com/view/asterisk/team/snuffy/ao2_jabber/include/asterisk/astobj2.h?view=diff&rev=141154&r1=141153&r2=141154
==============================================================================
--- team/snuffy/ao2_jabber/include/asterisk/astobj2.h (original)
+++ team/snuffy/ao2_jabber/include/asterisk/astobj2.h Fri Sep 5 06:57:23 2008
@@ -496,7 +496,7 @@
Operations on container include:
- - c = \b ao2_container_alloc(size, cmp_fn, hash_fn)
+ - c = \b ao2_container_alloc(size, hash_fn, cmp_fn)
allocate a container with desired size and default compare
and hash function
-The compare function returns an int, which
Modified: team/snuffy/ao2_jabber/include/asterisk/jabber.h
URL: http://svn.digium.com/view/asterisk/team/snuffy/ao2_jabber/include/asterisk/jabber.h?view=diff&rev=141154&r1=141153&r2=141154
==============================================================================
--- team/snuffy/ao2_jabber/include/asterisk/jabber.h (original)
+++ team/snuffy/ao2_jabber/include/asterisk/jabber.h Fri Sep 5 06:57:23 2008
@@ -122,23 +122,18 @@
};
struct aji_buddy {
- ASTOBJ_COMPONENTS_FULL(struct aji_buddy, AJI_MAX_JIDLEN, 1);
+ char name[AJI_MAX_JIDLEN];
char channel[160];
struct aji_resource *resources;
enum aji_btype btype;
struct ast_flags flags;
+ char needdestroy;
+ int mark;
};
-struct aji_buddy_container {
- ASTOBJ_CONTAINER_COMPONENTS(struct aji_buddy);
-};
-
-struct aji_transport_container {
- ASTOBJ_CONTAINER_COMPONENTS(struct aji_transport);
-};
struct aji_client {
- ASTOBJ_COMPONENTS(struct aji_client);
+ char name[80];
char password[160];
char user[AJI_MAX_JIDLEN];
char serverhost[AJI_MAX_RESJIDLEN];
@@ -169,16 +164,13 @@
int authorized;
struct ast_flags flags;
int component; /* 0 client, 1 component */
- struct aji_buddy_container buddies;
+ struct ao2_container *buddies;
AST_LIST_HEAD(messages,aji_message) messages;
void *jingle;
pthread_t thread;
int priority;
enum ikshowtype status;
-};
-
-struct aji_client_container{
- ASTOBJ_CONTAINER_COMPONENTS(struct aji_client);
+ int mark;
};
/* !Send XML stanza over the established XMPP connection */
@@ -196,6 +188,6 @@
/*! Join existing Chat session */
int ast_aji_join_chat(struct aji_client *client,char *room);
struct aji_client *ast_aji_get_client(const char *name);
-struct aji_client_container *ast_aji_get_clients(void);
+struct ao2_container *ast_aji_get_clients(void);
#endif
Modified: team/snuffy/ao2_jabber/res/res_jabber.c
URL: http://svn.digium.com/view/asterisk/team/snuffy/ao2_jabber/res/res_jabber.c?view=diff&rev=141154&r1=141153&r2=141154
==============================================================================
--- team/snuffy/ao2_jabber/res/res_jabber.c (original)
+++ team/snuffy/ao2_jabber/res/res_jabber.c Fri Sep 5 06:57:23 2008
@@ -55,7 +55,8 @@
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/module.h"
-#include "asterisk/astobj.h"
+/*#include "asterisk/astobj.h"*/
+#include "asterisk/astobj2.h"
#include "asterisk/astdb.h"
#include "asterisk/manager.h"
@@ -71,9 +72,16 @@
#define TRUE 1
#endif
+#ifdef LOW_MEMORY
+static int hash_buddy_size = 20;
+static int hash_client_size = 20;
+#else
+static int hash_buddy_size = 256;
+static int hash_client_size = 256;
+#endif
/*-- Forward declarations */
-static void aji_buddy_destroy(struct aji_buddy *obj);
-static void aji_client_destroy(struct aji_client *obj);
+static void aji_buddy_destroy(void *obj);
+static void aji_client_destroy(void *obj);
static int aji_send_exec(struct ast_channel *chan, void *data);
static int aji_status_exec(struct ast_channel *chan, void *data);
static int aji_is_secure(struct aji_client *client);
@@ -134,55 +142,134 @@
static char *app_ajisend = "JabberSend";
-static char *ajisend_synopsis = "JabberSend(Jabber,JID,Message)";
+static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
static char *ajisend_descrip =
-"JabberSend(Jabber,JID,Message)\n"
-" Jabber - Client or transport Asterisk uses to connect to Jabber\n"
-" JID - XMPP/Jabber JID (Name) of recipient\n"
-" Message - Message to be sent to the buddy\n";
+"JabberSend(Jabber,ScreenName,Message)\n"
+" Jabber - Client or transport Asterisk uses to connect to Jabber\n"
+" ScreenName - User Name to message.\n"
+" Message - Message to be sent to the buddy\n";
static char *app_ajistatus = "JabberStatus";
-static char *ajistatus_synopsis = "JabberStatus(Jabber,JID,Variable)";
+static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
static char *ajistatus_descrip =
-"JabberStatus(Jabber,JID,Variable)\n"
-" Jabber - Client or transport Asterisk uses to connect to Jabber\n"
-" JID - User Name to retrieve status from.\n"
+"JabberStatus(Jabber,ScreenName,Variable)\n"
+" Jabber - Client or transport Asterisk uses to connect to Jabber\n"
+" ScreenName - User Name to retrieve status from.\n"
" Variable - Variable to store presence in will be 1-6.\n"
-" In order, 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline\n"
-" If not in roster variable will be set to 7\n\n"
-"Note: This application is deprecated. Please use the JABBER_STATUS() function instead.\n";
-
-struct aji_client_container clients;
+" In order, Online, Chatty, Away, XAway, DND, Offline\n"
+" If not in roster variable will = 7\n";
+
+struct ao2_container *clients;
struct aji_capabilities *capabilities = NULL;
/*! \brief Global flags, initialized to default values */
static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
+
+static struct aji_buddy *buddy_ref(struct aji_buddy *b, char *tag)
+{
+ if (b) {
+ ao2_ref(b, 1);
+ } else {
+ ast_log(LOG_ERROR, "Attempt to ref a NULL pointer\n");
+ }
+
+ return b;
+}
+
+static void buddy_unref(struct aji_buddy *b, char *tag)
+{
+ if (b) {
+ ao2_ref(b, -1);
+ } else {
+ ast_log(LOG_ERROR, "Attempt to unref a NULL pointer\n");
+ }
+}
+
+static struct aji_client *client_ref(struct aji_client *c, char *tag)
+{
+ if (c) {
+ ao2_ref(c, 1);
+ } else {
+ ast_log(LOG_ERROR, "Attempt to ref a NULL pointer\n");
+ }
+
+ return c;
+}
+
+static void client_unref(struct aji_client *c, char *tag)
+{
+ if (c) {
+ ao2_ref(c, -1);
+ } else {
+ ast_log(LOG_ERROR, "Attempt to unref a NULL pointer\n");
+ }
+}
+
+static int client_cmp_cb(void *obj, void *arg, int flags)
+{
+ struct aji_client *client = obj, *client2 = arg;
+
+ return !strcasecmp(client->name, client2->name) ? CMP_MATCH : 0;
+}
+
+static int buddy_cmp_cb(void *obj, void *arg, int flags)
+{
+ struct aji_buddy *buddy = obj, *buddy2 = arg;
+
+ return !strcasecmp(buddy->name, buddy2->name) ? CMP_MATCH : 0;
+}
+
+static int buddy_hash_cb(const void *obj, const int flags)
+{
+ const struct aji_buddy *buddy = obj;
+
+ return ast_str_hash(buddy->name);
+}
+
+static int client_hash_cb(const void *obj, const int flags)
+{
+ const struct aji_client *client = obj;
+
+ return ast_str_hash(client->name);
+}
/*!
* \brief Deletes the aji_client data structure.
* \param obj aji_client The structure we will delete.
* \return void.
*/
-static void aji_client_destroy(struct aji_client *obj)
-{
+static void aji_client_destroy(void *obj)
+{
+ struct aji_client *c = obj;
struct aji_message *tmp;
- ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
- ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
- iks_filter_delete(obj->f);
- iks_parser_delete(obj->p);
- iks_stack_delete(obj->stack);
- AST_LIST_LOCK(&obj->messages);
- while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
+ struct aji_buddy *b;
+ struct ao2_iterator iter;
+
+ iter = ao2_iterator_init(c->buddies, 0);
+
+ while( (b = ao2_t_iterator_next(&iter, "iterate thru buddies")) ) {
+ ao2_t_unlink(c->buddies, b, "Remove buddy from list");
+ buddy_unref(b, "unref buddy");
+ }
+
+ iks_filter_delete(c->f);
+ iks_parser_delete(c->p);
+ iks_stack_delete(c->stack);
+ AST_LIST_LOCK(&c->messages);
+ while ((tmp = AST_LIST_REMOVE_HEAD(&c->messages, list))) {
if (tmp->from)
ast_free(tmp->from);
if (tmp->message)
ast_free(tmp->message);
}
- AST_LIST_HEAD_DESTROY(&obj->messages);
- ast_free(obj);
+ AST_LIST_HEAD_DESTROY(&c->messages);
+
+ ao2_lock(clients); /* required locking for removal? */
+ ao2_t_unlink(clients,obj,"Remove client from list");
+ ao2_unlock(clients);
}
/*!
@@ -190,17 +277,18 @@
* \param obj aji_buddy The structure we will delete.
* \return void.
*/
-static void aji_buddy_destroy(struct aji_buddy *obj)
-{
+static void aji_buddy_destroy(void *obj)
+{
+ struct aji_buddy *b = obj;
struct aji_resource *tmp;
- while ((tmp = obj->resources)) {
- obj->resources = obj->resources->next;
+ while ((tmp = b->resources)) {
+ b->resources = b->resources->next;
ast_free(tmp->description);
ast_free(tmp);
}
- ast_free(obj);
+ ast_free(b);
}
/*!
@@ -345,6 +433,7 @@
{
struct aji_client *client = NULL;
struct aji_buddy *buddy = NULL;
+ struct aji_buddy tmp_buddy;
struct aji_resource *r = NULL;
char *s = NULL;
int stat = 7;
@@ -364,7 +453,7 @@
ast_log(LOG_WARNING, "JabberStatus is deprecated. Please use the JABBER_STATUS dialplan function in the future.\n");
if (!data) {
- ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
+ ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<screenname>[/<resource>],<varname>\n");
return 0;
}
s = ast_strdupa(data);
@@ -377,22 +466,31 @@
AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
+/* I NEED A FUNCTION */
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
- buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
+
+ ast_copy_string(tmp_buddy.name, jid.screenname, sizeof(tmp_buddy.name));
+ buddy = ao2_t_find(client->buddies, &tmp_buddy, OBJ_POINTER, "Find buddy");
+
if (!buddy) {
ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
return -1;
}
+
r = aji_find_resource(buddy, jid.resource);
+
if (!r && buddy->resources)
r = buddy->resources;
if (!r)
ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
else
stat = r->status;
+
+ buddy_unref(buddy,"stat_exec");
+/* END I NEED A FUNCTION */
snprintf(status, sizeof(status), "%d", stat);
pbx_builtin_setvar_helper(chan, args.variable, status);
return 0;
@@ -402,6 +500,7 @@
{
struct aji_client *client = NULL;
struct aji_buddy *buddy = NULL;
+ struct aji_buddy tmp_buddy;
struct aji_resource *r = NULL;
int stat = 7;
AST_DECLARE_APP_ARGS(args,
@@ -414,23 +513,25 @@
);
if (!data) {
- ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
+ ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<screenname>[/<resource>])\n");
return 0;
}
AST_STANDARD_APP_ARGS(args, data);
if (args.argc != 2) {
- ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
+ ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments.\n");
return -1;
}
AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
+/* I NEED A FUNCTION */
if (!(client = ast_aji_get_client(args.sender))) {
ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
return -1;
}
- buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
+ ast_copy_string(tmp_buddy.name, jid.screenname, sizeof(tmp_buddy.name));
+ buddy = ao2_t_find(client->buddies, &tmp_buddy, OBJ_POINTER, "Find buddy");
if (!buddy) {
ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
return -1;
@@ -442,6 +543,8 @@
ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
else
stat = r->status;
+ buddy_unref(buddy,"stat_read");
+/* END I NEED A FUNCTION */
snprintf(buf, buflen, "%d", stat);
return 0;
}
@@ -452,11 +555,8 @@
.syntax = "JABBER_STATUS(<sender>,<buddy>[/<resource>])",
.read = acf_jabberstatus_read,
.desc =
-"Retrieves the numeric status associated with the specified buddy (jid). If the\n"
-"buddy does not exist in the buddylist, returns 7.\n"
-"Status will be 1-7.\n"
-" 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline\n"
-" If not in roster variable will be set to 7\n\n",
+"Retrieves the numeric status associated with the specified buddy. If the\n"
+"buddy does not exist in the buddylist, returns 7.\n",
};
/*!
@@ -776,7 +876,8 @@
*/
static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
+ client_ref(client,"log_hook");
if (!ast_strlen_zero(xmpp))
manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
@@ -786,15 +887,14 @@
ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
else {
if( strlen(xmpp) == 1) {
- if(option_debug > 2 && xmpp[0] == ' ') {
- ast_verbose("\nJABBER: Keep alive packet\n");
- }
+ if(option_debug > 2 && xmpp[0] == ' ')
+ ast_verbose("\nJABBER: Keep alive packet\n");
} else
ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
}
}
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client,"log_hook");
}
/*!
@@ -857,19 +957,21 @@
*/
static int aji_act_hook(void *data, int type, iks *node)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
ikspak *pak = NULL;
iks *auth = NULL;
int features = 0;
+ client_ref(client,"act_hook");
+
if(!node) {
ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "act_hook_packet");
return IKS_HOOK;
}
if (client->state == AJI_DISCONNECTING) {
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "act_hook_disc");
return IKS_HOOK;
}
@@ -881,12 +983,12 @@
if (client->usetls && !aji_is_secure(client)) {
#ifndef HAVE_OPENSSL
ast_log(LOG_ERROR, "OpenSSL not installed. You need to install OpenSSL on this system, or disable the TLS option in your configuration file\n");
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client,"act_hook_no_openssl_tls");
return IKS_HOOK;
#else
if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
ast_log(LOG_ERROR, "Could not start TLS\n");
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client,"act_hook_openssl_tls");
return IKS_HOOK;
}
#endif
@@ -954,7 +1056,7 @@
ret = aji_start_sasl(client, features, client->jid->user, client->password);
if (ret != IKS_OK) {
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "act_hook_not_ok");
return IKS_HOOK;
}
break;
@@ -969,12 +1071,12 @@
break;
case IKS_NODE_ERROR:
ast_log(LOG_ERROR, "JABBER: Node Error\n");
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "act_hook_node_error");
return IKS_HOOK;
break;
case IKS_NODE_STOP:
ast_log(LOG_WARNING, "JABBER: Disconnected\n");
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "act_hook_discon_error");
return IKS_HOOK;
break;
}
@@ -1007,12 +1109,12 @@
case IKS_NODE_ERROR:
ast_log(LOG_ERROR, "JABBER: Node Error\n");
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "act_hook_node_error");
return IKS_HOOK;
case IKS_NODE_STOP:
ast_log(LOG_WARNING, "JABBER: Disconnected\n");
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "act_hook_discon_error");
return IKS_HOOK;
}
}
@@ -1047,20 +1149,21 @@
if (node)
iks_delete(node);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "end_act_hook");
return IKS_OK;
}
/*!
- * \brief Unknown
+ * \brief Uknown
* \param data void
* \param pak ikspak
* \return IKS_FILTER_EAT.
*/
static int aji_register_approve_handler(void *data, ikspak *pak)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
iks *iq = NULL, *presence = NULL, *x = NULL;
+ client_ref(client,"arpv_hand");
iq = iks_new("iq");
presence = iks_new("presence");
x = iks_new("x");
@@ -1090,29 +1193,29 @@
iks_delete(presence);
iks_delete(x);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "aprv_hand");
return IKS_FILTER_EAT;
}
/*!
- * \brief register handler for incoming querys (IQ's)
+ * \brief register query
* \param data incoming aji_client request
* \param pak ikspak
* \return IKS_FILTER_EAT.
*/
static int aji_register_query_handler(void *data, ikspak *pak)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
struct aji_buddy *buddy = NULL;
+ struct aji_buddy tmp_buddy;
char *node = NULL;
- iks *iq = NULL, *query = NULL;
-
- client = (struct aji_client *) data;
-
- buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+
+ client_ref(client,"qry_hand");
+ ast_copy_string(tmp_buddy.name, pak->from->partial,sizeof(tmp_buddy.name));
+ buddy = ao2_t_find(client->buddies, &tmp_buddy, OBJ_POINTER, "Find Buddy");
if (!buddy) {
- iks *error = NULL, *notacceptable = NULL;
-
- ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
+ iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
+
+ ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
iq = iks_new("iq");
query = iks_new("query");
error = iks_new("error");
@@ -1134,10 +1237,12 @@
ast_log(LOG_ERROR, "Out of memory.\n");
}
+ iks_delete(iq);
+ iks_delete(query);
iks_delete(error);
iks_delete(notacceptable);
} else if (!(node = iks_find_attrib(pak->query, "node"))) {
- iks *instructions = NULL;
+ iks *iq = NULL, *query = NULL, *instructions = NULL;
char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
iq = iks_new("iq");
query = iks_new("query");
@@ -1156,11 +1261,12 @@
ast_log(LOG_ERROR, "Out of memory.\n");
}
+ iks_delete(iq);
+ iks_delete(query);
iks_delete(instructions);
}
- iks_delete(iq);
- iks_delete(query);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ buddy_unref(buddy, "qry_hand");
+ client_unref(client, "qry_hand");
return IKS_FILTER_EAT;
}
@@ -1172,8 +1278,10 @@
*/
static int aji_ditems_handler(void *data, ikspak *pak)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
char *node = NULL;
+
+ client_ref(client,"itm_hand");
if (!(node = iks_find_attrib(pak->query, "node"))) {
iks *iq = NULL, *query = NULL, *item = NULL;
@@ -1255,7 +1363,7 @@
iks_delete(feature);
}
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "itm_hand");
return IKS_FILTER_EAT;
}
@@ -1267,15 +1375,20 @@
*/
static int aji_client_info_handler(void *data, ikspak *pak)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
struct aji_resource *resource = NULL;
- struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
-
+ struct aji_buddy *buddy = NULL;
+ struct aji_buddy tmp_buddy;
+
+ client_ref(client, "info_hand");
+ ast_copy_string(tmp_buddy.name, pak->from->partial, sizeof(tmp_buddy.name));
+ buddy = ao2_t_find(client->buddies, &tmp_buddy, OBJ_POINTER, "Find buddy");
resource = aji_find_resource(buddy, pak->from->resource);
+
if (pak->subtype == IKS_TYPE_RESULT) {
if (!resource) {
- ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
+ client_unref(client, "info_hand");
return IKS_FILTER_EAT;
}
if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
@@ -1316,7 +1429,8 @@
} else if (pak->subtype == IKS_TYPE_ERROR) {
ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
}
- ASTOBJ_UNREF(client, aji_client_destroy);
+ buddy_unref(buddy,"info_hand");
+ client_unref(client, "info_hand");
return IKS_FILTER_EAT;
}
/*!
@@ -1327,20 +1441,28 @@
*/
static int aji_dinfo_handler(void *data, ikspak *pak)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
+ struct aji_resource *resource = NULL;
+ struct aji_buddy *buddy = NULL;
+ struct aji_buddy tmp_buddy;
char *node = NULL;
- struct aji_resource *resource = NULL;
- struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
-
+
+ client_ref(client, "dinfo_hand");
+ ast_copy_string(tmp_buddy.name, pak->from->partial, sizeof(tmp_buddy.name));
+ buddy = ao2_t_find(client->buddies, &tmp_buddy, OBJ_POINTER, "Find buddy");
resource = aji_find_resource(buddy, pak->from->resource);
+
if (pak->subtype == IKS_TYPE_ERROR) {
ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
+ buddy_unref(buddy, "dinfo_hand");
+ client_unref(client, "dinfo_hand");
return IKS_FILTER_EAT;
}
if (pak->subtype == IKS_TYPE_RESULT) {
if (!resource) {
ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ buddy_unref(buddy, "dinfo_hand");
+ client_unref(client, "dinfo_hand");
return IKS_FILTER_EAT;
}
if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
@@ -1456,7 +1578,8 @@
iks_delete(feature);
}
- ASTOBJ_UNREF(client, aji_client_destroy);
+ buddy_unref(buddy, "dinfo_hand");
+ client_unref(client, "dinfo_hand");
return IKS_FILTER_EAT;
}
@@ -1519,14 +1642,16 @@
static void aji_handle_presence(struct aji_client *client, ikspak *pak)
{
int status, priority;
- struct aji_buddy *buddy;
+ struct aji_buddy tmp_buddy, *buddy;
struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
char *ver, *node, *descrip, *type;
if(client->state != AJI_CONNECTED)
aji_create_buddy(pak->from->partial, client);
- buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+ ast_copy_string(tmp_buddy.name, pak->from->partial, sizeof(tmp_buddy.name));
+ buddy = ao2_t_find(client->buddies, &tmp_buddy, OBJ_POINTER, "Find Buddy");
+
if (!buddy && pak->from->partial) {
/* allow our jid to be used to log in with another resource */
if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
@@ -1535,16 +1660,19 @@
ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
return;
}
+
type = iks_find_attrib(pak->x, "type");
+
if(client->component && type &&!strcasecmp("probe", type)) {
aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
ast_verbose("what i was looking for \n");
}
- ASTOBJ_WRLOCK(buddy);
+
status = (pak->show) ? pak->show : 6;
priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
tmp = buddy->resources;
descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
+ ao2_lock(buddy);
while (tmp && pak->from->resource) {
if (!strcasecmp(tmp->resource, pak->from->resource)) {
@@ -1653,8 +1781,8 @@
buddy->resources = found;
}
- ASTOBJ_UNLOCK(buddy);
- ASTOBJ_UNREF(buddy, aji_buddy_destroy);
+ ao2_unlock(buddy);
+ buddy_unref(buddy, "hld_pres");
node = iks_find_attrib(iks_find(pak->x, "c"), "node");
ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
@@ -1696,35 +1824,35 @@
}
switch (pak->subtype) {
case IKS_TYPE_AVAILABLE:
- ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
+ ast_verb(5, "JABBER: I am available ^_* %i\n", pak->subtype);
break;
case IKS_TYPE_UNAVAILABLE:
- ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
+ ast_verb(5, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
break;
default:
- ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
+ ast_verb(5, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
}
switch (pak->show) {
case IKS_SHOW_UNAVAILABLE:
- ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
+ ast_verb(5, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
case IKS_SHOW_AVAILABLE:
- ast_debug(3, "JABBER: type is available\n");
+ ast_verb(5, "JABBER: type is available\n");
break;
case IKS_SHOW_CHAT:
- ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
+ ast_verb(5, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
case IKS_SHOW_AWAY:
- ast_debug(3, "JABBER: type is away\n");
+ ast_verb(5, "JABBER: type is away\n");
break;
case IKS_SHOW_XA:
- ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
+ ast_verb(5, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
case IKS_SHOW_DND:
- ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
+ ast_verb(5, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
break;
default:
- ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
+ ast_verb(5, "JABBER: Kinky! how did that happen %i\n", pak->show);
}
}
@@ -1738,6 +1866,7 @@
{
iks *presence = NULL, *status = NULL;
struct aji_buddy* buddy = NULL;
+ struct aji_buddy tmp_buddy;
switch (pak->subtype) {
case IKS_TYPE_SUBSCRIBE:
@@ -1761,14 +1890,15 @@
if (client->component)
aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
case IKS_TYPE_SUBSCRIBED:
- buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+ ast_copy_string(tmp_buddy.name, pak->from->partial, sizeof(tmp_buddy.name));
+ buddy = ao2_t_find(client->buddies, &tmp_buddy, OBJ_POINTER, "Find buddy");
if (!buddy && pak->from->partial) {
aji_create_buddy(pak->from->partial, client);
+ } else {
+ buddy_unref(buddy,"hand_sub");
}
default:
- if (option_verbose > 4) {
- ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
- }
+ ast_verb(3, "JABBER: This is a subcription of type %i\n", pak->subtype);
}
}
@@ -1899,11 +2029,13 @@
*/
static void *aji_recv_loop(void *data)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
int res = IKS_HOOK;
+ client_ref(client,"recv_loop");
+
while(res != IKS_OK) {
- ast_debug(3, "JABBER: Connecting.\n");
+ ast_verb(4, "JABBER: Connecting.\n");
res = aji_reconnect(client);
sleep(4);
}
@@ -1911,7 +2043,7 @@
do {
if (res == IKS_NET_RWERR || client->timeout == 0) {
while(res != IKS_OK) {
- ast_debug(3, "JABBER: reconnecting.\n");
+ ast_verb(4, "JABBER: reconnecting.\n");
res = aji_reconnect(client);
sleep(4);
}
@@ -1931,7 +2063,7 @@
if (res == IKS_HOOK)
ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
else if (res == IKS_NET_TLSFAIL)
- ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
+ ast_log(LOG_WARNING, "JABBER: Failure in TLS.\n");
else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
if(res == IKS_OK)
@@ -1941,7 +2073,7 @@
} else if (res == IKS_NET_RWERR)
ast_log(LOG_WARNING, "JABBER: socket read error\n");
} while (client);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "recv_loop");
return 0;
}
@@ -2056,11 +2188,13 @@
* \brief goes through roster and prunes users not needed in list, or adds them accordingly.
* \param client the configured XMPP client we use to connect to a XMPP server
* \return void.
- * \note The messages here should be configurable.
*/
static void aji_pruneregister(struct aji_client *client)
{
int res = 0;
+ struct ao2_iterator iter;
+ struct aji_buddy *b = NULL;
+
iks *removeiq = iks_new("iq");
iks *removequery = iks_new("query");
iks *removeitem = iks_new("item");
@@ -2072,30 +2206,33 @@
iks_insert_node(removeiq, removequery);
iks_insert_node(removequery, removeitem);
- ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
- ASTOBJ_RDLOCK(iterator);
+ iter = ao2_iterator_init(client->buddies, 0);
+
+ while ((b = ao2_t_iterator_next(&iter, "Iter through buddies"))) {
+ ao2_lock(b);
/* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
* be called at the same time */
- if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) {
- res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
- "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
+ if (ast_test_flag(&b->flags, AJI_AUTOPRUNE)) {
+ res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, b->name,
+ "GoodBye your status is no longer needed by Asterisk the Open Source PBX"
" so I am no longer subscribing to your presence.\n"));
- res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
- "GoodBye. You are no longer in the Asterisk config file so I am removing"
+ res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, b->name,
+ "GoodBye you are no longer in the asterisk config file so I am removing"
" your access to my presence.\n"));
iks_insert_attrib(removeiq, "from", client->jid->full);
iks_insert_attrib(removeiq, "type", "set");
iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
- iks_insert_attrib(removeitem, "jid", iterator->name);
+ iks_insert_attrib(removeitem, "jid", b->name);
iks_insert_attrib(removeitem, "subscription", "remove");
res = ast_aji_send(client, removeiq);
- } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
- res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
- "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
- ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
- }
- ASTOBJ_UNLOCK(iterator);
- });
+ } else if (ast_test_flag(&b->flags, AJI_AUTOREGISTER)) {
+ res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, b->name,
+ "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
+ ast_clear_flag(&b->flags, AJI_AUTOREGISTER);
+ }
+ ao2_unlock(b);
+ buddy_unref(b,"iter list");
+ }
safeout:
iks_delete(removeiq);
@@ -2103,7 +2240,6 @@
iks_delete(removeitem);
iks_delete(send);
- ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
}
/*!
@@ -2114,42 +2250,46 @@
*/
static int aji_filter_roster(void *data, ikspak *pak)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
+ struct aji_buddy *buddy = NULL, *b = NULL;
+ struct ao2_iterator iter;
int flag = 0;
iks *x = NULL;
- struct aji_buddy *buddy;
-
+
+ client_ref(client, "filter_ros");
client->state = AJI_CONNECTED;
- ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
- ASTOBJ_RDLOCK(iterator);
+ iter= ao2_iterator_init(client->buddies, 0);
+ while ((b = ao2_t_iterator_next(&iter, "iterate through buddies"))) {
+ ao2_lock(b);
x = iks_child(pak->query);
flag = 0;
while (x) {
if (!iks_strcmp(iks_name(x), "item")) {
- if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
+ if (!strcasecmp(b->name, iks_find_attrib(x, "jid"))) {
flag = 1;
- ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
+ ast_clear_flag(&b->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
}
}
x = iks_next(x);
}
- if (!flag)
- ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
+ if (!flag) {
+ ast_copy_flags(&b->flags, &client->flags, AJI_AUTOREGISTER);
+ }
iks_delete(x);
-
- ASTOBJ_UNLOCK(iterator);
- });
+ ao2_unlock(b);
+ buddy_unref(b, "filter_ros");
+ }
x = iks_child(pak->query);
while (x) {
flag = 0;
if (iks_strcmp(iks_name(x), "item") == 0) {
- ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
- ASTOBJ_RDLOCK(iterator);
- if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
+ iter = ao2_iterator_init(client->buddies, 0);
+ while ((b = ao2_t_iterator_next(&iter,"iter through buddies"))) {
+ if (!strcasecmp(b->name, iks_find_attrib(x, "jid")))
flag = 1;
- ASTOBJ_UNLOCK(iterator);
- });
+ buddy_unref(b, "filter_ros");
+ }
if (flag) {
/* found buddy, don't create a new one */
@@ -2157,28 +2297,26 @@
continue;
}
- buddy = ast_calloc(1, sizeof(*buddy));
+ buddy = ao2_t_alloc(sizeof(*buddy), aji_buddy_destroy, "alloc buddy");
if (!buddy) {
ast_log(LOG_WARNING, "Out of memory\n");
return 0;
}
- ASTOBJ_INIT(buddy);
- ASTOBJ_WRLOCK(buddy);
+ buddy_ref(buddy, "ref buddy");
+ ao2_lock(buddy);
ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
if(ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
- ASTOBJ_MARK(buddy);
+ buddy->mark = 1;
} else if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
/* subscribe to buddy's presence only
if we really need to */
ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
}
- ASTOBJ_UNLOCK(buddy);
- if (buddy) {
- ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
- ASTOBJ_UNREF(buddy, aji_buddy_destroy);
- }
+ ao2_unlock(buddy);
+ ao2_t_link(client->buddies, buddy, "Adding buddy to client list");
+ buddy_unref(buddy, "unref buddy");
}
x = iks_next(x);
}
@@ -2186,10 +2324,9 @@
iks_delete(x);
aji_pruneregister(client);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "unref client");
return IKS_FILTER_EAT;
}
-
/*!
* \brief reconnect to jabber server
* \param client the configured XMPP client we use to connect to a XMPP server
@@ -2211,7 +2348,6 @@
return res;
}
-
/*!
* \brief Get the roster of jabber users
* \param client the configured XMPP client we use to connect to a XMPP server
@@ -2241,8 +2377,9 @@
*/
static int aji_client_connect(void *data, ikspak *pak)
{
- struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
+ struct aji_client *client = (struct aji_client *) data;
int res = 0;
+ client_ref(client, "client_con");
if (client) {
if (client->state == AJI_DISCONNECTED) {
@@ -2253,10 +2390,11 @@
if(!client->component) /*client*/
aji_get_roster(client);
}
- } else
+ } else {
ast_log(LOG_ERROR, "Out of memory.\n");
-
- ASTOBJ_UNREF(client, aji_client_destroy);
+ }
+
+ client_unref(client, "unref client_con");
return res;
}
@@ -2305,7 +2443,7 @@
#endif
iks_disconnect(client->p);
iks_parser_delete(client->p);
- ASTOBJ_UNREF(client, aji_client_destroy);
+ client_unref(client, "unref client disc");
}
return 1;
@@ -2356,12 +2494,15 @@
*/
static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
+ struct ao2_iterator iter;
+ struct aji_client *c = NULL;
+
switch (cmd) {
case CLI_INIT:
e->command = "jabber set debug {on|off}";
e->usage =
"Usage: jabber set debug {on|off}\n"
- " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
+ " Enables/disables dumping of Jabber packets for debugging purposes.\n";
return NULL;
case CLI_GENERATE:
return NULL;
@@ -2371,19 +2512,23 @@
return CLI_SHOWUSAGE;
if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
- ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
- ASTOBJ_RDLOCK(iterator);
- iterator->debug = 1;
- ASTOBJ_UNLOCK(iterator);
- });
+ iter = ao2_iterator_init(clients, 0);
+ while((c = ao2_t_iterator_next(&iter,"Go through list"))) {
+ ao2_lock(c);
+ c->debug = 1;
+ ao2_unlock(c);
+ client_unref(c, "client unref");
+ }
ast_cli(a->fd, "Jabber Debugging Enabled.\n");
return CLI_SUCCESS;
} else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
- ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
- ASTOBJ_RDLOCK(iterator);
- iterator->debug = 0;
- ASTOBJ_UNLOCK(iterator);
- });
+ iter = ao2_iterator_init(clients, 0);
+ while((c = ao2_t_iterator_next(&iter,"Go through list"))) {
+ ao2_lock(c);
+ c->debug = 0;
+ ao2_unlock(c);
+ client_unref(c, "client unref");
+ }
ast_cli(a->fd, "Jabber Debugging Disabled.\n");
return CLI_SUCCESS;
}
@@ -2396,6 +2541,8 @@
*/
static char *aji_do_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
+ struct ao2_iterator iter;
+ struct aji_client *c;
switch (cmd) {
case CLI_INIT:
@@ -2409,20 +2556,24 @@
}
if (a->argc == 2) {
- ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
- ASTOBJ_RDLOCK(iterator);
- iterator->debug = 1;
- ASTOBJ_UNLOCK(iterator);
- });
+ iter = ao2_iterator_init(clients, 0);
+ while((c = ao2_t_iterator_next(&iter,"Go through list"))) {
+ ao2_lock(c);
+ c->debug = 1;
+ ao2_unlock(c);
+ client_unref(c, "client unref");
+ }
ast_cli(a->fd, "Jabber Debugging Enabled.\n");
return CLI_SUCCESS;
} else if (a->argc == 3) {
if (!strncasecmp(a->argv[2], "off", 3)) {
- ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
- ASTOBJ_RDLOCK(iterator);
- iterator->debug = 0;
- ASTOBJ_UNLOCK(iterator);
- });
+ iter = ao2_iterator_init(clients, 0);
+ while((c = ao2_t_iterator_next(&iter,"Go through list"))) {
+ ao2_lock(c);
+ c->debug = 0;
+ ao2_unlock(c);
+ client_unref(c, "client unref");
+ }
ast_cli(a->fd, "Jabber Debugging Disabled.\n");
return CLI_SUCCESS;
}
@@ -2459,6 +2610,8 @@
static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
char *status;
+ struct ao2_iterator iter;
+ struct aji_client *c = NULL;
int count = 0;
switch (cmd) {
@@ -2473,10 +2626,11 @@
}
ast_cli(a->fd, "Jabber Users and their status:\n");
- ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
- ASTOBJ_RDLOCK(iterator);
+ iter = ao2_iterator_init(clients, 0);
+ while((c = ao2_t_iterator_next(&iter,"Go through list"))) {
+ ao2_lock(c);
count++;
- switch (iterator->state) {
+ switch (c->state) {
case AJI_DISCONNECTED:
status = "Disconnected";
break;
@@ -2489,9 +2643,10 @@
default:
status = "Unknown";
}
- ast_cli(a->fd, " User: %s - %s\n", iterator->user, status);
- ASTOBJ_UNLOCK(iterator);
- });
+ ast_cli(a->fd, " User: %s - %s\n", c->user, status);
+ ao2_unlock(c);
+ client_unref(c, "remove ref");
+ }
ast_cli(a->fd, "----\n");
ast_cli(a->fd, " Number of users: %d\n", count);
return CLI_SUCCESS;
@@ -2504,7 +2659,10 @@
[... 446 lines stripped ...]
More information about the asterisk-commits
mailing list