Monday, November 08, 2010 at 12:06 AM.
system.verbs.builtins.tcp.im.builtinDrivers.jabber.code.openConnection
on openConnection ( host = "", username = "", password = "", resource = "", port = "", registrationInfoAdr = "", flCreateNewAccount = true, mustCreateNewAccount = false, loginTimeout = 60*60, connection = nil ) {
<<Changes
<<5/14/02; 1:51:34 PM by JB
<<Changelog created.
<<Jabber framework internal args:
<<mustCreateNewAccount: If true, this invocation will attempt to create a new account. Otherwise, it will try to login to an existing account.
tcp.im.builtinDrivers.jabber.code.init();
if not user.im.jabber.flActive {
scriptError ( "Can't open connection because the Jabber framework is inactive." )};
if defined ( connection^ ) {
if connection^.state != "FAILED LOGIN" { //JES 7/29/02: special case -- we're about to create a new account
scriptError ( "Can't open connection to the Jabber server because it is already active." )}};
bundle { // handle default arguments correctly
// when openConnection is called, we can't be sure jabber.init() has run, so the default arg resolution needs to be delayed. Fortunately, for all other verbs, we know openConnection has been called.
if host == "" {
host = user.im.jabber.host};
if username == "" {
username = user.im.jabber.username};
if password == "" {
password = user.im.jabber.password};
if resource == "" {
resource = user.im.jabber.resource};
if port == "" {
port = user.im.jabber.port};
if registrationInfoAdr == "" {
registrationInfoAdr = @user.im.jabber.registrationInfo};
// and this one is because Frontier/Radio gets upset when the default argument is an address to non-existant value
if connection == nil {
connection = @system.temp.jabber.connection}};
new ( tableType, connection );
bundle { // set up connection information
connection^.username = username;
connection^.host = host;
connection^.resource = resource;
connection^.password = password;
connection^.registrationInfoAdr = registrationInfoAdr;
new (tableType, @connection^.presence)};
connection^.tcpStream = tcp.openStream ( host, port );
connection^.state = "LOGGING IN";
local ( loginSemName = "JabLogin" + nameOf ( connection^ ) );
connection^.loginSemName = loginSemName;
bundle { // write out the stream header
tcp.writeStream ( connection^.tcpStream, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n<stream:stream to=\"");
tcp.writeStream ( connection^.tcpStream, xml.entityEncode(host, true) + "\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\">" )};
if not mustCreateNewAccount {
tcp.im.builtinDrivers.jabber.code.messages.iqAuth ( connection)} // try to login
else {
local ( idTbl = tcp.im.builtinDrivers.jabber.code.idTables.create () ); // need this for the key, according to spec, but nobody uses it?
if not defined (connection^.tcpStream) { //JES 7/29/02: make sure the tcp stream is opened
connection^.tcpStream = tcp.openStream ( host, port )};
try {
tcp.im.builtinDrivers.jabber.code.messages.iqRegisterRequest ( idTbl, connection )} // try to create new account //JES 7/29/02: parameter order was reversed -- swapped back
else { //JES 7/29/02: close the tcp stream, and throw the error up the call stack
tcp.closeStream (connection^.tcpStream);
bundle { //JES 7/29/02: this is a fatal error -- do garbage collection
try {delete (system.temp.connections.[nameOf (connection^)] ) };
try {delete (connection)};
try {delete (idTbl)}};
scriptError (tryError)}};
system.temp.jabber.connections[string(connection)] = true;
try {
semaphore.lock(loginSemName, 60)};
// Comment this line out, and you can run the thread by hand for debugging
thread.callScript (@tcp.im.builtinDrivers.jabber.code.thread, { connection } );
// uncomment this if you comment the thread.easyCall, so you don't stall on the code below
<<return
try {
semaphore.lock(loginSemName, loginTimeout )};
semaphore.unlock(loginSemName);
if not defined ( connection^ ) {
scriptError ("Can't complete logging in to the Jabber server because the connection was terminated before logging in was complete.")};
// see how the login went, do the appropriate thing
case connection^.state {
"LOGGED IN" {
// stuff we do when we log in: send prescense, ask for server version, get roster
local ( rosterRequestId = tcp.im.builtinDrivers.jabber.code.idTables.create(), versionRequestId = tcp.im.builtinDrivers.jabber.code.idTables.create() );
tcp.im.builtinDrivers.jabber.code.messages.presence(type: "available", status: "Online", priority: 0, connection: connection);
tcp.im.builtinDrivers.jabber.code.messages.iqRosterRequest(connection: connection, idTbl: rosterRequestId);
tcp.im.builtinDrivers.jabber.code.messages.iqVersionRequest(connection: connection, dest: connection^.host, idTbl: versionRequestId);
try {
tcp.im.builtinDrivers.jabber.code.waitForIqReply(rosterRequestId);
tcp.im.builtinDrivers.jabber.code.waitForIqReply(versionRequestId)}
else {
tcp.im.builtinDrivers.jabber.code.closeConnection(connection);
scriptError ( "Can't login to Jabber server because the login attempt timed out." )};
if connection == @system.temp.jabber.connection {
user.scheduler.everyMinute.jabber = @tcp.im.builtinDrivers.jabber.code.everyMinute};
return true};
"LOGGING IN" { // evidently, things timed out
tcp.im.builtinDrivers.jabber.code.closeConnection(connection);
scriptError ( "Can't login to Jabber server because the login attempt timed out." )};
"FAILED LOGIN" {
if flCreateNewAccount and not mustCreateNewAccount { // no account exists, close the stream and create the new account
return tcp.im.builtinDrivers.jabber.code.openConnection ( host: host, username: username, password: "", resource: resource, port: port, registrationInfoAdr: registrationInfoAdr, flCreateNewAccount: flCreateNewAccount, mustCreateNewAccount: true, connection: connection )}
else {
tcp.im.builtinDrivers.jabber.code.closeConnection(connection);
scriptError ( "Can't login to Jabber server because your account information is incorrect. (Most likely either a wrong password, or an unregistered account on a server not accepting new accounts.)" )}};
"ACCOUNT CREATED" { // an account was created, now close the stream and re-open with the new account
tcp.im.builtinDrivers.jabber.code.closeConnection(connection);
return tcp.im.builtinDrivers.jabber.code.openConnection ( host: host, username: username, password: "", resource: resource, port: port, registrationInfoAdr: registrationInfoAdr, connection: connection)}}};
bundle { //test code
openConnection ( )}
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.