Registration Projects

Registration


 RepRap X2V3   RepRap X2   Virtual Display Image Viewer for PDA   XUL Jabber Client   Voice Sensitive Screen Saver 

XUL Jabber Client Development

Author: Denis Bakin
December 5, 2002

CONTENTS

XUL Jabber Client development

Jabber Protocol

Design Considerations

Jabber Client User interface

Jabber Client Operation and Execution Flow

Conclusion

References

Appendix A

XML debug log for signing on with server test.net of new user test3@test.net

XML debug log for signing on with server test.net of existent user test@test.net

XML debug log for adding user den@test.net to the roster of test1@test.net

XML debug log for receiving a subscription request from user denis@test.net

XML debug log for sending message to user den@test.net

XML debug log for receiving a message from user denis@test.net

Appendix B

Jabber Client Directory/File Structure

Application startup code (start_me.html)

User interface file (jabber.xul)

Java applet source code (jsApplet.java)

Appendix C

Jabber daemon for MS Windows installation instructions

Requirements

Installation

XUL Jabber Client development

Jabber Protocol

Jabber is an open protocol for the instant message exchange. It offers functionality similar to MSN, ICQ, IRC and many other proprietary instant messaging systems provide. The advantages of the Jabber protocol are:

A detailed explanation of some of these advantages is worth mentioning.

The gateways to the existent instant messaging systems should provide interoperability and smooth transition to Jabber for users of the other similar services. For example, to send a message to an ICQ address trough the jabber.org server, a Jabber user has to have an existent ICQ account, register it with the Jabber ICQ agent, and send the message to the address formed of a destination ICQ ID concatenated with “@icq.jabber.org”. It is simple like that. Another important advantage of the Jabber protocol is its flexibility. The great level of it is reached by using of XML (Extensible Markup Language) namespace. For example, an instant message generated by a client is passed to a server and then further to the destination wrapped into XML (see appendix A):

<message id="" to="den@test.net"><subject>SubjectLine</subject><body>MessageBody</body></message>

The only information the server needs to know to relay the message is in the “message” tag. Extra information can be passed along using the extension tag with a unique custom namespace identifier:

<message id="" to="den@test.net"><subject>SubjectLine</subject><body>MessageBody</body><x xmlns='jabber:x:say'><phrase>Say it if you can</phrase></x></message>

The new tag may be recognized and processed on the receiving end, or it can be ignored in case the receiving client does not support the functionality required to process the extension.
For more details about the Jabber protocol please refer to [4].

Design Considerations

XUL (XML-based User Interface Language) is a part of Mozilla open source project launched by Netscape. It is a result of an attempt to create a standard platform independent user interface description language. Mozilla itself is an operation environment for the platform independent applications. The standard Mozilla distribution includes a number of the built in multiplatform applications such as an Internet browser, a mail and a chat client. The Mozilla built in multiplatform applications are written and operate using the same means as the ones provided for all other applications. These means are XUL, JavaScript, CSS, XBL and XPCOM. The XUL here is a skeleton of an application, the JavaScript is its brains and the CSS is its decorations. The other components provide some flexibility such as dynamic style changes, custom widgets development and platform dependent code extensions.

A platform independent code running under Mozilla can be either distributed as a package to be installed locally on a user’s workstation or as a network application downloadable on demand. The installable packages have no limits on local resources usage and can be even extended to execute a platform dependent code. The network applications are designed to work in the boundaries of security restrictions. At the same time, the network applications do not require disk space, can be executed on any computer running Mozilla just by referencing a URL and can be upgraded with no end user intervention. The Jabber Client has been developed as a Mozilla network application.

Currently, the latest version of the Mozilla browser is 1.2a Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2a) Gecko/20020910. This is the Mozilla version the Jabber Client has been developed and tested for. The latest Muse Java API (version 0.8a1) has been used to provide a set of methods to perform conventional Jabber Client functions like signing in with a server and sending/receiving messages. The API hides low level details and takes care of chores like connection management, XML messages wrapping and unwrapping. A nice short Muse API overview with examples is presented in [5].

The applet class ‘jcApplet’ has been created to serve as the Jabber Client application main thread and to allow communication and data exchange between JavaScript UI routines and the Muse API. The applet has been developed and tested to work with the Muse API and the JavaScript routines under the Java Development Kit 1.3.1_05, therefore the JRE (Java Runtime Environment) of version 1.3.1_05 is suggested for executing the developed application. Conceptually the components of the Jabber Client application communicate as described on the fig. 1.

 Fig. 1 Jabber Client Application structure

The JRE security does not allow network applications to communicate to servers other than the one the application is downloaded from. This imposes a requirement on the Jabber Client application to be either installed locally or to be downloaded from the Jabber server it is going to connect to, in which case it still fails doing a name resolution. In addition to that, the applet using Muse API has to be provided read access to XML parser properties. The easiest ways to solve the security issue is to either modify the set of permissions for the jcApplet class or sign the applet with a certificate from a trusted certificate authority. The latter is rather expansive, so here is an explanation of how to use the first approach:

// Jabber Client gets permissions to connect resoveand read SAXParser properties
grant codeBase "http://okob.net" {
  permission java.net.SocketPermission "*", "connect, resolve";
  permission java.util.PropertyPermission "com.echomine.jabber.SAXParser", "read";
};
grant codeBase "http://okob.net/jabberc/-" {
  permission java.net.SocketPermission "*", "connect, resolve";
  permission java.util.PropertyPermission "com.echomine.jabber.SAXParser", "read";
};

Note, that these changes affect all users of your system using the same JRE (Java Runtime Environment). If you’d like to modify permissions for individual user account only, try to put these lines to the .java.policy file in the user home directory. It can be quite easily done with help of Java policytool program included in standard set of the JRE executables. 

In order to prove the concept placed to the basement of the Jabber Clint application development, the described application structure has been implemented to perform a simple action of signing in with the Jabber server ‘test.net’ and sending a message to the user test@test.net. The application files were placed in a directory shared by MS IIS server and opened with the Mozilla browser by accessing a URL pointing to the start_me.html file. In order for the Mozilla browser to recognize an XUL application, the IIS was configured to supply the application/vnd.mozilla.xul+xml MIME type for XUL files transferred from the server.

 The simple send message application consisted of three files:

1. http://www.okob.net/jabberc/start_me.html
It contains the onload even handler that start the XUL application.

<!-- This will open Jabber Client window and disappear leaving the client window intact. -->

<HTML>
<HEAD>
</HEAD>
<BODY onload="window.open('jabber.xul','xulex','chrome,centerscreen');
             
window.close();
             
return false;">
<h1>Jabber Client Started</h1>
</BODY>
</HTML>

2. http://www.okob.net/jabberc/jabber.xul
It contains XUL description of a window with two buttons. One is to test the LiveConnect operation (“Say Hello”), and another one is to test the Muse API operation (“Test Muse”).

<?xml version="1.0"?>
<?xml
-stylesheet href="chrome://modern/skin/" type="text/css"?>
<window
 
title="Jabber Client"
 
persist="width height"
 
orient="vertical"
 
xmlns:html="http://www.w3.org/1999/xhtml"
 
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 

  <script>
    
function appletDoneLoading()
    
{
       
document.getElementById('stBarDesc').value = " ";
    
}
 
</script>

  <hbox>
 
<html:applet
     
code="jcApplet.class"
     
name="jcApplet"
     
type="application/x-java-applet;version=1.3.1_05"
     
id="jcApplet"
     
archive="muse/aspectjrt.jar, muse/crimson-1.1.3.jar,
              
muse/jakarta-oro-2.0.4.jar, muse/jaxp-1.1.jar,
              
muse/jdom-b8.jar, muse/junit-3.7.jar,
              
muse/log4j-1.2.6.jar, muse/muse-0.8a1.jar"
     
mayscript="true"
     
height="0"
     
width="0">
 
</html:applet>
 
</hbox>
 
<hbox>
     
<button label="Test Muse"
             
onclick = "document.getElementById('jcApplet').tryJabberApi();"/>
     
<button label="Say Hello"
             
onclick = "document.getElementById('jcApplet').sayHello();"/>
 
</hbox>
 
<hbox>
    
<description id="stBarDesc" value="Loading..."/>
 
</hbox>
</window>

3. http://www.okob.net/jabberc/jcApplet.java
This Java code has to be compiled to the jcApplet.class file.

/* This is applet providing communication for java script to
  
Muse jabber client code. */

import java.awt.*;
import
java.applet.*;
import com.echomine.jabber.*;
import
netscape.javascript.*;

public class jcApplet extends Applet
{
  
public void init()
  
{
     
// Let JS know we are done loading
     
JSObject win = JSObject.getWindow(this);
     
win.eval("appletDoneLoading()");
  
}

   public void sayHello()
  
{
     
Graphics g = getGraphics();
     
String   arg[] = { "This alert is from jcApplet.class" };
     
JSObject win = JSObject.getWindow(this);
     
System.out.println("Hello from Java!");
     
win.call("alert", arg);
  
}

   public void tryJabberApi()
  
{
     
Graphics g = getGraphics();
     
// Initialize the Jabber context
     
JabberContext jabberContext = new JabberContext("test1", "test1",
                                                     
"test.net");
     
// Create an instance of the Jabber session factory
     
Jabber jabber = new Jabber();
     
// Create the new session
     
JabberSession jabberSession = jabber.createSession(jabberContext);
     
try
     
{
        
// Connect to the server
        
jabberSession.connect("test.net", 5222);
        
// Log in to the Jabber server
        
jabberSession.getUserService().login();
        
// Construct test message
        
JabberChatMessage msg = new JabberChatMessage(JabberChatMessage.TYPE_HEADLINE);
        
msg.setSubject("Test Message");
        
msg.setBody("This is a test message from jcApplet");
        
msg.setTo("test@test.net");
        
// Send the message
        
jabberSession.sendMessage(msg);
     
}

      catch (Exception e)
     
{
        
System.out.println(e);
     
}

      return;
 
  }
}

Jabber Client User interface

Developing network applications puts lots of restrictions on the applications and their UI design. Some of the restrictions encountered during the Jabber Client development were:

In order to avoid issues related to the mentioned above restrictions the Jabber client was developed as a one-window application. Tabs were used instead of the menu and provided functionality similar to the one that can be achieved by having multiple windows and dialog boxes. Only basic Mozilla features were used.

The Jabber client application provides the following functionality:

To perform each of the mentioned operations the client has a separate tab panel.

Fig. 1 Login/Logout tab

The fig.1 shows user login/logout tab. User has to enter his/her Jabber ID, specify resource if desired, type in password and either press Enter or click “LogIn” button to log in. The Roster and Messages tabs will appear, LogIn button will be disabled, LogOut button will be enabled and status string will change if operation completed successfully (fig.2). Otherwise an alert box identifying error will be displayed.

Fig. 2 Login/Logout tab after logging in

The fig.3 shows Account tab. The tab’s outlook changes depending on either a user is logged in or not. Before user logs in the tab can be used to create a new account. After logging in it can be used only to change current user password. The fig.3 shows the tab before and after logging in.

The roster provides Jabber users with functionality similar to an address book. The roster contains JIDs (Jabber Identifiers) of people user communicates to. The information is stored on the Jabber server and it is retrieved by the Jabber client after a successful login. The roster functionality is tightly bound to functionality called presence. The latter allows a user to subscribe with Jabber server to receive presence notifications for some JIDs. The result of such subscription would be exchange of subscriber and subscribed users with their JIDs and placing them into each other’s roster (after the subscription is granted). The user subscribed to receive presence notifications of another user receives messages informing either the subject of the subscription is offline, online, available …

Fig. 3 Account tab before and after logging in

The fig.4 shows the Jabber client’s roster tab. The tab displays roster contacts and contacts’ current presence. At the bottom of the window there is an input box allowing user to enter new contact JID. The two checkboxes below control how the client responds to subscription requests from other users. If only the topmost one is checked, only contact JID specified in the input box is allowed to subscribe to the current user presence, (in the most cases a contact user adds to roster also subscribes for the user’s presence). By default, the Jabber client allows everybody to subscribe to the logged in user’s presence. It does not imposes any serious threat since all contacts subscribed to the user’s presence are automatically added to the user’s roster and the subscription can be terminated by simple removing those contacts from roster. If user selects a contact in the roster list the contact’s JID is placed in the contact JID input textbox on the roster tab and to the “Send To” field of the messages tab (fig.5).

Fig. 4 Roster tab

The messages tab mostly consists of the message display area (fig.5). The new messages appear in the area’s topmost line. Each message is preceded by time the message was received/send and the username part of sender’s JID. The messages the client sends are also displayed here. The messages tab also features destination address input box where user can type a JID to send messages to. The JID selected in roster is automatically placed in the box. Below the “Send To” input box there is a one line input box for message text. The message entered is sent to destination when user presses enter or clicks on the “Send” button. The “Clear Received” button clears the message output window.

Fig. 5 Messages tab

Jabber Client Operation and Execution Flow

In order to start the Jabber Client application user must open the start_me.html file with the Mozilla browser. The file contains an onload JavaScript handler that opens a new window and loads the jabber.xul file telling the Mozilla that the file should be loaded as a standalone network application. The window with the start_me.html file is closed after that. The jabber.xul file can also be loaded directly by referring to its URL, but the application will run inside a Mozilla browser window in this case.

Upon loading the jabber.xul file creates initial user interface view and waits for the Java applet classes to load. After the Java applet is loaded it calls setStatusStr() method, which in turn uses the LiveConnect to call the JavaScript updateStatusStr() function to change the status string to “Done loading…” (see fig.1 and Appendix B). The application behavior is the best to be represented as event diagram for each of the application tabs. Fig.7 explains actions taken for events related to logging in and out. The initial state is identified by the bold border.

 

Fig. 7 Log in/out processing

The fig.8 describes behavior of the Account tab. The account tab provides user with a way to create a new account on a jabber server and to change password of an existent account. The new account creation is allowed only if used is not logged in. Quite opposite, the password change operation require user to be logged in and changes password only for account the user currently logged in for. The JavaScript function processSignOut(), and Java methods processSignOut() and signIn() are responsible for enabling and disabling user interface components of both login/out and account tab.

 

Fig. 8 Accounting tab operations

The fig.9 shows an event diagram for the Roster tab. The Roster tab is only available if client is in the logged in state. All the Roster operations are done through a Jabber server. For example, adding an item to the roster requires sending a request to server, and updating the roster displayed to user after the server processes the add request and sends the client a message containing an updated roster. The Roster tab is also affected by presence messages. When a presence status message is received the Jabber client updates the presence status for a roster contact specified in the message.

Fig. 9 Roster tab operations

The “Contact JID” and the subscription checkboxes elements of the Roster tab UI are used to control processing of presence subscription requests. The elements have an onchange handler, which changes properties of the jcApplet Java class representing state of these elements.

The Messages tab is small but the most significant part of the Jabber client. Jabber is an instant messaging service and therefore the tab looks like UI of the majority of chat clients. It has a multi-line read-only textbox where incoming and outgoing messages are displayed, an input box for outgoing message destination address and an input box for outgoing message itself. A message is sent to a destination when user either clicks on the send button or presses Enter in the outgoing message input box. The fig. 10 shows an event diagram for the Messages tab related events.

Fig. 10 Messages tab operations

For further details please refer to the JavaScript, Java and XUL code (Appendix B). For the Jabber protocol data exchange logs please refer to the Appendix A.

Conclusion

The fact that although simple but functional Jabber client has been developed using the XUL, JavaScript and Java combination shows the waste possibilities the Mozilla network application development environment has for both users and developers. The boundaries between conventional and network applications are becoming thinner, technologies merge and learn to “understand” each other, but although very promising the complex multiplatform network application environment like Mozilla requires lots of work and “fine tuning” to become a reliable, convenient and easy to use tool.

The Jabber is an emerging standard that may have a great future. Its advantages are easily noticeable. It is an open standard, it has truly network design, it is extensible and it already provides gateways for existent proprietary instant messaging services. Eventually, unless something better is invented, Jabber should win the majority of the instant messaging fans and become a standard de facto.

References

  1. XUL Tutorial, http://www.xulplanet.com/tutorials/xultu/

  2. Java Script Reference, http://developer.netscape.com/docs/manuals/communicator/jsref/refix.htm

  3. Live Connect, http://wp.netscape.com/eng/mozilla/3.0/handbook/javascript/livecon.htm

  4. Jabber Software Foundation, http://www.jabber.org/

  5. Jabber away with instant messaging, http://www.javaworld.com/javaworld/jw-07-2002/jw-0726-im.html

  6. Echomine Muse 0.8a1 API, http://www.echomine.org/projects/muse/javadocs/

  7. Exodus – Escape From Proprietary Instant Messaging, http://exodus.jabberstudio.org/

Appendix A

XML debug log for signing on with server test.net of new user test3@test.net

# Session setup

SENT: <stream:stream to="test.net" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
RECV: <?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' id='3D9F417F' xmlns='jabber:client' from='test.net'>

# Sending authentication request

SENT: <iq id="jcl_19" type="get"><query xmlns="jabber:iq:auth"><username>test3</username></query></iq>
RECV: <iq id='jcl_19' type='error'><query xmlns='jabber:iq:auth'><username>test3</username></query><error code='401'>Unauthorized</error></iq>

# Authentication failed, sending new user registration request

SENT: <iq id="jcl_20" type="set"><query xmlns="jabber:iq:register"><username>test3</username><password>test3</password></query></iq>
RECV: <iq id='jcl_20' type='result'/>

# Registration succeeded, sending authentication request

SENT: <iq id="jcl_21" type="get"><query xmlns="jabber:iq:auth"><username>test3</username></query></iq>
RECV: <iq id='jcl_21' type='result'><query xmlns='jabber:iq:auth'><username>test3</username><password/><digest/><resource/></query></iq>

SENT: <iq id="jcl_22" type="set"><query xmlns="jabber:iq:auth"><username>test3</username><resource>Home</resource><digest>cd7deba532cab0e667cc1306a4ed46146d6d9444</digest></query></iq>

RECV: <iq id='jcl_22' type='result'/>

# Authentication succeeded, sending request for account data and our presence status update

SENT: <iq id="jcl_23" type="get"><query xmlns="jabber:iq:roster"/></iq>
SENT: <iq id="jcl_24" type="get"><query xmlns="jabber:iq:private"><bookmarks xmlns="storage:bookmarks"/></query></iq>
SENT: <presence><status>available</status><priority>0</priority></presence>
SENT: <iq id="jcl_25" to="test.net" type="get"><query xmlns="jabber:iq:agents"/></iq>
SENT: <iq id="jcl_26" type="get"><query xmlns="jabber:iq:private"><storage xmlns="storage:imprefs"/></query></iq>

RECV: <iq id='jcl_23' type='result' from='test3@test.net/Home'><query xmlns='jabber:iq:roster'/></iq>
RECV: <iq id='jcl_24' type='result' from='test3@test.net/Home'><query xmlns='jabber:iq:private'><bookmarks xmlns='storage:bookmarks'/></query></iq>
RECV: <message from='test.net' to='test3@test.net'> <subject>Hello!</subject><body>Welcome to the Denis&apos;s Jabber server at test.net. The server has been installed for development purposes. For information about how to use Jabber, visit the Jabber User&apos;s Guide at http://docs.jabber.org/</body><x xmlns='jabber:x:delay' from='test3@test.net' stamp='20021005T19:46:10'>Offline Storage</x></message>
RECV: <iq id='jcl_25' to='test3@test.net/Home' type='result' from='test.net'><query xmlns='jabber:iq:agents'><agent jid='users.jabber.org'><name>Jabber User Directory</name><service>jud</service><search/><register/></agent></query></iq><iq id='jcl_26' type='result' from='test3@test.net/Home'><query xmlns='jabber:iq:private'><storage xmlns='storage:imprefs'/></query></iq>

XML debug log for signing on with server test.net of existent user test@test.net

# Session setup

SENT: <stream:stream to="test.net" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
RECV: <?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' id='3D8E4E26' xmlns='jabber:client' from='test.net'>

# Sending authentication request

SENT: <iq id="jcl_1" type="get"><query xmlns="jabber:iq:auth"><username>test</username></query></iq>
RECV: <iq id='jcl_1' type='result'><query xmlns='jabber:iq:auth'><username>test</username><password/><digest/><resource/></query></iq>

SENT: <iq id="jcl_2" type="set"><query xmlns="jabber:iq:auth"><username>test</username><resource>Home</resource><digest>0bcfb17160e70bc0f2e7e93354bece206e3d61d1</digest></query></iq>

RECV: <iq id='jcl_2' type='result'/>

# Authentication succeeded, sending request for account data, updating presence status

SENT: <iq id="jcl_3" type="get"><query xmlns="jabber:iq:roster"/></iq>
SENT: <iq id="jcl_4" type="get"><query xmlns="jabber:iq:private"><bookmarks xmlns="storage:bookmarks"/></query></iq>
SENT: <presence><status>available</status><priority>0</priority></presence>
SENT: <iq id="jcl_5" to="test.net" type="get"><query xmlns="jabber:iq:agents"/></iq>
SENT: <iq id="jcl_6" type="get"><query xmlns="jabber:iq:private"><storage xmlns="storage:imprefs"/></query></iq>

RECV: <iq id='jcl_3' type='result' from='test@test.net/Home'><query xmlns='jabber:iq:roster'><item jid='denis@test.net' name='denis' subscription='none'><group>My Resources</group></item><item jid='den@test.net' name='den' subscription='none'><group>My Resources</group></item></query></iq>
RECV: <iq id='jcl_4' type='result' from='test@test.net/Home'><query xmlns='jabber:iq:private'><bookmarks xmlns='storage:bookmarks'/></query></iq>
RECV: <iq id='jcl_5' to='test@test.net/Home' type='result' from='test.net'><query xmlns='jabber:iq:agents'><agent jid='users.jabber.org'><name>Jabber User Directory</name><service>jud</service><search/><register/></agent></query></iq><iq id='jcl_6' type='result' from='test@test.net/Home'><query xmlns='jabber:iq:private'><storage xmlns='storage:imprefs'/></query></iq>

XML debug log for adding user den@test.net to the roster of test1@test.net

# Session is already set up, sending request to add item to roster

SENT: <iq id="jcl_9" type="set"><query xmlns="jabber:iq:roster"><item jid="den@test.net" name="den"/></query></iq>
RECV: <iq type='set'><query xmlns='jabber:iq:roster'><item jid='den@test.net' name='den' subscription='none'/></query></iq>
RECV: <iq id='jcl_9' type='result' from='test1@test.net/Home' to='test1@test.net/Home'/>

# Sending request to subscribe new contact’s presence of the

SENT: <presence to="den@test.net" type="subscribe"/>
RECV: <iq type='set'><query xmlns='jabber:iq:roster'><item jid='den@test.net' name='den' subscription='none' ask='subscribe'/></query></iq>

# Receiving presence subscription confirmation

RECV: <presence to='test1@test.net' type='subscribed' from='den@test.net'/>

# Receiving updated roster

RECV: <iq type='set'><query xmlns='jabber:iq:roster'><item jid='den@test.net' name='den' subscription='to'/></query></iq><presence from='den@test.net/Home' to='test1@test.net'><status>available</status><priority>0</priority><x xmlns='jabber:x:delay' from='den@test.net/Home' stamp='20020923T00:25:59'/><x xmlns='jabber:x:delay' from='den@test.net/Home' stamp='20020923T00:25:59'/></presence>

XML debug log for receiving a subscription request from user denis@test.net

RECV: <presence to='test1@test.net' type='subscribe' from='denis@test.net'/>
SENT: <presence to="denis@test.net" type="subscribed"/>

RECV: <iq type='set'><query xmlns='jabber:iq:roster'><item jid='denis@test.net' subscription='from'/></query></iq>

XML debug log for sending message to user den@test.net

SENT: <message id="" to="den@test.net"><subject>SubjectLine</subject><body>MessageBody</body></message>

XML debug log for receiving a message from user denis@test.net

RECV: <message id='' to='test1@test.net' from='denis@test.net/Home'><subject>MsgSubj</subject><body>MsgText</body></message>

Appendix B

Jabber Client Directory/File Structure

The Jabber client application is placed under jubberc directory of test.net web site. Under the directory there are 6 files. The start_me.html file is used to start the Jabber client application. The jabber.xul and all .class files are the core of the jabber client. The jcApplet.java is the source code of the Java class files. Unfortunately placing the client’s JavaScript code into separate file creates problems therefore all the JavaScript code resides in the jabber.xul file. The muse directory under jabberc contains all Muse API Java classes.

Application startup code (start_me.html)

<!-- This will open Jabber Client window and disappear leaving the client 
window intact. -->
<HTML>
<HEAD>
</HEAD>
<BODY onload="window.open('jabber.xul','xulex','chrome,centerscreen');
window.close();
return false;">
<h1>Jabber Client Started</h1>
</BODY>
</HTML>

User interface file (jabber.xul)

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://modern/skin/" type="text/css"?>
 
<window
title="Jabber Client"
persist="width height"
orient="vertical"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
<script>
/* Java script functions. Live connect does not seem to work
if they placed in separate file. */
 
/* Functions */
// Called by applet to set status string
function updateStatusStr(str)
{
// Can't call Java from here
document.getElementById('stBarDesc').value = str.toString();
}
function updateStatusStr2(str)
{
document.getElementById('stBarDesc2').value = str.toString();
}
// Passes parameters to Java sign in method
function signIn()
{
if(document.getElementById('signInButton').disabled)
{
return;
}
usr = document.getElementById('usr').value;
pwd = document.getElementById('pwd').value;
srv = document.getElementById('srv').value;
res = document.getElementById('res').value;
port = document.getElementById('port').value;
if(usr.length == 0)
{
alert("Please specify user name");
return;
}
if(srv.length == 0)
{
alert("Please specify server");
return;
}
document.getElementById('jcApplet').signIn(usr, pwd, srv, res, port);
setChkboxVars();
}
// Checks status and calls signOut Java method
function signOut()
{
if(document.getElementById('signOutButton').disabled)
{
return;
}
document.getElementById('jcApplet').signOut();
}
// Passes parameters to Java register method
function Register()
{
if(document.getElementById('registerButton').disabled)
{
return;
}
usr = document.getElementById('ausr').value;
pwd = document.getElementById('apwd').value;
pwd1 = document.getElementById('apwd1').value;
srv = document.getElementById('asrv').value;
port = document.getElementById('aport').value;
if(usr.length == 0)
{
alert("Please specify user name");
return;
}
if(srv.length == 0)
{
alert("Please specify server");
return;
}
if(pwd != pwd1)
{
alert("Passwords do not match");
return;
}
document.getElementById('jcApplet').register(usr, pwd, srv, port);
document.getElementById('apwd').value='';
document.getElementById('apwd1').value='';
}
// Passes parameters to Java chpass method
function chPass()
{
if(document.getElementById('chpassButton').disabled)
{
return;
}
pwd = document.getElementById('apwd').value;
pwd1 = document.getElementById('apwd1').value;
document.getElementById('jcApplet').chpwd(pwd);
document.getElementById('apwd').value = '';
document.getElementById('apwd1').value = '';
}
// Handles req to add an item to roster
function addToRosterReq()
{
cont = document.getElementById('cont').value;
if(cont.length == 0)
{
alert("Please specify contact JID");
return;
}
document.getElementById('jcApplet').addToRosterReq(cont);
}
// Adds a record to roster view
function addToRoster(jidstr, subs)
{
  delFromRoster(jidstr);
var chld = document.getElementById('rtree');
var titem = document.createElement('treeitem');
var trow = document.createElement('treerow');
var jidc = document.createElement('treecell');
var presc = document.createElement('treecell');
titem.setAttribute('id',jidstr);
jidc.setAttribute('label',jidstr);
presc.setAttribute('id', "presence_"+jidstr);
presc.setAttribute('label', subs);
trow.appendChild(jidc);
trow.appendChild(presc);
titem.appendChild(trow);
chld.appendChild(titem);
}
// Puts selected roster JID into textbox
function treeitemIntoHolder()
{
var tree = document.getElementById('roster');
var chld = document.getElementById('rtree');
var tbox = document.getElementById('cont');
var item = chld.childNodes[tree.currentIndex];
var tbox1 = document.getElementById('sndto');
tbox.value = item.id;
tbox1.value = item.id;
setChkboxVars();
}
// Handles req to remove an item from roster
function removeFromRosterReq()
{
cont = document.getElementById('cont').value;
if(cont.length == 0)
{
alert("Please specify contact JID");
return;
}
document.getElementById('jcApplet').removeFromRosterReq(cont);
}
// Removes a record from roster view
function delFromRoster(jidstr)
{
var chld = document.getElementById('rtree');
var rmitem = document.getElementById(jidstr);
if(rmitem != null)
{
chld.removeChild(rmitem);
}
}
// Removes all records from roster view
function clearRoster()
{
var chld = document.getElementById('rtree');
while( chld.lastChild != null )
{
chld.removeChild(chld.firstChild);
}
}
// Sets presence for specified JID in roster view
function setPresence(pjid, prStr)
{
var pitemid = "presence_" + pjid;
var item = document.getElementById(pitemid);
if(item != null)
{
item.setAttribute('label', prStr);
}
}
// Processes signing out
function processSignOut()
{
    clearRoster();
document.getElementById('ausr').readonly=0;
document.getElementById('ausr').value='';
document.getElementById('asrv').readonly=0;
document.getElementById('aport').readonly=0;
document.getElementById('signInButton').disabled=0;
document.getElementById('signOutButton').disabled=1;
document.getElementById('registerButton').disabled=0;
document.getElementById('chpassButton').disabled=1;
document.getElementById('rosterTab').collapsed=1;
document.getElementById('messagesTab').collapsed=1;
document.getElementById('pwd').value='';
document.getElementById('rcvmsg').value='';
}
// Process changes to checkboxes
function setChkboxVars()
{
cont = document.getElementById('cont').value;
allow = document.getElementById('subscribe').checked;
allowall = document.getElementById('subscribeall').checked;
document.getElementById('jcApplet').setChkboxVars(allow, cont, allowall);
}
// Adds message to message output window
function showMsg(jid, msg)
{
curmsgs = document.getElementById('rcvmsg').value;
today = new Date();
idx = jid.indexOf('@');
if(idx != -1)
     {
jid = jid.substr(0, idx);
}
newmsgs = '['+today.getHours()+':'+today.getMinutes()+':'+today.getSeconds()+
' '+jid+']: '+msg+'\n'+curmsgs;
if(newmsgs.length > 2500)
{
newmsgs = newmsgs.substr(0, 2000);
idx = newmsgs.lastIndexOf('\n');
newmsgs = newmsgs.substr(0, idx)+'...';
}
document.getElementById('rcvmsg').value = newmsgs;
}
// Sends a message
function sendMsg(tojid, msg)
   {
var msg = document.getElementById('msg').value;
var tojid = document.getElementById('sndto').value;
if(tojid.length == 0 || tojid.indexOf('@')==-1)
{
alert('Please pick a destination address from roster');
         return;
}
var myname = document.getElementById('ausr').value;
ret = document.getElementById('jcApplet').sendMsg(tojid, msg);
if(ret != false)
{
showMsg(myname, msg);
}
}
</script>
 
<hbox>
<html:applet
code="jcApplet.class"
name="jcApplet"
type="application/x-java-applet;version=1.3.1_05"
id="jcApplet"
archive="muse/aspectjrt.jar, muse/crimson-1.1.3.jar,
muse/jakarta-oro-2.0.4.jar, muse/jaxp-1.1.jar,
muse/jdom-b8.jar, muse/junit-3.7.jar,
muse/log4j-1.2.6.jar, muse/muse-0.8a1.jar"
mayscript="true"
height="0"
width="0">
</html:applet>
</hbox>
<command id="checkboxes" oncommand="setChkboxVars();"/>
<hbox debug="false">
 
<tabbox>
 
<tabs>
<tab label="LogIn/Out"/>
<tab label="Account"/>
<tab label="Roster" id="rosterTab" collapsed="true"/>
<tab label="Messages" id="messagesTab" collapsed="true"/>
</tabs>
 
<tabpanels>
 
<tabpanel id="tab_sign" debug="false">
<vbox flex="10">
<groupbox>
<grid flex="1">
<columns>
<column flex="1"/>
<column flex="1"/>
</columns>
<rows>
<row>
<label control="jidl" value="UserJID:"/>
<hbox align="start">
<textbox id="usr" flex="0" style="width: 7em;"/><label
        value="@" style="width: 1em;"/><textbox id="srv" flex="0"
value="jabber.org" style="width: 11em;"/><label value="/"
style="width: 1em;"/><textbox id="res" flex="0"
style="width: 5em;"/>
</hbox>
</row>
<row>
<label control="pwdl" value="Password:"/>
<hbox align="start">
<textbox id="pwd" type="password" flex="0"
onkeypress="if(event.keyCode==13) signIn();"
style="width: 26em;"/>
</hbox>
</row>
<row>
<hbox/>
<hbox align="start" flex="0">
<label control="portl" value="Port:"/><textbox
id="port" flex="0" value="5222" style="width: 5em;"/>
</hbox>
</row>
<row>
<hbox/>
<hbox align="start">
                 <checkbox id="invisible" label="Invisible" disabled="1" flex="0"/>
</hbox>
</row>
</rows>
</grid>
<hbox align="end">
<spacer flex="3"/>
<button id="signInButton" label="LogIn" flex="0"
onclick = "signIn();"/>
<spacer flex="1"/>
<button id="signOutButton" label="LogOut" flex="0" disabled="true"
onclick = "signOut(); processSignOut();"/>
<spacer flex="3"/>
</hbox>
</groupbox>
<spacer flex="10"/>
</vbox>
</tabpanel>
 
<tabpanel id="tab_acct">
<vbox flex="10">
<groupbox>
<grid flex="1">
<columns>
<column flex="1"/>
<column flex="1"/>
</columns>
<rows>
<row>
<label control="jidl" value="User:"/>
<hbox align="start">
<textbox id="ausr" style="width: 9em;"/><label
value="@" style="width: 1em;"/><textbox id="asrv"
value="jabber.org" style="width: 14em;"/>
</hbox>
</row>
<row>
<label control="apwd" value="Password:"/>
<hbox align="start">
<textbox id="apwd" type="password" style="width: 24em;"/>
</hbox>
</row>
          <row>
<label control="apwdl" value="Confirm Password:"/>
<hbox align="start">
<textbox id="apwd1" type="password" flex="0" style="width: 24em;"/>
</hbox>
</row>
<row>
<hbox/>
<hbox align="start">
<label control="portl" value="Port:"/><textbox
id="aport" flex="0" value="5222" style="width: 5em;"/>
</hbox>
</row>
</rows>
</grid>
<hbox align="end">
<spacer flex="3"/>
<button id="registerButton" label="Register" flex="0"
onclick = "Register();"/>
  <spacer flex="1"/>
<button id="chpassButton" label="Change Password" flex="0" disabled="true"
onclick = "chPass();"/>
<spacer flex="3"/>
</hbox>
</groupbox>
<spacer flex="10"/>
</vbox>
</tabpanel>
 
<tabpanel id="tab_roster" flex="1">
<vbox flex="10">
<hbox flex="10">
<tree seltype="single" hidecolumnpicker="true" style="height: 10em;"
flex="10" id="roster" onselect="treeitemIntoHolder();">
<treecols>
<treecol id="coljid" label="JID" flex="5"/>
<treecol id="colpres" label="Presence" flex="1"/>
</treecols>
<treechildren id="rtree">
</treechildren>
</tree>
</hbox>
<hbox flex="0">
<label control="jidr" value="Contact JID:"/>
<textbox id="cont" oninput="setChkboxVars()" flex="5"/>
    <!--- <spacer flex="1"/>
<label control="grpr" value="Group:"/>
<textbox id="grp" flex="3"/> -->
</hbox>
<hbox>
<checkbox id="subscribe" checked="false" persist="true"
label="Accept subscribe request from the contact JID"
command="checkboxes" flex="0"/>
</hbox>
<hbox>
<checkbox id="subscribeall" checked="true" persist="true"
label="Accept all subscribe requests"
command="checkboxes" flex="0"/>
</hbox>
<hbox align="end">
<spacer flex="3"/>
<button id="addr" label="Add" flex="0"
onclick = "addToRosterReq();"/>
<spacer flex="1"/>
<button id="remover" label="Remove" flex="0"
onclick = "removeFromRosterReq();"/>
<spacer flex="3"/>
</hbox>
<spacer flex="10"/>
</vbox>
</tabpanel>
 
<tabpanel id="tab_msgs">
<vbox flex="10">
<hbox flex="10">
<textbox id="rcvmsg" multiline="true" readonly="true" wrap="true"
value="No new messages" flex="1" rows="8" cols="80"
style="background-color : white; text-color : black;"/>
</hbox>
<hbox flex="10">
<label control="sndto" value="Send to:"/>
<textbox id="sndto" value="Pick an address from roster" flex="1"/>
</hbox>
    <hbox>
<textbox id="msg" value="Type your message here"
onkeypress="if(event.keyCode == 13) sendMsg();"
rows="1" cols="80" flex="1"/>
</hbox>
<hbox align="end">
<spacer flex="3"/>
<button id="send" label="Send" default="1" flex="0"
onclick = "sendMsg();"/>
<spacer flex="1"/>
<button id="clear" label="Clear Received" flex="0"
onclick = "document.getElementById('rcvmsg').value = '';"/>
<spacer flex="3"/>
</hbox>
<spacer flex="10"/>
</vbox>
</tabpanel>
 
</tabpanels>
 
</tabbox>
 
</hbox>
<hbox>
<description id="stBarDesc" value="Loading..."/>
<description value=" "/>
<description id="stBarDesc2" value=""/>
</hbox>
</window>

Java applet source code (jsApplet.java)

/* This is applet provides communication for java script to
Muse jabber client code. */
 
import java.awt.*;
import java.applet.*;
import java.util.*;
import com.echomine.jabber.*;
import com.echomine.net.*;
import netscape.javascript.*;
 
public class jcApplet extends Applet
{
/* Public properties */
public String statusStr;
public boolean signedIn;
public boolean allowSubscribe;
public boolean allowAllSubscribe;
public String allowSubscribeJid;
/* Class properties */
JSObject win;
Jabber jabber;
JabberContext jabberContext;
JabberSession jabberSession;
JabberRosterService roster;
/* Handlers */
// Connection monitoring
ConnectionListener cMon = new com.echomine.net.ConnectionListener()
{
public void connectionClosed(ConnectionEvent e)
{
System.out.println("connectionClosed");
// If the flag is set assume connedction terminated unexpectedly
if(signedIn)
{
jsAlert("Connection terminated: " + e);
processSignOut();
}
signedIn = false;
setStatusStr("Not signed in");
    return;
}
public void connectionStarting(ConnectionEvent e)
{
System.out.println("connectionStarting");
return;
}
public void connectionEstablished(ConnectionEvent e)
{
System.out.println("connectionEstablished");
return;
}
};
// Message reception handling
JabberMessageListener msgMon = new com.echomine.jabber.JabberMessageListener()
{
public void messageReceived(JabberMessageEvent event)
{
System.out.println("Received msg id="+event.getMessageType());
switch(event.getMessageType())
{
case JabberCode.MSG_CHAT:
System.out.println("Received MSG_CHAT");
JabberChatMessage cmsg = (JabberChatMessage) event.getMessage();
if(cmsg.getType().equals(JabberChatMessage.TYPE_CHAT) ||
cmsg.getType().equals(JabberChatMessage.TYPE_NORMAL))
{
showMessage(cmsg.getFrom(), cmsg.getBody());
            }
break;
case JabberCode.MSG_IQ_ROSTER:
System.out.println("Received MSG_IQ_ROSTER");
RosterIQMessage msg = (RosterIQMessage) event.getMessage();
Iterator items = msg.getRosterItems().iterator();
RosterItem item;
while (items.hasNext())
{
item = (RosterItem) items.next();
System.out.println("[Roster Contact] " + item);
if(item.getSubscription().equals("remove"))
{
delFromRoster(item.getJID());
}
else
{
if(item.getSubscription().equals("to") ||
      item.getSubscription().equals("both"))
{
addToRoster(item.getJID(), "offline");
}
else
{
addToRoster(item.getJID(), "unknown");
}
}
}
break;
case JabberCode.MSG_PRESENCE:
System.out.println("Received MSG_PRESENCE");
System.out.println("PresMsg: "+event.getMessage());
if(jabberSession == null)
{
break;
}
JabberPresenceMessage pmsg = (JabberPresenceMessage) event.getMessage();
if(pmsg.getType().equals(PresenceCode.TYPE_SUBSCRIBE))
{
try
{
if(allowAllSubscribe ||
(allowSubscribe && allowSubscribeJid != null &&
allowSubscribeJid.equals(pmsg.getFrom())))
{
jabberSession.getPresenceService().acceptSubscribe(pmsg);
setStatusStr2("Accepted subscription: "+pmsg.getFrom());
}
              else
{
jabberSession.getPresenceService().denySubscribe(pmsg);
setStatusStr2("Denied subscription: "+pmsg.getFrom());
}
}
      catch (Exception e)
{
System.out.println(e);
}
}
else
{
System.out.println("Setting presence to " + pmsg.getType());
     setPresence(pmsg.getFrom(), pmsg.getType());
}
break;
default:
return;
}
}
};
 
/* Major methods */
// Initializes applet
public void init()
{
// Initialize the applet
win = JSObject.getWindow(this);
signedIn = false;
allowSubscribe = false;
allowAllSubscribe = true;
allowSubscribeJid = null;
jabber = new Jabber();
jabberContext = null;
jabberSession = null;
statusStr = "Done loading, not signed in";
// Let user know we are done loading
setStatusStr(statusStr);
System.out.println("Applet initialized.");
return;
}
 
// Signs a user in
public void signIn(String usr, String pwd, String srv, String res, int port)
{
System.out.println("signIn("+usr+","+pwd+","+srv+","+res+","+port+")");
if(signedIn)
{
jsAlert("You are signed in as " +
jabberContext.getUsername() +
         ", please sign out first.");
return;
}
// Initialize the Jabber context
if(usr.length() == 0)
{
usr = null;
System.out.println("User not set");
}
if(pwd.length() == 0)
{
 pwd = null;
System.out.println("Password not set");
}
if(srv.length() == 0)
{
srv = null;
System.out.println("Server not set");
}
// Create the new session
jabberContext = new JabberContext(usr, pwd, srv);
if(res.length() > 0)
{
jabberContext.setResource(res);
}
jabberSession = jabber.createSession(jabberContext);
try
{
// Connect to the server
jabberSession.connect(srv, port);
     // Add connection event listener
jabberSession.getConnection().addConnectionListener(cMon);
// Log in to the Jabber server
jabberSession.getUserService().login();
jabberSession.addMessageListener(msgMon);
roster = jabberSession.getRosterService();
roster.requestRosterList(true);
jabberSession.getPresenceService().setToAvailable(null,null);
}
catch (Exception e)
{
System.out.println(e);
jsAlert(e.toString());
return;
}
allowSubscribe = false;
allowSubscribeJid = null;
signedIn = true;
win.eval("document.getElementById('ausr').readonly=1;"+
"document.getElementById('ausr').value='"+
jabberContext.getUsername()+"';"+
"document.getElementById('asrv').readonly=1;"+
"document.getElementById('asrv').value='"+
jabberContext.getServerName()+"';"+
"document.getElementById('aport').readonly=1;"+
"document.getElementById('aport').value='"+
jabberSession.getConnection().getConnectionModel().getPort()+"';"+
"document.getElementById('signInButton').disabled=1;"+
"document.getElementById('signOutButton').disabled=0;"+
"document.getElementById('registerButton').disabled=1;"+
"document.getElementById('chpassButton').disabled=0;\n"+
"document.getElementById('rosterTab').collapsed=0;"+
"document.getElementById('messagesTab').collapsed=0;\n");
setStatusStr("Signed in as " + jabberContext.getUsername());
return;
}
 
// Signs a user out
public void signOut()
{
System.out.println("signOut()");
// Disconnect
signedIn = false;
jabberSession.disconnect();
}
 
// Register a new user
public void register(String usr, String pwd, String srv, int port)
{
System.out.println("register("+usr+","+pwd+","+srv+","+port+")");
if(signedIn)
{
jsAlert("You are signed in as " +
jabberContext.getUsername() +
", please sign out first.");
return;
}
if(usr.length() == 0)
{
usr = null;
 System.out.println("User not set");
}
if(pwd.length() == 0)
{
pwd = null;
System.out.println("Password not set");
}
if(srv.length() == 0)
{
srv = null;
System.out.println("Server not set");
}
// Create the new session
jabberContext = new JabberContext(usr, pwd, srv);
jabberSession = jabber.createSession(jabberContext);
try
{
// Connect to the server
jabberSession.connect(srv, port);
// Try to register the new user
HashMap av = new HashMap();
av.put("username", usr);
av.put("password", pwd);
jabberSession.getUserService().register(srv, av);
// Now disconnect
jabberSession.disconnect();
jabberSession = null;
jabberContext = null;
}
catch (Exception e)
{
System.out.println(e);
if(jabberSession != null && jabberSession.getConnection().isConnected())
{
jabberSession.disconnect();
}
jsAlert(e.toString());
return;
}
jsAlert("User "+usr+" has been succefully registerd");
return;
}
 
// Change user's password
public void chpwd(String pwd)
{
System.out.println("chpwd("+pwd+")");
// Change passwd
try
{
jabberSession.getUserService().changePassword(pwd);
}
catch (Exception e)
{
jsAlert(e.toString());
return;
}
jsAlert("Password has been successfully changed");
}
 
// Request to add an item to Roster
public void addToRosterReq(String jid)
{
System.out.println("addRosterReq("+jid+")");
if(!signedIn || roster == null)
{
jsAlert("You are not signed in");
return;
}
if(jid.length() == 0)
{
System.out.println("JID not set");
jsAlert("Please specify JID of the contact to add");
return;
}
try
{
roster.addToRoster(jid, jid, null, false);
jabberSession.getPresenceService().subscribe(jid);
}
catch (Exception e)
{
jsAlert(e.toString());
return;
}
return;
}
 
// Request to remove an item from Roster
public void removeFromRosterReq(String jid)
{
System.out.println("removeFromRosterReq("+jid+")");
if(!signedIn || roster == null)
{
jsAlert("You are not signed in");
return;
}
if(jid.length() == 0)
  {
System.out.println("JID not set");
jsAlert("Please specify JID of the contact to remove");
return;
}
try
{
roster.removeFromRoster(jid, false);
}
catch (Exception e)
{
jsAlert(e.toString());
return;
}
return;
}
 
public void setChkboxVars(boolean allow, String cont, boolean allowall)
{
allowSubscribe = allow;
allowAllSubscribe = allowall;
allowSubscribeJid = cont;
}
 
public boolean sendMsg(String tojid, String msg)
{
System.out.println("sendMsg("+tojid+","+msg+")");
if(!signedIn || tojid.length() == 0 || msg.length() == 0)
{
jsAlert("Please sign in, specify destination address and a message to send");
return false;
}
try
{
jabberSession.getChatService().sendPrivateMessage(tojid, msg);
}
catch (Exception e)
{
jsAlert(e.toString());
return false;
}
return true;
}
 
/* Helper methods */
// Calls JS alert
void jsAlert(String str)
{
String arg[] = { str };
win.call("alert", arg);
return;
}
 
// Sets status string
void setStatusStr(String str)
{
String arg[] = { str };
win.call("updateStatusStr", arg);
return;
}
void setStatusStr2(String str2)
{
String arg[] = { str2 };
win.call("updateStatusStr2", arg);
return;
}
 
// Add an item to roster
void addToRoster(String jid, String subs)
{
String arg[] = { jid, subs };
win.call("addToRoster", arg);
return;
}
 
// Remove an item from roster
void delFromRoster(String jid)
{
String arg[] = { jid };
win.call("delFromRoster", arg);
return;
}
 
// Set presence to an item in roster
void setPresence(String jidstr, String pres)
{
JID jid;
try
{
jid = new JID(jidstr);
}
catch(Exception e)
{
System.out.println("Malformed JID: "+jidstr);
return;
}
String arg[] = { jid.getNode()+"@"+jid.getHost(), pres };
win.call("setPresence", arg);
return;
}
 
// Removes all items from roster view
void clearRoster()
{
String arg[] = {};
win.call("clearRoster", arg);
return;
}
 
// Calls XUL sign out processing
void processSignOut()
{
String arg[] = { };
win.call("processSignOut", arg);
return;
}
 
// Adds message to message output window
void showMessage(String jid, String msg)
{
String arg[] = { jid, msg };
win.call("showMsg", arg);
return;
}
}

Appendix C

Jabber daemon for MS Windows installation instructions

Requirements

Note: The add-on components for groupchat, the Jabber User Directory (JUD), and the gateways to other IM networks have NOT yet been ported to win32 and will NOT run on Windows!

Installation

  1. Install Cygwin.

    • Go to http:/www.cygwin.com and click on the ‘Install now’ icon.
      It will run setup.exe program.

    • In the setup program choose ‘install from Internet’ option and follow the setup instructions.

    • When prompted what packages to install, choose default set of Cygwin packages plus other packages you would like to have.

    • Test the Cygwin installation by running ‘bash’ or any of your favorite applications installed.

  2. Install Jabber daemon.

    • Download and install
      http://jabberd.jabberstudio.org/downloads/JabberD-1.4.2.exe

    • Go to the Jabber installation directory and edit jabber.xml configuration file. See http://jabberd.jabberstudio.org/howto.html#INSTALL-WINDOWS for detailed instructions.

    • If you are behind a firewall make sure your server is reachable from outside world. The usual setup (see configuration file) is to have jabber server listening on 5222, 5223 and 5269 TCP ports. Port 5222 is for client TCP connections. Port 5223 serves SSL encrypted client connections. Port 5269 is present for inter-server communications.

    • Start the Jabber daemon (jabberd.exe).

    • Using Jabber client test the server installation. If you experience problems with user authentication (server returns error 401 for existent users even if specifying correct password), try to comment out line
      <mod_auth_0k>./libs/jsm.dll</mod_auth_0k> in jabber.xml configuration file and restart the daemon.

  3. Enabling SSL for windows version of jabberd (v 1.4.2).

    • Download and extract jabberd source code (the jabberd windows binary is not compiled with SSL support).

    • Run cygwin setup (see step1) and install openssl and openssl-dev packages. Look them up under “Libs” section. Also, install development packages like gcc, binutils, patch e.t.c.

    • Go to the jubberd source code directory and edit ./cygwin/Makefile.jubberd. Change line (should be one line)
      EXTRALIBS=-lpth /lib/crt0.o $(shell gcc -print-libgcc-file-name) -lcygwin -lkernel32
      to (should be one line)
      EXTRALIBS=-L$(shell pth-config --libdir) -lpth /lib/crt0.o $(shell gcc -print-libgcc-file-name) -llibcrypto -llibssl -lcygwin -lkernel32

    • Download and apply patch http://jabberd.jabberstudio.org/downloads/mio_ssl.c.patch

    • Run ./configure –enable-ssl

    • Run ./make

    • Replace your original jubberd.exe file and all your original DLLs with newly build ones. If you’ve installed jubberd binary, all your DLLs should be under libs in your jubberd installation directory.

    • Go to the http://jabberd.jabberstudio.org/faq.html and follow instructions under “1.14. How do I get SSL working with my Jabber server?”