[svn-commits] tilghman: trunk r270519 - in /trunk: ./ configs/ doc/ include/asterisk/ res/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jun 15 12:06:32 CDT 2010


Author: tilghman
Date: Tue Jun 15 12:06:23 2010
New Revision: 270519

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=270519
Log:
Add distributed devicestate via the XMPP protocol.

(closes issue #15757)
 Reported by: Marquis
 Patches: 
       distributed_devstate-XMPP.txt uploaded by lmadsen (license 10)
 Tested by: Marquis, lmadsen, marcelloceschia
 
Review: https://reviewboard.asterisk.org/r/351/

Added:
    trunk/doc/distributed_devstate-XMPP.txt   (with props)
Modified:
    trunk/CHANGES
    trunk/configs/jabber.conf.sample
    trunk/include/asterisk/jabber.h
    trunk/res/res_jabber.c

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=270519&r1=270518&r2=270519
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Jun 15 12:06:23 2010
@@ -496,6 +496,8 @@
    initialization order.
  * The Realtime dialplan switch now caches entries for 1 second.  This provides a
    significant increase in performance (about 3X) for installations using this switchtype.
+ * Distributed devicestate now supports the use of the XMPP protocol, in addition to
+   AIS.  For more information, please see doc/distributed_devstate-XMPP.txt
 
 CLI Changes
 -----------

Modified: trunk/configs/jabber.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/jabber.conf.sample?view=diff&rev=270519&r1=270518&r2=270519
==============================================================================
--- trunk/configs/jabber.conf.sample (original)
+++ trunk/configs/jabber.conf.sample Tue Jun 15 12:06:23 2010
@@ -1,29 +1,41 @@
 [general]
-;debug=yes				;;Turn on debugging by default.
-;autoprune=yes				;;Auto remove users from buddy list. Depending on your
-					;;setup (ie, using your personal Gtalk account for a test)
-					;;you might lose your contacts list. Default is 'no'.
-;autoregister=yes			;;Auto register users from buddy list.
-;auth_policy=accept			;;Auto accept users' subscription requests (default).
-							;;Set to deny for auto denial.
+;debug=yes                              ;;Turn on debugging by default.
+;autoprune=yes                          ;;Auto remove users from buddy list. Depending on your
+                                        ;;setup (ie, using your personal Gtalk account for a test)
+                                        ;;you might lose your contacts list. Default is 'no'.
+;autoregister=yes                       ;;Auto register users from buddy list.
+;collection_nodes=yes                   ;;Enable support for XEP-0248 for use with
+                                        ;;distributed device state.  Default is 'no'.
+;pubsub_autocreate=yes                  ;;Whether or not the PubSub server supports/is using
+                                        ;;auto-create for nodes.  If it is, we have to
+                                        ;;explicitly pre-create nodes before publishing them.
+                                        ;;Default is 'no'.
+;auth_policy=accept                     ;;Auto accept users' subscription requests (default).
+                                        ;;Set to deny for auto denial.
 
 
-;[asterisk]				;;label
-;type=client				;;Client or Component connection
-;serverhost=astjab.org			;;Route to server for example,
-					;;	talk.google.com
-;username=asterisk at astjab.org/asterisk	;;Username with optional resource.
-;secret=blah				;;Password
-;priority=1				;;Resource priority
-;port=5222				;;Port to use defaults to 5222
-;usetls=yes				;;Use tls or not
-;usesasl=yes				;;Use sasl or not
-;buddy=mogorman at astjab.org		;;Manual addition of buddy to list.
-;status=available			;;One of: chat, available, away,
-					;;	xaway, or dnd
-;statusmessage="I am available"		;;Have custom status message for
-					;;Asterisk.
-;timeout=5				;;Timeout (in seconds) on the message stack, defaults to 5.
-					;;Messages stored longer than this value will be deleted by Asterisk.
-					;;This option applies to incoming messages only, which are intended to
-					;;be processed by the JABBER_RECEIVE dialplan function.
+;[asterisk]                             ;;label
+;type=client                            ;;Client or Component connection
+;serverhost=astjab.org                  ;;Route to server for example,
+                                        ;;	talk.google.com
+;pubsub_node=pubsub.astjab.org          ;;Node to use for publishing events via PubSub
+;username=asterisk at astjab.org/asterisk  ;;Username with optional resource.
+;secret=blah                            ;;Password
+;priority=1                             ;;Resource priority
+;port=5222                              ;;Port to use defaults to 5222
+;usetls=yes                             ;;Use tls or not
+;usesasl=yes                            ;;Use sasl or not
+;buddy=mogorman at astjab.org              ;;Manual addition of buddy to list.
+                                        ;;For distributed events, these buddies are
+                                        ;;automatically added in the whitelist as
+                                        ;;'owners' of the node(s).
+;distribute_events=yes                  ;;Whether or not to distribute events using
+                                        ;;this connection.  Default is 'no'.
+;status=available                       ;;One of: chat, available, away,
+                                        ;;	xaway, or dnd
+;statusmessage="I am available"         ;;Have custom status message for
+                                        ;;Asterisk.
+;timeout=5                              ;;Timeout (in seconds) on the message stack, defaults to 5.
+                                        ;;Messages stored longer than this value will be deleted by Asterisk.
+                                        ;;This option applies to incoming messages only, which are intended to
+                                        ;;be processed by the JABBER_RECEIVE dialplan function.

Added: trunk/doc/distributed_devstate-XMPP.txt
URL: http://svnview.digium.com/svn/asterisk/trunk/doc/distributed_devstate-XMPP.txt?view=auto&rev=270519
==============================================================================
--- trunk/doc/distributed_devstate-XMPP.txt (added)
+++ trunk/doc/distributed_devstate-XMPP.txt Tue Jun 15 12:06:23 2010
@@ -1,0 +1,433 @@
+===============================================================================
+===
+=== XMPP PubSub Distributed Device State
+===
+=== Copyright (C) 2010, Digium, Inc.
+=== Leif Madsen <lmadsen at digium.com>
+===
+===============================================================================
+
+-------------------------------------------------------------------------------
+--- INTRODUCTION
+-------------------------------------------------------------------------------
+
+This document describes installing and utilizing XMPP PubSub events to 
+distribute device state and message waiting indication (MWI) events between
+servers. The difference between this method and OpenAIS (see 
+distributed_devstate.txt) is that OpenAIS can only be used in low latency
+networks; meaning only on the LAN, and not across the internet.
+
+If you plan on distributing device state or MWI across the internet, then you
+will require the use of XMPP PubSub events.
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Tigase Installation
+-------------------------------------------------------------------------------
+
+-- Description --
+
+Currently the only server supported for XMPP PubSub events is the Tigase open 
+source XMPP/Jabber environment. This is the server that the various Asterisk
+servers will connect to in order to distribute the events. The Tigase server can
+even be clustered in order to provide high availability for your device state;
+however, that is beyond the scope of this document.
+
+For more information about Tigase, visit their web site:
+
+    http://www.tigase.org
+
+-- Download --
+
+To download the Tigase environment, get the latest version at:
+
+    http://www.tigase.org/en/filebrowser/tigase-server
+
+-- Install --
+
+The Tigase server requires a working Java environment, including both a JRE
+(Java Runtime Environment) and a JDK (Java Development Kit), currently at least
+version 1.6.
+
+For more information about how to install Tigase, see the web site:
+
+    http://www.tigase.org/en/content/quick-start
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Tigase Configuration
+-------------------------------------------------------------------------------
+
+While installing Tigase, be sure you enable the PubSub module. Without it, the
+PubSub events won't be accepted by the server, and your device state will not be
+distributed.
+
+There are a couple of things you need to configure in Tigase before you start it
+in order for Asterisk to connect. The first thing we need to do is generate the
+self-signed certificate. To do this we use the keytool application. More
+information can be found here:
+
+    http://www.tigase.org/en/content/server-certificate
+
+-- Generating the keystore file --
+
+Generally, we need to run the following commands to generate a new keystore
+file.
+
+# cd /opt/Tigase-4.3.1-b1858/certs
+
+Be sure to change the 'yourdomain' to your domain.
+
+# keytool -genkey -alias yourdomain -keystore rsa-keystore \
+      -keyalg RSA -sigalg MD5withRSA
+
+The keytool application will then ask you for a password. Use the password
+'keystore' as this is the default password that Tigase will use to load the
+keystore file.
+
+You then need to specify your domain as the first value to be entered in the
+security certificate.
+
+What is your first and last name?
+  [Unknown]: asterisk.mydomain.tld
+What is the name of your organizational unit?
+  [Unknown]:
+What is the name of your organization?
+  [Unknown]:
+What is the name of your City or Locality?
+  [Unknown]:
+What is the name of your State or Province?
+  [Unknown]:
+What is the two-letter country code for this unit?
+  [Unknown]:
+Is CN=asterisk.mydomain.tld, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
+  [no]: yes
+
+You will then be asked for another password, in which case you must just press
+enter for the same password as Tigase will not work without them being the same.
+
+Enter key password for <mykey>
+             (RETURN if same as keystore password):
+
+
+-- Configuring init.properties --
+
+The next step is to configure the init.properties file which is used by Tigase
+to generate the tigase.xml file. Whenever you change the init.properties file
+because sure to remove the current tigase.xml file so that it will be
+regenerated at start up.
+
+# cd /opt/Tigase-4.3.1-b1858/etc
+
+Then edit the init.properties file and add the following:
+
+config-type=--gen-config-def
+--admins=admin at asterisk.mydomain.tld
+--virt-hosts=asterisk.mydomain.tld
+--debug=server
+--user-db=derby
+--user-db-uri=jdbc:derby:/opt/Tigase-4.3.1-b1858
+--comp-name-1=pubsub
+--comp-class-1=tigase.pubsub.PubSubComponent
+
+Be sure to change the domain in the --admin and --virt-hosts options. The most
+important lines are --comp-name-1 and --comp-class-1 which tell Tigase to load
+the PubSub module.
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Running Tigase
+-------------------------------------------------------------------------------
+
+You can then start the Tigase server with the tigase.sh script.
+
+# cd /opt/Tigase-4.3.1-b1858
+# ./scripts/tigase.sh start etc/tigase.conf
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Adding Buddies to Tigase
+-------------------------------------------------------------------------------
+
+At this time, Asterisk is not able to automatically register your peers for you,
+so you'll need to use an external application to do the initial registration.
+
+Pidgin is an excellent multi-protocol instant messenger application which
+supports XMPP. It runs on Linux, Windows, and OSX, and is open source. You can
+get Pidgin from http://www.pidgin.im
+
+Then add the two buddies we'll use in Asterisk with Pidgin by connecting to
+the Tigase server. For more information about how to register new buddies, see
+the Pidgin documentation.
+
+Once the initial registration is done and loaded into Tigase, you no longer need
+to worry about using Pidgin. Asterisk will then be able to load the peers into
+memory at start up.
+
+The example peers we've used in the following documentation for our two nodes
+are:
+
+server1 at asterisk.mydomain.tld/astvoip1
+server2 at asterisk.mydomain.tld/astvoip2
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Installing Asterisk
+-------------------------------------------------------------------------------
+
+Install Asterisk as usual. However, you'll need to make sure you have the
+res_jabber module compiled, which requires the iksemel development library.
+Additionally, be sure you have the OpenSSL development library installed so you
+can connect securly to the Tigase server.
+
+Make sure you check menuselect that res_jabber is selected so that it will
+compile.
+
+# cd asterisk-source
+# ./configure
+
+# make menuselect
+  ---> Resource Modules
+
+If you don't have jabber.conf in your existing configuration, because sure to
+copy the sample configuration file there.
+
+# cd configs
+# cp jabber.conf.sample /etc/asterisk/jabber.conf
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Configuring Asterisk
+-------------------------------------------------------------------------------
+
+We then need to configure our servers to communicate with the Tigase server. We
+need to modify the jabber.conf file on the servers. The configurations below are
+for a 2 server setup, but could be expanded for additional servers easily.
+
+The key note here is to note that the pubsub_node option needs to start with
+pubsub, so for example, pubsub.asterisk.mydomain.tld. Without the 'pubsub' your
+Asterisk system will not be able to distribute events.
+
+Additionally, you will need to specify each of the servers you need to connec to
+using the 'buddy' option.
+
+
+-- Asterisk Server 1 --
+
+[general]
+debug=no                                ;;Turn on debugging by default.
+;autoprune=yes                          ;;Auto remove users from buddy list. Depending on your
+                                        ;;setup (ie, using your personal Gtalk account for a test)
+                                        ;;you might lose your contacts list. Default is 'no'.
+autoregister=yes                        ;;Auto register users from buddy list.
+;collection_nodes=yes                   ;;Enable support for XEP-0248 for use with
+                                        ;;distributed device state.  Default is 'no'.
+;pubsub_autocreate=yes                  ;;Whether or not the PubSub server supports/is using
+                                        ;;auto-create for nodes.  If it is, we have to
+                                        ;;explicitly pre-create nodes before publishing them.
+                                        ;;Default is 'no'.
+
+[asterisk]
+type=client
+serverhost=asterisk.mydomain.tld
+pubsub_node=pubsub.asterisk.mydomain.tld
+username=server1 at asterisk.mydomain.tld/astvoip1
+secret=welcome
+distribute_events=yes
+status=available
+usetls=no
+usesasl=yes
+buddy=server2 at asterisk.mydomain.tld/astvoip2
+
+
+-- Asterisk Server 2 --
+
+[general]
+debug=yes				;;Turn on debugging by default.
+;autoprune=yes				;;Auto remove users from buddy list. Depending on your
+					;;setup (ie, using your personal Gtalk account for a test)
+					;;you might lose your contacts list. Default is 'no'.
+autoregister=yes			;;Auto register users from buddy list.
+;collection_nodes=yes			;;Enable support for XEP-0248 for use with
+					;;distributed device state.  Default is 'no'.
+;pubsub_autocreate=yes			;;Whether or not the PubSub server supports/is using
+					;;auto-create for nodes.  If it is, we have to
+					;;explicitly pre-create nodes before publishing them.
+					;;Default is 'no'.
+
+[asterisk]
+type=client
+serverhost=asterisk.mydomain.tld
+pubsub_node=pubsub.asterisk.mydomain.tld
+username=server2 at asterisk.mydomain.tld/astvoip2
+secret=welcome
+distribute_events=yes
+status=available
+usetls=no
+usesasl=yes
+buddy=server1 at asterisk.mydomain.tld/astvoip1
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Basic Testing of Asterisk with XMPP PubSub
+-------------------------------------------------------------------------------
+
+Once you have Asterisk installed with XMPP PubSub, it is time to test it out.
+
+We need to start up our first server and make sure we get connected to the XMPP
+server. We can verify this with an Asterisk console command to determine if
+we're connected.
+
+On Asterisk 1 we can run 'jabber show connected' to verify we're connected to
+the XMPP server.
+
+*CLI> jabber show connected 
+Jabber Users and their status:
+       User: server1 at asterisk.mydomain.tld/astvoip1     - Connected
+----
+   Number of users: 1
+
+The command above has given us output which verifies we've connected our first
+server.
+
+We can then check the state of our buddies with the 'jabber show buddies' CLI
+command.
+
+*CLI> jabber show buddies
+Jabber buddy lists
+Client: server1 at asterisk.mydomain.tld/astvoip1
+	Buddy:	server2 at asterisk.mydomain.tld
+		Resource: None
+	Buddy:	server2 at asterisk.mydomain.tld/astvoip2
+		Resource: None
+
+The output above tells us we're not connected to any buddies, and thus we're not
+distributing state to anyone (or getting it from anyone). That makes sense since
+we haven't yet started our other server.
+
+Now, let's start the other server and verify the servers are able to establish
+a connection between each other.
+
+On Asterisk 2, again we run the 'jabber show connected' command to make sure
+we've connected successfully to the XMPP server.
+
+*CLI> jabber show connected 
+Jabber Users and their status:
+       User: server2 at asterisk.mydomain.tld/astvoip2     - Connected
+----
+   Number of users: 1
+
+And now we can check the status of our buddies.
+
+*CLI> jabber show buddies
+Jabber buddy lists
+Client: server2 at scooter/astvoip2
+	Buddy:	server1 at asterisk.mydomain.tld
+		Resource: astvoip1
+			node: http://www.asterisk.org/xmpp/client/caps
+			version: asterisk-xmpp
+			Jingle capable: yes
+		Status: 1
+		Priority: 0
+	Buddy:	server1 at asterisk.mydomain.tld/astvoip1
+		Resource: None
+
+Excellent! So we're connected to the buddy on Asterisk 1, and we could run the
+same command on Asterisk 1 to verify the buddy on Asterisk 2 is seen.
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Testing Distributed Device State
+-------------------------------------------------------------------------------
+
+The easiest way to test distributed device state is to use the DEVICE_STATE()
+diaplan function.  For example, you could have the following piece of dialplan
+on every server:
+
+[devstate_test]
+
+exten => 1234,hint,Custom:mystate
+
+exten => set_inuse,1,Set(DEVICE_STATE(Custom:mystate)=INUSE)
+exten => set_not_inuse,1,Set(DEVICE_STATE(Custom:mystate)=NOT_INUSE)
+
+exten => check,1,NoOp(Custom:mystate is ${DEVICE_STATE(Custom:mystate)})
+
+
+Now, you can test that the cluster-wide state of "Custom:mystate" is what
+you would expect after going to the CLI of each server and adjusting the state.
+
+server1*CLI> console dial set_inuse at devstate_test
+   ...
+
+server2*CLI> console dial check at devstate_test
+    -- Executing [check at devstate_test:1] NoOp("OSS/dsp", "Custom:mystate is INUSE") in new stack
+
+Various combinations of setting and checking the state on different servers can
+be used to verify that it works as expected.  Also, you can see the status of
+the hint on each server, as well, to see how extension state would reflect the
+state change with distributed device state:
+
+server2*CLI> core show hints
+    -= Registered Asterisk Dial Plan Hints =-
+                   1234 at devstate_test       : Custom:mystate        State:InUse           Watchers  0
+
+
+One other helpful thing here during testing and debugging is to enable debug
+logging.  To do so, enable debug on the console in /etc/asterisk/logger.conf.
+Also, enable debug at the Asterisk CLI.
+
+*CLI> core set debug 1
+
+When you have this debug enabled, you will see output during the processing of
+every device state change.  The important thing to look for is where the known
+state of the device for each server is added together to determine the overall
+state.
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Notes On Large Installations
+-------------------------------------------------------------------------------
+
+On larger installations where you want a fully meshed network of buddies (i.e.
+all servers have all the buddies of the remote servers), you may want some
+method of distributing those buddies automatically so you don't need to modify
+all servers (N+1) every time you add a new server to the cluster.
+
+The problem there is that you're confined by what's allowed in XEP-0060, and 
+unfortunately that means modifying affiliations by individual JID (as opposed to
+the various subscription access models, which are more flexible).
+
+See here for details:
+http://xmpp.org/extensions/xep-0060.html#owner-affiliations
+
+One method for making this slightly easier is to utilize the #exec functionality
+in configuration files, and dynamically generate the buddies via script that
+pulls the information from a database, or to #include a file which is 
+automatically generated on all the servers when you add a new node to the
+cluster.
+
+Unfortunately this still requires a reload of res_jabber.so on all the servers,
+but this could also be solved through the use of the Asterisk Manager Interface
+(AMI).
+
+So while this is not the ideal situation, it is programmatically solvable with
+existing technologies and features found in Asterisk today.
+
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--- Questions, Comments, and Bug Reports
+-------------------------------------------------------------------------------
+
+Please utilize the Asterisk issue tracker for all bug reports at
+https://issues.asterisk.org

Propchange: trunk/doc/distributed_devstate-XMPP.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/doc/distributed_devstate-XMPP.txt
------------------------------------------------------------------------------
    svn:keywords = 'Date Author Id Revision Yoyo'

Propchange: trunk/doc/distributed_devstate-XMPP.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: trunk/include/asterisk/jabber.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/jabber.h?view=diff&rev=270519&r1=270518&r2=270519
==============================================================================
--- trunk/include/asterisk/jabber.h (original)
+++ trunk/include/asterisk/jabber.h Tue Jun 15 12:06:23 2010
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2005, Digium, Inc.
+ * Copyright (C) 1999 - 2010, Digium, Inc.
  *
  * Matt O'Gorman <mogorman at digium.com>
  *
@@ -85,13 +85,19 @@
 enum {
 	AJI_AUTOPRUNE = (1 << 0),
 	AJI_AUTOREGISTER = (1 << 1),
-	AJI_AUTOACCEPT = (1 << 2)
+	AJI_AUTOACCEPT = (1 << 2),
+};
+
+enum {
+	AJI_XEP0248 = (1 << 0),
+	AJI_PUBSUB = (1 << 1),
+	AJI_PUBSUB_AUTOCREATE = (1 << 2),
 };
 
 enum aji_btype {
-	AJI_USER=0,
-	AJI_TRANS=1,
-	AJI_UTRANS=2
+	AJI_USER = 0,
+	AJI_TRANS = 1,
+	AJI_UTRANS = 2,
 };
 
 struct aji_version {
@@ -145,6 +151,7 @@
 	char password[160];
 	char user[AJI_MAX_JIDLEN];
 	char serverhost[AJI_MAX_RESJIDLEN];
+	char pubsub_node[AJI_MAX_RESJIDLEN];
 	char statusmessage[256];
 	char name_space[256];
 	char sid[10]; /* Session ID */
@@ -170,6 +177,7 @@
 	int timeout;
 	int message_timeout;
 	int authorized;
+	int distribute_events;
 	struct ast_flags flags;
 	int component; /* 0 client,  1 component */
 	struct aji_buddy_container buddies;

Modified: trunk/res/res_jabber.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_jabber.c?view=diff&rev=270519&r1=270518&r2=270519
==============================================================================
--- trunk/res/res_jabber.c (original)
+++ trunk/res/res_jabber.c Tue Jun 15 12:06:23 2010
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2010, Digium, Inc.
  *
  * Matt O'Gorman <mogorman at digium.com>
  *
@@ -58,6 +58,8 @@
 #include "asterisk/astobj.h"
 #include "asterisk/astdb.h"
 #include "asterisk/manager.h"
+#include "asterisk/event.h"
+#include "asterisk/devicestate.h"
 
 /*** DOCUMENTATION
 	<application name="JabberSend" language="en_US">
@@ -277,8 +279,8 @@
 	</manager>
  ***/
 
-/*! \todo This should really be renamed to xmpp.conf. For backwards compatibility, we
- 	need to read both files */
+/*!\todo This should really be renamed to xmpp.conf. For backwards compatibility, we
+ * need to read both files */
 #define JABBER_CONFIG "jabber.conf"
 
 /*-- Forward declarations */
@@ -325,7 +327,45 @@
 static int aji_register_query_handler(void *data, ikspak *pak);
 static int aji_register_approve_handler(void *data, ikspak *pak);
 static int aji_reconnect(struct aji_client *client);
+static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd,
+	struct ast_cli_args *a);
+static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd,
+	struct ast_cli_args *a);
+static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
+	ast_cli_args *a);
+static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
+		ast_cli_args *a);
 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
+static int aji_receive_node_list(void *data, ikspak* pak);
+static void aji_init_event_distribution(struct aji_client *client);
+static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type,
+	const char *name, const char *collection_name);
+static iks* aji_build_node_config(iks *pubsub, const char *node_type,
+	const char *collection_name);
+static void aji_create_pubsub_collection(struct aji_client *client,
+	const char *collection_name);
+static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
+   const char *leaf_name);
+static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd,
+	struct ast_cli_args *a);
+static void aji_create_affiliations(struct aji_client *client, const char *node);
+static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type);
+static void aji_publish_device_state(struct aji_client *client, const char * device,
+	const char *device_state);
+static int aji_handle_pubsub_error(void *data, ikspak *pak);
+static int aji_handle_pubsub_event(void *data, ikspak *pak);
+static void aji_pubsub_subscribe(struct aji_client *client, const char *node);
+static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name);
+static iks* aji_build_node_request(struct aji_client *client, const char *collection);
+static int aji_delete_node_list(void *data, ikspak* pak);
+static void aji_pubsub_purge_nodes(struct aji_client *client,
+	const char* collection_name);
+static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
+	const char *context, const char *oldmsgs, const char *newmsgs);
+static void aji_devstate_cb(const struct ast_event *ast_event, void *data);
+static void aji_mwi_cb(const struct ast_event *ast_event, void *data);
+static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
+	const char *event_type);
 /* No transports in this version */
 /*
 static int aji_create_transport(char *label, struct aji_client *client);
@@ -339,6 +379,11 @@
 	AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"),
 	AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"),
 	AST_CLI_DEFINE(aji_test, "Shows roster, but is generally used for mog's debugging."),
+	AST_CLI_DEFINE(aji_cli_create_collection, "Creates a PubSub node collection."),
+	AST_CLI_DEFINE(aji_cli_list_pubsub_nodes, "Lists PubSub nodes"),
+	AST_CLI_DEFINE(aji_cli_create_leafnode, "Creates a PubSub leaf node"),
+	AST_CLI_DEFINE(aji_cli_delete_pubsub_node, "Deletes a PubSub node"),
+	AST_CLI_DEFINE(aji_cli_purge_pubsub_nodes, "Purges PubSub nodes"),
 };
 
 static char *app_ajisend = "JabberSend";
@@ -349,12 +394,16 @@
 
 static struct aji_client_container clients;
 static struct aji_capabilities *capabilities = NULL;
+static struct ast_event_sub *mwi_sub = NULL;
+static struct ast_event_sub *device_state_sub = NULL;
 static ast_cond_t message_received_condition;
 static ast_mutex_t messagelock;
 
 /*! \brief Global flags, initialized to default values */
 static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT };
 
+/*! \brief PubSub flags, initialized to default values */
+static struct ast_flags pubsubflags = { AJI_AUTOREGISTER };
 /*!
  * \internal
  * \brief Deletes the aji_client data structure.
@@ -430,17 +479,20 @@
 
 	list = capabilities;
 
-	if (!node)
+	if (!node) {
 		node = pak->from->full;
-	if (!version)
+	}
+	if (!version) {
 		version = "none supplied.";
-	while(list) {
+	}
+	while (list) {
 		if (!strcasecmp(list->node, node)) {
 			res = list->versions;
 			while(res) {
-				 if (!strcasecmp(res->version, version))
-					 return res;
-				 res = res->next;
+				if (!strcasecmp(res->version, version)) {
+					return res;
+				}
+				res = res->next;
 			}
 			/* Specified version not found. Let's add it to
 			   this node in our capabilities list */
@@ -489,14 +541,15 @@
  * \internal
  * \brief Find the aji_resource we want
  * \param buddy aji_buddy A buddy
- * \param name 
+ * \param name
  * \return aji_resource object
 */
 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
 {
 	struct aji_resource *res = NULL;
-	if (!buddy || !name)
+	if (!buddy || !name) {
 		return res;
+	}
 	res = buddy->resources;
 	while (res) {
 		if (!strcasecmp(res->resource, name)) {
@@ -515,8 +568,9 @@
 */
 static int gtalk_yuck(iks *node)
 {
-	if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
+	if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
 		return 1;
+	}
 	return 0;
 }
 
@@ -577,8 +631,9 @@
 		AST_APP_ARG(resource);
 	);
 
-	if (deprecation_warning++ % 10 == 0)
+	if (deprecation_warning++ % 10 == 0) {
 		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");
@@ -608,12 +663,14 @@
 		return -1;
 	}
 	r = aji_find_resource(buddy, jid.resource);
-	if (!r && buddy->resources) 
+	if (!r && buddy->resources) {
 		r = buddy->resources;
-	if (!r)
+	}
+	if (!r) {
 		ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
-	else
+	} else {
 		stat = r->status;
+	}
 	snprintf(status, sizeof(status), "%d", stat);
 	pbx_builtin_setvar_helper(chan, args.variable, status);
 	return 0;
@@ -670,12 +727,14 @@
 		return -1;
 	}
 	r = aji_find_resource(buddy, jid.resource);
-	if (!r && buddy->resources) 
+	if (!r && buddy->resources) {
 		r = buddy->resources;
-	if (!r)
+	}
+	if (!r) {
 		ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
-	else
+	} else {
 		stat = r->status;
+	}
 	snprintf(buf, buflen, "%d", stat);
 	return 0;
 }
@@ -723,7 +782,7 @@
 	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (args.argc < 2 || args.argc > 3) {
-                ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
+		ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
 		return -1;
 	}
 
@@ -771,7 +830,7 @@
 		struct timeval wait;
 		int res;
 
-                wait = ast_tvadd(start, ast_tv(timeout, 0));
+		wait = ast_tvadd(start, ast_tv(timeout, 0));
 		ts.tv_sec = wait.tv_sec;
 		ts.tv_nsec = wait.tv_usec * 1000;
 
@@ -782,7 +841,7 @@
 		if (res == ETIMEDOUT) {
 			ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
 			break;
-		};
+		}
 
 		AST_LIST_LOCK(&client->messages);
 		AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
@@ -940,23 +999,23 @@
 		ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
 		return -1;
 	}
-	
+
 	if (!(client = ast_aji_get_client(args.sender))) {
 		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
 		return -1;
 	}
-	
+
 	if (strchr(args.jid, '/')) {
 		ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
 		ASTOBJ_UNREF(client, aji_client_destroy);
 		return -1;
-	}	
-	
+	}
+
 	if (!ast_strlen_zero(args.nick)) {
 		snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
 	} else {
 		if (client->component) {
-			sprintf(nick, "asterisk"); 			
+			sprintf(nick, "asterisk");
 		} else {
 			snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
 		}
@@ -967,11 +1026,11 @@
 	} else {
 		ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
 	}
-	
+
 	ASTOBJ_UNREF(client, aji_client_destroy);
 	return 0;
 }
-	
+
 /*!
 * \brief Application to leave a chat room
 * \param chan ast_channel
@@ -989,29 +1048,29 @@
 		AST_APP_ARG(jid);
 		AST_APP_ARG(nick);
 	);
-	
+
 	if (!data) {
 		ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
 		return -1;
 	}
 	s = ast_strdupa(data);
-	
+
 	AST_STANDARD_APP_ARGS(args, s);
 	if (args.argc < 2 || args.argc > 3) {
 		ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
 		return -1;
 	}
-	
+
 	if (!(client = ast_aji_get_client(args.sender))) {
 		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
 		return -1;
 	}
-	
+
 	if (strchr(args.jid, '/')) {
 		ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
 		ASTOBJ_UNREF(client, aji_client_destroy);
 		return -1;
-	} 
+	}
 	if (!ast_strlen_zero(args.nick)) {
 		snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
 	} else {
@@ -1021,10 +1080,10 @@
 			snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
 		}
 	}
-	
+
 	if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
 		ast_aji_leave_chat(client, args.jid, nick);
-	} 
+	}
 	ASTOBJ_UNREF(client, aji_client_destroy);
 	return 0;
 }
@@ -1088,24 +1147,24 @@
 		AST_APP_ARG(message);
 		AST_APP_ARG(nick);
 	);
-	
+
 	if (!data) {
 		ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
 		return -1;
 	}
 	s = ast_strdupa(data);
-	
+
 	AST_STANDARD_APP_ARGS(args, s);
 	if (args.argc < 3 || args.argc > 4) {
 		ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
 		return -1;
 	}
-	
+
 	if (!(client = ast_aji_get_client(args.sender))) {
 		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
 		return -1;
 	}
-	
+
 	if (ast_strlen_zero(args.nick) || args.argc == 3) {
 		if (client->component) {
 			sprintf(nick, "asterisk");
@@ -1115,11 +1174,11 @@
 	} else {
 		snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
 	}
-	
+
 	if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
 		res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
 	}
-	
+
 	ASTOBJ_UNREF(client, aji_client_destroy);
 	if (res != IKS_OK) {
 		return -1;
@@ -1154,64 +1213,64 @@
 	int ret;
 
 	/* This is sent not encrypted */
-	ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
-	if (ret)
+	if ((ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"))) {
 		return ret;
+	}
 
 	client->stream_flags |= TRY_SECURE;
 	return IKS_OK;
 }
 
-/*! 
+/*!
  * \internal
  * \brief TLS handshake, OpenSSL initialization
  * \param client the configured XMPP client we use to connect to a XMPP server
- * \return IKS_OK on success, IKS_NET_TLSFAIL on failure 
+ * \return IKS_OK on success, IKS_NET_TLSFAIL on failure
  */
 static int aji_tls_handshake(struct aji_client *client)
 {
 	int ret;
 	int sock;
-	
-	ast_debug(1, "Starting TLS handshake\n"); 
+
+	ast_debug(1, "Starting TLS handshake\n");
 
 	/* Choose an SSL/TLS protocol version, create SSL_CTX */
 	client->ssl_method = SSLv3_method();
-	client->ssl_context = SSL_CTX_new(client->ssl_method);                
-	if (!client->ssl_context)
+	if (!(client->ssl_context = SSL_CTX_new(client->ssl_method))) {
 		return IKS_NET_TLSFAIL;
+	}
 
 	/* Create new SSL session */
-	client->ssl_session = SSL_new(client->ssl_context);
-	if (!client->ssl_session)
+	if (!(client->ssl_session = SSL_new(client->ssl_context))) {
 		return IKS_NET_TLSFAIL;
+	}
 
 	/* Enforce TLS on our XMPP connection */
 	sock = iks_fd(client->p);
-	ret = SSL_set_fd(client->ssl_session, sock);
-	if (!ret)
+	if (!(ret = SSL_set_fd(client->ssl_session, sock))) {
 		return IKS_NET_TLSFAIL;
+	}
 
 	/* Perform SSL handshake */
-	ret = SSL_connect(client->ssl_session);
-	if (!ret)
+	if (!(ret = SSL_connect(client->ssl_session))) {
 		return IKS_NET_TLSFAIL;
+	}
 
 	client->stream_flags &= (~TRY_SECURE);
 	client->stream_flags |= SECURE;
 
 	/* Sent over the established TLS connection */
-	ret = aji_send_header(client, client->jid->server);
-	if (ret != IKS_OK)
+	if ((ret = aji_send_header(client, client->jid->server)) != IKS_OK) {
 		return IKS_NET_TLSFAIL;
-
-	ast_debug(1, "TLS started with server\n"); 
+	}
+
+	ast_debug(1, "TLS started with server\n");
 
 	return IKS_OK;
 }
 #endif /* HAVE_OPENSSL */
 
-/*! 
+/*!
  * \internal
  * \brief Secured or unsecured IO socket receiving function
  * \param client the configured XMPP client we use to connect to a XMPP server
@@ -1232,11 +1291,12 @@
 #ifdef HAVE_OPENSSL
 	if (aji_is_secure(client)) {
 		sock = SSL_get_fd(client->ssl_session);
-		if (sock < 0)
-			return -1;		
+		if (sock < 0) {
+			return -1;
+		}
 	} else
 #endif /* HAVE_OPENSSL */
-		sock = iks_fd(client->p);	
+		sock = iks_fd(client->p);
 
 	memset(&tv, 0, sizeof(struct timeval));
 	FD_ZERO(&fds);
@@ -1265,7 +1325,7 @@
 	return res;
 }
 
-/*! 
+/*!
  * \internal
  * \brief Tries to receive data from the Jabber server
  * \param client the configured XMPP client we use to connect to a XMPP server
@@ -1296,7 +1356,7 @@
 		buf[len] = '\0';
 
 		/* our iksemel parser won't work as expected if we feed
-		   it with XML packets that contain multiple whitespace 

[... 1952 lines stripped ...]



More information about the svn-commits mailing list