Jump to content

wodXMPP & Autoit


 Share

Recommended Posts

Well, i found a wonderful COM object type system to allow quick access to jabber, and do what is necessary; wodXMPP from: http://www.weonlydo.com/index.asp?showform=XMPP

There is a 30 day demo: http://www.weonlydo.com/Samples/wodXMPP.exe

You will need to download/install that, so that you can help me, i hope, with my code here:

#include <Inet.au3>
#include<String.au3>
$xmpp = ObjCreate("WeOnlyDo.wodXMPPCom.1")
If IsObj($xmpp) Then
    ConsoleWrite("Object created" & @CRLF)
    $oMyError = ObjEvent("AutoIt.Error","MyErrFunc")    ; Initialize a COM error handler
Else
    ConsoleWrite("Object Failed" & @CRLF)
    Exit
EndIf
$gui = GUICreate("XMPP", 100, 100, -1, -1)
GUISetState()

$xmpp.Login = "testautoit@jabber.org/techchat"
$xmpp.Password = "testing"
$xmpp.Authentication = 0
$xmpp.Security = 2
$xmpp.Connect
ConsoleWrite("Connecting to: " & $xmpp.Login & @CRLF)
$tst = getStatus($xmpp.State)
ConsoleWrite($tst & @CRLF)

While $xmpp.State <> 5
    $tst = getStatus($xmpp.State)
    ConsoleWrite(@HOUR & ":" & @MIN & ":" & @SEC & ": " & $tst & @CRLF)
    Sleep(100)
WEnd
$tst = getStatus($xmpp.State)
ConsoleWrite($tst & @CRLF)
If $tst <> "Connected!" Then
    MsgBox(0, "ERROR", "Not connected to server:  " & getStatus($xmpp.State))
    Exit
EndIf

$message = ObjCreate("WeOnlyDo.XMPPMessage")
$message.Text = "This is a test"
$xmpp.SendMessage("testautoit@jabber.org", $message)


While 1
    $nmsg = GUIGetMsg()
    Switch $nmsg
        Case - 3
            Exit
    EndSwitch
WEnd

Func getStatus($code)
    Switch $xmpp.State
        Case 0
            Return "Disconnected"
        Case 1
            Return "Connecting"
        Case 2
            Return "Registering user"
        Case 3
            Return "Init Secure Connection"
        Case 4
            Return "Sending Auth Data"
        Case 5
            Return "Connected!"
        Case 6
            Return "RX data"
        Case 7
            Return "TX data"
        Case 8
            Return "Execute Command"
        Case 9
            Return "Disconnecting"
        Case 10
            Return "Resolving"
    EndSwitch
EndFunc   ;==>getStatus

Func MyErrFunc()

  Msgbox(0,"AutoItCOM Test","We intercepted a COM Error !"      & @CRLF  & @CRLF & _
             "err.description is: "    & @TAB & $oMyError.description    & @CRLF & _
             "err.windescription:"     & @TAB & $oMyError.windescription & @CRLF & _
             "err.number is: "         & @TAB & hex($oMyError.number,8)  & @CRLF & _
             "err.lastdllerror is: "   & @TAB & $oMyError.lastdllerror   & @CRLF & _
             "err.scriptline is: "     & @TAB & $oMyError.scriptline     & @CRLF & _
             "err.source is: "         & @TAB & $oMyError.source         & @CRLF & _
             "err.helpfile is: "       & @TAB & $oMyError.helpfile       & @CRLF & _
             "err.helpcontext is: "    & @TAB & $oMyError.helpcontext _
            )

    Local $err = $oMyError.number
    If $err = 0 Then $err = -1

    $g_eventerror = $err  ; to check for after this function returns
Endfunc

When looking at the SendMessage information in the wodXMPP help file, i get:

Description

Sends message to some JID.

Return Type

None

Syntax

object.SendMessage JID, Message

The SendMessage Method syntax has these parts:

Part Description

object An expression evaluating to an object of type wodXMPP.

JID Required. A String value. Determines which JID will message be sent to.

Message Required. A XMPPMessage object. A reference to wodXMPPMessage object which will be sent.

Remarks

Sends message (through wodXMPPMessage object) to the user specified by JID parameter. Message parameter in this case isn't a String value containing the text you wish to send, but a reference to wodXMPPMessage object.

If you wish wodXMPP to create wodXMPPMessage object automatically, you should use SendText method.

But, whenever I call it that way, i get a type mismatch, I did try to look it up via the OLEview:

void SendMessage(

BSTR JID,

IXMPPMessage* Message);

Which to me, means u use the format:

$xmpp.SendMessage("testautoit@jabber.org/techchat", $message)

But that gives me a type mismatch error.

This is rather frustrating, can someone help?

Edited by zackrspv

-_-------__--_-_-____---_-_--_-__-__-_ ^^€ñ†®øÞÿ ë×阮§ wï†høµ† ƒë@®, wï†høµ† †ïmë, @ñd wï†høµ† @ †ïmïdï†ÿ ƒø® !ïƒë. €×阮 ñø†, bµ† ïñ§†ë@d wï†hïñ, ñ@ÿ, †h®øµghøµ† †hë 맧ëñ§ë øƒ !ïƒë.

Link to comment
Share on other sites

Getting closer, but not by much. I'm able to connect to the server, and actually listen for some events, but many of the events dont parse right.

I could REALLLLY use some help with this :/ I need to be able to join chat rooms, send messages, *sighs*

#include <Inet.au3>
#include<String.au3>
$xmpp = ObjCreate("WeOnlyDo.wodXMPP.1")
If IsObj($xmpp) Then
    ConsoleWrite("Object created" & @CRLF)
    $SinkObject = ObjEvent($xmpp, "IwodXMPPNotify_") ; Assign events to UDFs starting with IEEvent_
    $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc") ; Initialize a COM error handler


Else
    ConsoleWrite("Object Failed" & @CRLF)
    Exit
EndIf
$Form1 = GUICreate("Form1", 625, 445, 192, 124)
GUISetState()
$xmpp.Login = "testautoit@jabber.org/techchat"
$xmpp.Password = "testing"
$xmpp.Authentication = 0
$xmpp.Security = 2
$xmpp.Connect
ConsoleWrite("Connecting to: " & $xmpp.Login & @CRLF)
While $xmpp.State <> 5
    Sleep(100)
WEnd
If $xmpp.State <> 5 Then
    MsgBox(0, "ERROR", "Not connected to server:  " & getStatus($xmpp.State))
    Exit
EndIf


$message = ObjCreate("WeOnlyDo.XMPPMessage")
If Not IsObj($message) Then ConsoleWrite("Nope" & @CRLF)
$message.Text = "This is a test: "
$message.Type = 1
$xmpp.SendMessage("testautoit@jabber.org/techchat", $message)

While 1
    $nmsg = GUIGetMsg()
    Switch $nmsg
        Case - 3
            Exit
    EndSwitch
WEnd

Func getStatus($code)
    Switch $xmpp.State
        Case 0
            Return "Disconnected"
        Case 1
            Return "Connecting"
        Case 2
            Return "Registering user"
        Case 3
            Return "Init Secure Connection"
        Case 4
            Return "Sending Auth Data"
        Case 5
            Return "Connected!"
        Case 6
            Return "RX data"
        Case 7
            Return "TX data"
        Case 8
            Return "Execute Command"
        Case 9
            Return "Disconnecting"
        Case 10
            Return "Resolving"
    EndSwitch
EndFunc   ;==>getStatus

Func IwodXMPPNotify_IncomingMessage($contact, $message)
    If IsObj($contact) Then ConsoleWrite("Contact object" & @CRLF)
    If IsObj($message) Then ConsoleWrite("Message object" & @CRLF)
    ConsoleWrite("------- MESSAGE ---------" & @CRLF)

EndFunc   ;==>IwodXMPPNotify_IncomingMessage
Func IwodXMPPNotify_IncomingNotification()
    ConsoleWrite("------- notify ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_IncomingNotification
Func IwodXMPPNotify_Pong()
    ConsoleWrite("------- Pong ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_Pong
Func IwodXMPPNotify_StateChange()
    ConsoleWrite("[" & @HOUR & ":" & @MIN & ":" & @SEC & "]  " & getStatus($xmpp.State) & @CRLF)
EndFunc   ;==>IwodXMPPNotify_StateChange
Func IwodXMPPNotify_VCardDetails()
    ConsoleWrite("------- vcardDetails ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_VCardDetails
Func IwodXMPPNotify_Connected()
    ConsoleWrite("------- IwodXMPPNotify_Connected ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_Connected
Func IwodXMPPNotify_Disconnected()
    ConsoleWrite("------- IwodXMPPNotify_Disconnected ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_Disconnected
Func IwodXMPPNotify_FileTransferStart()
    ConsoleWrite("------- IwodXMPPNotify_FileTransferStart ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_FileTransferStart
Func IwodXMPPNotify_HostCertificate()
    ConsoleWrite("------- IwodXMPPNotify_HostCertificate ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_HostCertificate
Func IwodXMPPNotify_PreTranslateCommand($owner, $command)
    ConsoleWrite("------- IwodXMPPNotify_PreTranslateCommand: " & $command & " ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_PreTranslateCommand
Func IwodXMPPNotify_PreTranslateReply($owner, $val)
    ConsoleWrite("------- IwodXMPPNotify_PreTranslateReply: " & $val & " ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_PreTranslateReply
Func IwodXMPPNotify_PrivateData()
    ConsoleWrite("------- IwodXMPPNotify_PrivateData ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_PrivateData
Func IwodXMPPNotify_ServiceRegister()
    ConsoleWrite("------- IwodXMPPNotify_ServiceRegister ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_ServiceRegister
Func IwodXMPPNotify_ServiceStatusChange()
    ConsoleWrite("------- IwodXMPPNotify_ServiceStatusChange ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_ServiceStatusChange
Func IwodXMPPNotify_ContactList()
    ConsoleWrite("------- IwodXMPPNotify_ContactList ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_ContactList
Func IwodXMPPNotify_ChatRooMData()
    ConsoleWrite("------- IwodXMPPNotify_ChatRooMData ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_ChatRooMData
Func IwodXMPPNotify_ChatRooMListDone()
    ConsoleWrite("------- IwodXMPPNotify_ChatRooMListDone ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_ChatRooMListDone
Func IwodXMPPNotify_ContactStatusChange()
    ConsoleWrite("------- IwodXMPPNotify_ContactStatusChange ---------" & @CRLF)
EndFunc   ;==>IwodXMPPNotify_ContactStatusChange
; This is my custom defined error handler
Func MyErrFunc()

    MsgBox(0, "AutoItCOM Test", "We intercepted a COM Error !" & @CRLF & @CRLF & _
            "err.description is: " & @TAB & $oMyError.description & @CRLF & _
            "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _
            "err.number is: " & @TAB & Hex($oMyError.number, 8) & @CRLF & _
            "err.lastdllerror is: " & @TAB & $oMyError.lastdllerror & @CRLF & _
            "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF & _
            "err.source is: " & @TAB & $oMyError.source & @CRLF & _
            "err.helpfile is: " & @TAB & $oMyError.helpfile & @CRLF & _
            "err.helpcontext is: " & @TAB & $oMyError.helpcontext _
            )

    Local $err = $oMyError.number
    If $err = 0 Then $err = -1

    $g_eventerror = $err ; to check for after this function returns
EndFunc   ;==>MyErrFunc

-_-------__--_-_-____---_-_--_-__-__-_ ^^€ñ†®øÞÿ ë×阮§ wï†høµ† ƒë@®, wï†høµ† †ïmë, @ñd wï†høµ† @ †ïmïdï†ÿ ƒø® !ïƒë. €×阮 ñø†, bµ† ïñ§†ë@d wï†hïñ, ñ@ÿ, †h®øµghøµ† †hë 맧ëñ§ë øƒ !ïƒë.

Link to comment
Share on other sites

If your only purpose is to join chat rooms and send messages, why don't you use "SendText" method instead of SendMessage?

It will work about the same if you are instrrested to send text messages; its big advantage is that you don't need to pass an object as a parameter but a string.

I'm using their wodTelnet for quite a long time and I am really happy. If you have any problems you could open a thread on their support forum - they are nice guys and the chances are that you'll get help.

Apart from that what can I say? Your code looks fine and it's obvious that you're doing your work; I really doubt I can improve anything.

It is a matter of trial and error; that would be my approach.

SNMP_UDF ... for SNMPv1 and v2c so far, GetBulk and a new example script

wannabe "Unbeatable" Tic-Tac-Toe

Paper-Scissor-Rock ... try to beat it anyway :)

Link to comment
Share on other sites

If your only purpose is to join chat rooms and send messages, why don't you use "SendText" method instead of SendMessage?

It will work about the same if you are instrrested to send text messages; its big advantage is that you don't need to pass an object as a parameter but a string.

I'm using their wodTelnet for quite a long time and I am really happy. If you have any problems you could open a thread on their support forum - they are nice guys and the chances are that you'll get help.

Apart from that what can I say? Your code looks fine and it's obvious that you're doing your work; I really doubt I can improve anything.

It is a matter of trial and error; that would be my approach.

Due to the time constraints on my project, i decided to forgo using wodXMPP. Instead, i'm going to handle the XML handling myself, and all the commands myself. I'm currently using ChilkatSocket, from ChilKat software, to connect to the server, encrypt using SASL and TLS, and then send/receive information.

I even threaded it, using async connection/read/send commands, it's working great. Took my origional autoit script for XMPP (using openssl.exe) from 10-15% CPU usage to 0% cpu usage and 8mb for a full ui and XMPP compliant chat.

Loving their addon. MULTITHREAD chat, muahahaha, man i'm happy. (chat handled in separate thread, and command/polling/gui commands handled in primary)

Edited by zackrspv

-_-------__--_-_-____---_-_--_-__-__-_ ^^€ñ†®øÞÿ ë×阮§ wï†høµ† ƒë@®, wï†høµ† †ïmë, @ñd wï†høµ† @ †ïmïdï†ÿ ƒø® !ïƒë. €×阮 ñø†, bµ† ïñ§†ë@d wï†hïñ, ñ@ÿ, †h®øµghøµ† †hë 맧ëñ§ë øƒ !ïƒë.

Link to comment
Share on other sites

Hello !

Could you please give us the necessary .au3 code to connect to Jabber and send/receive some messages ?

I'm very interested, but the COM part is still hard for me :)

Thx !

Apzo.

Due to the time constraints on my project, i decided to forgo using wodXMPP. Instead, i'm going to handle the XML handling myself, and all the commands myself. I'm currently using ChilkatSocket, from ChilKat software, to connect to the server, encrypt using SASL and TLS, and then send/receive information.

I even threaded it, using async connection/read/send commands, it's working great. Took my origional autoit script for XMPP (using openssl.exe) from 10-15% CPU usage to 0% cpu usage and 8mb for a full ui and XMPP compliant chat.

Loving their addon. MULTITHREAD chat, muahahaha, man i'm happy. (chat handled in separate thread, and command/polling/gui commands handled in primary)

Link to comment
Share on other sites

  • 1 month later...

Hello !

Could you please give us the necessary .au3 code to connect to Jabber and send/receive some messages ?

I'm very interested, but the COM part is still hard for me :)

Thx !

Apzo.

Heya, you will need to have the trial version of the ChilkatSocket dll in order to actually use this, as well as the _Base64() UDF.

You will need the DLL so that you can send commands out, create the socket, and use a separate thread.

You will need the _Base64() UDF so that you can create a proper random CODE ID to use with the server in the ID fields.

There are a few issues, which you have to code around:

* If your jabber server doesn't support ANON, then you will need a custom auth handler. ANON SASL is the easiest method to connect to the server, because you dont have to parse MD5 hashes. If you do need to use PLAIN or DIGEST-MD5 then you will have to have some method to calculate the HA1, HA2 and Z formats in this article: MD5 Digeset XMPP Of which, the MD5 hash UDF for Autoit wont do that properly for you. So you will need a different method.

* You will need to code your own send/receive message handlers, so that you know what is going on, but i'll include some examples here.

Global Variables, used throughout the client

$codeID_tmp = StringReplace(_base64Encode(Int(Random(0, 99393))), "=", Int(Random(0, 99))) ;- Generate CodeID
$codeid_tmp_len = StringLen($codeID_tmp) ;- Grab it's length
Global $codeID = StringStripWS(StringTrimLeft($codeID_tmp, $codeid_tmp_len - Int(Random(6, 9))), 8) ;- Format the code properly
Global $count = 0
Global $username = "USERNAME" ;- Your username
Global $Password = "PASSWORD" ;- Your password
Global $host = "SERVER" ;- The Jabber Host
Global $ssl = 1 ;- Encrypt using SSL?
If $ssl = 0 Then
    Global $port = 5222
Else
    Global $port = 5223
EndIf
Global $maxWait = 150000 ;- max wait time for the Socket
Global $resourceID = "RESOURCEID"
Global $codeID, $count, $objXMPP

The CODE TEMPS etc can be disposed of, as only the $codeID is important, but the rest is required to connect. As to SSL, you need to decide if that is what your server will support. If not, then set it to 0, else set it to 1, so that the socket knows to encrypt or not.

Best to store your username/password in the registry or a file component or at least encrypted. What i do, for my client, is store them with a Base64 HASH and SALT ID and then decode those at runtime, so taht none of that information is encoded in the script.

Connection Call

$tmp = _Connect() ;- initiates connection to server
If $tmp = -1 Then
    ;- Process code to re-register all the chilkat DLL's
    ;- Then just call $tmp = _Connect() again
    ;- then check if $tmp = -1
    ;- If it does, then the system failed to register the COM objects
    ;- Usually, if you #RequireAdmin, you dont have to worry about that.
    ConsoleWrite("NO COM OBJECTS" & @CRLF)
    Exit
EndIf

Func _Connect() ;- Connection Protocol
    $objXMPP = connectCOM() ;- Create the COM connection
    ConsoleWrite($objXMPP & @CRLF)
    If $objXMPP = -1 Then
        Return -1
    EndIf
    ;- Start the stream
    asend($objXMPP, "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='" & $host & "' version='1.0'>")
    $data = waitars($objXMPP)
    If $data = -1 Then Return 1
    ConsoleWrite($data & @CRLF)
    ;//// YOU CAN USE CUSTOM ERROR HANDLING OR THE XML DOM FOR STRIPPING OUT THE XMPP XML THAT IS RETURNED, FOR THE MOST PART
    ;//// YOU CAN USE THE STRINGINSTR() FUNCTION TO LOOK FOR ERRORS, FAILURES, AUTH ISSUES, ETC, AND THEN MAKE YOUR DECISIONS
    ;//// ON WHAT TO DO FROM THERE.
    ;////
    ;////
    ;//// SEE THE XMPP RFC's for proper message handling and selecting your own AUTH method to the server.  For the most part
    ;//// You can use SASL ANON if your server accepts it, and the entire process can be scripted via autoit. For other
    ;//// METHODS, such as PLAIN or DIGEST-MD5, you have to be able to calculate the MD5 16 byte Octet and MD5 32 HEX
    ;//// of all the responses.  Which, iirc, autoit cannot do.
    ;////
    ;//// The following code will disconnect you from the server.
    asend($objXMPP, "</stream:stream>")
    $data = waitars($objXMPP)
    ConsoleWrite($data & @CRLF)

    ;- Logged into the server, have fun!
    Return 0
EndFunc   ;==>_Connect

The purpose of the connect function is to allow you to process all of the basic XML commands to connect to the server, pass auth, and then grab your roster (which you should store to a global array. Once you are done with that, you can continue on in your client's mani loop.

ChilkatSocket COM Creation and Connection

Func connectCOM()
    Local $objXMPP = ObjCreate("Chilkat.Socket") ;- create the COM connection object
    If Not IsObj($objXMPP) Then ;- If it's not an object, quit
        Return -1
    EndIf
    $objXMPP.UnlockComponent("YOURUNLOCKCODE") ;- unlock for use
    If $objXMPP.IsUnlocked = 0 Then
        Return -1
    EndIf
    With $objXMPP ;- While there IS an object
        .VerboseLogging = 1 ;- log everything
        .SslProtocol = "default" ;- auto netgotiate ssl/tls
        .HeartbeatMs = 50 ;- pretty much instant returns
        .KeepSessionLog = True ;- log all events
        .SessionLogEncoding = "esc" ;- set to esc (readable) instead of hex
        .MaxSendIdlems = $maxWait ;- Max wait for sending messages
    EndWith
    $objXMPP.AsyncConnectStart($host, $port, $ssl, $maxWait) ;- Create secondary thread to connect to server
    While $objXMPP.AsyncConnectFinished = 0 ;- While the connection is connecting
        Sleep(100) ;- do nothing
    WEnd
    $objXMPP.MaxReadIdlems = $maxWait ;- Set the Read idle to the same as $maxWait
    If $objXMPP.ConnectFailReason <> 0 Then ;- If the connection fails
        MsgBox(0, "Error", $objXMPP.AsyncConnectLog) ;- Print out why with the full connection log
        Exit
    EndIf
    If Not $objXMPP.IsConnected = 1 Then Return -1 ;- If it connected, but it kills connection instantly, then return -1
    Return $objXMPP ;- Return the object
EndFunc   ;==>connectCOM

Assuming this function goes as planned, you will be connected to the server, on the port, address, and ssl type that you specified. One of the key things to note here is that: if you have EVER had a registered version of chilkatSocket on your system, this code will not work. You will need to use the same registered code to gain access to it. It's a protection scheme of the DLL, to prevent people from running unregistered sockets on their machine. As i assume that you have never had one running (which is most likely the case), then you wont have to worry about the 'UNLOCK' sequence, and should have no issue connecting out.

When returning this returns a global Object $objXMPP for you to use against all of your commands.

Sending Function

Func asend($object, $message) ;- Send messages via 2nd thread
    If $message = "" Then Return -1 ;- Ignore blank messages
    $object.AsyncSendString($message) ;- Send the actual message
    While $object.AsyncSendFinished <> 1 ;- While the send action isn't finished
        Sleep(100) ;- Do nothing
    WEnd
    If $object.AsyncSendSuccess <> 1 Then ;- If the send was not successful, return -1
        Return -1
    EndIf
EndFunc   ;==>asend

Having the asend in it's own function allows you to simply call it with the OBject and Message, and then continue on. Helps in threaded environments where you want to process other commands while the system has already sent the command to the server.

Receive Function

Func waitARS($object) ;- Wait for data
    $data = "" ;- Clear the data just in case
    If Not IsObj($object) Then ;- If it's not an object, return -1
        Return -1
    EndIf
    $object.AsyncReceiveString() ;- Begin to Receive the entire string from the socket
    While $object.AsyncReceiveFinished <> 1 ;- If it's not finished
        Sleep(100) ;- Do nothing
    WEnd
    If $object.AsyncReceiveSuccess = 1 Then ;- If receive was successful
        $data = $object.AsyncReceivedString ;- Set the $data varaible to the data received
        Return $data ;- Return the data
    EndIf
    Return -1 ;- Only if data fails to return, return -1
EndFunc   ;==>waitARS

This function is a BLOCKING receive function, not useful for anything but the connection routine, or any XML command to the server where you MUST wait on specific codes. It will return the data that was on the stream after the receive has finished.

Main Loop RX Check

$ars = 0
$connAttempt = 0
while 1
    If Not $objXMPP.CheckWriteable(1) = 1 Then ;- ensure the socket is writeable
        $connAttempt += 1
        If $connAttempt = 3 Then ;- if 3 connect attempts exist, then exit
            Exit
        EndIf
        _Connect() ;- if not writeable try to connect
    ElseIf $objXMPP.ISConnected = 1 Then ;- but if it connects
        $connAttempt = 0 ;- set back to 0
    EndIf
    If $ars = 0 Then ;- if we are not receving
        $objXMPP.AsyncReceiveString() ;- send the command to receive
        $ars = 1 ;- set that we are receving
    EndIf
    If $objXMPP.AsyncReceiveFinished = 1 Then ;- keep processing main loop commands until we have finished with the RX function
        If $objXMPP.AsyncReceiveSuccess = 1 Then ;- if RX was successful
            $data = $objXMPP.AsyncReceivedString ;- set $data to the data that was received off the socket
            If $data <> "" Then read($data) ;- call your custom read handler to figure out what to do
            $ars = 0 ;- set back that we are no longer receving
        Else
            $connAttempt += 1 ;- problem w/ the connection, receive failed
            If $connAttempt = 3 Then ;- same as above, if 3 attempts, exit
                Exit
            EndIf
            _Connect() ;- try to connect again
        EndIf
    EndIf
    sleep(100) ;- only used if you have no other code to run in the main loop (such as a blind message handler)
WEnd

The above handler would go in your main loop, and all other case/select functions under it. So that it is the first thing your app processes. The custom read handler would be where your XML DOM or XML handling would exist, so that, when it receives the data from read($data), it knows what to do. What I do, in that situation, is parse the data for the prpoer codes, and then send it to the proper function (RX message, RX presence, etc).

Example of sending a group chat message (via jabber conference rooms)

$outMESSAGE = '<message id="' & $codeID & '-' & $count & '" to="' & $active_Chat & '@' & $cserver & '" type="groupchat"><body>' & $msg & '</body><x xmlns="jabber:x:event"><offline/><delivered/><displayed/><composing/></x></message>'
asend($objXMPP, $outMESSAGE & @CRLF)

In this case, there are a few items here that need to be filled out, prior to calling this command, of which you will determine client side (such as what chat the cilent is looking at, if multiple chats):

* $active_chat = the chat window that the client is looking at (if you have multiple rooms), you will want to make sure that this is set to the proper name of the chat room to send the message too. Such as: 'my_chat_room'

* $cserver = the same thing as $host, for the most part, but if you have enhanced security like our system, the host and the chat server are different entities, so if that's the case (where your jabber conference server is not the same as the im server you connect too), then you will want to specificy the global variable $cserver so that it knows where to send the messages too.

* $msg = obviously the message you would like to send. Can be most anything, really, as the system processes commands across the board. For special characters like the & sign, it's best you replace them with something else. I'll include a quick replace function for that here later.

That's how you send a message to the server. Note, there is no RX command here, we dont care if there is one or not. We only want to SEND the command to the server. In the main loop, the command will check if we are receving. If we are, then it will post the response back stating that the message either was or was not delievered. in which case, your read($data) function would parse for the RESULT and FAILURE messages and take proper action.

Receive a Message

Func read($data) ;- read the data stream and take apprporiate measures based on type of message recieved
    If $data = "" Then Return -1

    If StringLeft($data, 11) = "<message id" And StringRight($data, 10) = "</message>" Then ;- this is a normal XML message handle
        $array = StringRegExp($data, '(?i)(?s)(?i)(?s)(.*?</message>)', 3, 1)
        If IsArray($array) Then
            For $i = 0 To UBound($array) - 1
                $ret = $array[$i]
                chkMessage($ret) ;- Prase the XML for data
            Next
        EndIf
EndIf

Now, as we can see many things are going on here. I chose not to use the XML DOM here only cuz i'm processing only a very limited # of messages from the server for jabber conferences, personal IM's, etc not really what i'm looking for, such as vcards, etc, not what i'm going to be handling. So, i look at the XML data, and look for the <message id and </message> in the stream, at the proper places, if it's there, then i call my checkMessage routine to parse whats in the <body>(.*?)</body> section via regex and then put that into the client's window so they can see what's going on.

What I did here, however, was take into account multiple messages bound on the stream. For example if you had:

<message id=BLAH from="someone@somewhere.com/NICKNAME" to="me@somewhere.com/MYNICK"><body>SOME MESSAGE</body></message>

It would parse just 1 message (as the array had only 1 message). But, if it had multiple:

<message id=BLAH from="someone@somewhere.com/NICKNAME" to="me@somewhere.com/MYNICK"><body>SOME MESSAGE</body></message><message id=BLAH from="someone@somewhere.com/NICKNAME" to="me@somewhere.com/MYNICK"><body>SOME MESSAGE</body></message>

Then it would parse both messages and send them in series to the proper function (in this case chkmessage()), makes it to where you dont miss many messages coming through ;)

You can look for <presence> and <iq> types in the same manner, and prase them out as necessary as well. The point is, once you get a message, you have to know what to do for it, or skip it, so that the communications can continue to go on w/o much issue.

Replace special characters that can mess up some XMPP installations

Func repLines($data) ;- Has several redundant checks, true, but doesn't fail at replacing :)
    $data = StringRegExpReplace($data, "&lt;", "::LL2T::")
    $data = StringRegExpReplace($data, "&gt;", "::LG2T::")
    $data = StringRegExpReplace($data, "\v", "::LBK::") ;- replace all vertical white space
    $data = StringRegExpReplace($data, "\n", "::LNB::") ;- replace all new lines
    $data = StringRegExpReplace($data, "\l", "::LNR::") ;- replace all line feeds
    $data = StringRegExpReplace($data, "<", "::LLT::") ;- replace all <
    $data = StringRegExpReplace($data, ">", "::LGT::") ;- replace all >
    $data = StringRegExpReplace($data, "&", "::LAP::") ;- replace all &
    $data = StringRegExpReplace($data, "<br>", "::CBR::") ;- replace all breaks HTML
    $data = StringRegExpReplace($data, "/", "::LST::") ;- replace all /
    Return $data
EndFunc   ;==>repLines

Above, are the codes that I found to cause some havoc depending on the server you connect too. So i find it useful to replace them first, and then recombine them before i show the message to the client. Good rule of thumb: Get your messages out to the server all on one line, so that from <message.....> to </message> is all a single line. It speeds up handling and reduces server lag and load times.

Recombine the Codes above

Func _Recombine($data) ;- recombined the actual message before displaying it
    $data = StringRegExpReplace($data, "::LL2T::", "&lt;")
    $data = StringRegExpReplace($data, "::LG2T::", "&gt;")
    $data = StringRegExpReplace($data, "::LBK::", @LF) ;- restore line breaks with new lines
    $data = StringRegExpReplace($data, "::LGT::", ">") ;- restore >
    $data = StringRegExpReplace($data, "::LLT::", "<") ;- restore <
    $data = StringRegExpReplace($data, "::LST::", "/") ;- restore /
    $data = StringRegExpReplace($data, "::LAP::", "&") ;- restore &
    $data = StringRegExpReplace($data, "::LNB::", @LF) ;- restore new line
    $data = StringRegExpReplace($data, "::LNR::", @CR) ;- restore carrige return
    $data = StringRegExpReplace($data, "::CBR::", "<br>") ;- restore html breaks
    Return $data
EndFunc   ;==>_Recombine

The above will take those special codes and put them back to how they belong, so that the origional message is no longer messed up.

Logging into rooms and checking their topics (subjects)

Func loginROOM($count) ;- Log into the defined rooms
    Global $topics[4][2]
    $topics[0][0] = "my_room_1"
    $topics[0][1] = ""
    $topics[1][0] = "my_room_2"
    $topics[1][1] = ""
    Global $rooms[7][2] ;- Array containing the rooms list
    $rooms[0][0] = "my_room_1"
    $rooms[0][1] = ""
    $rooms[1][0] = "my_room_2"
    $rooms[1][1] = "myPassword"
    $count += 1
    $msg = repLines($WelcomeMessage)

    For $i = 0 To UBound($rooms) - 1 ;- process each command below for each room
        If $rooms[$i][0] = "" Then
        Else
            ;- set presence as active in the room
            $count += 1
            $send = '<presence id="' & $codeID & '-' & $count + $i & '" to="' & $rooms[$i][0] & '@' & $cserver & '/' & $myjid & '"><x xmlns="http://jabber.org/protocol/muc"><password>' & $rooms[$i][1] & '</password></x></presence>'
            asend($objXMPP, $send & @CRLF)
            $data = waitars($objXMPP)
            If $data = -1 Then return -3
            If Not StringInStr($data, "presence") Then
                $data = waitars($objXMPP)
                If Not StringInStr($data, "presence") Then ContinueLoop
            EndIf
            $outMESSAGE = '<message id="' & $codeID & '-' & $count + 1 & '" to="'&$rooms[$i][0]&'@' & $cserver & '" type="groupchat"><body>' & $msg & '</body><x xmlns="jabber:x:event"><offline/><delivered/><displayed/><composing/></x></message>'
            asend($objXMPP, $outMESSAGE & @CRLF)
        EndIf
    Next
    For $i = 0 To UBound($topics) - 1
        If $topics[$i][0] = "" Then
        Else
            $count += 1
            $query = "<iq id='" & $codeID & "-" & $count + $i & "' to='" & $topics[$i][0] & "@" & $cserver & "' type='get'><query xmlns='http://jabber.org/protocol/disco#info'/></iq>"
            asend($objXMPP, $query)
            $data = waitars($objXMPP)
            If Not StringInStr($data, "result") Then
                $data = waitars($objXMPP)
                If Not StringInStr($data, "result") Then ContinueLoop
            EndIf
            $tmp = StringRegExp($data, '(?i)(?s)muc#roominfo_subject\"\>\<value\>(.*?)\</value\>', 3, 1)
            If IsArray($tmp) Then
                $topics[$i][1] = $tmp[0]
                ConsoleWrite($topics[$i][1] & @CRLF)
            EndIf
        EndIf
    Next
    Return 1
EndFunc   ;==>loginROOM

If you have Jabber conferences on your server, and you want to be able to JOIN their rooms, and then join them on startup so they are already visible to your clients, you can use somewhat like the above function. There are a few items in there that need to be specified:

* Rooms: What rooms you want, added to the array (these are hard coded in the app)

* Passwords: What is the password for the room

* MyJID: This is what your Jabber Nickname will be, can be most anything, unelss you have registered with the chatroom/server, in which case it should be the bare JID that you have registered with (not your username).

While it's not necessary to always code for the $topics array, i decided i'd like a separate array to handle them, so just matching the $rooms array with a blank 2nd element allows me to parse the room topics, and add them to the array.

The calls on this function are BLOCKING, so you should do this as part of your CONNECTION routine, so that the client doesn't have a chance to send/receive messages yet.

* Welcome Message: You can set your message to whatever you want, as soon as the room is joined, it will send a message to the room stating you are there, or whatever. It does do the replines thing, so if you are doing this to connect to a PUBLIC room, probably best to leave that replines() command out. But for custom client to custom client, you can leave it in.

Again, you can use the XML DOM to get all the data here, but i find it more useful to code it for yourself, and just parse out using regex B)

Disconnecting from the Server

asend($objXMPP, "</stream:stream>"&@crlf)

You will want to clear out all of your object connections (if you need to, chilkat doesn't need too), or any other commands you want to do during close at this point, and then send that above command to the Jabber server, so that you are disconnected from the stream.

Find out who is in the room

Func getRoomList()
    $msg = '<iq id="' & $codeID & '-' & $count + 1 & '" to="MY_ROOM_NAME@' & $cserver & '" type="get"><query xmlns="http://jabber.org/protocol/disco#items"></query></iq>'
    asend($objXMPP, $msg & @CRLF)
    $data = waitars($objXMPP)
    If Not StringInStr($data, "<") Then ;- if features WERE not recieved
        Return -1 ;- send back error
    EndIf
    read($data)
    Return 1
EndFunc   ;==>getRoomList

You can process that command in the login to room function, if you wish, but if you are like me, you'll just do that whenever a <presence> message is Received from the jabber conference server. This will allow you to find out who all is part of a room, and in your read() function, you can parse that out by looking at <iq result> commands and ITEM ID's to find out who they are and add them to a global array (i use listviews for this).

Connecting via SASL ANON Exmple

You can connect to the server using SASL ANON, if your server supports it, here's an example login routine to do just that:

Func _Connect() ;- Connection Protocol
    Global $objXMPP = connectCOM()
    If $objXMPP = -1 Then
        Return -1
    EndIf
    asend($objXMPP, "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='" & $host & "' version='1.0'>")
    $data = waitars($objXMPP)
    If $data = -1 Then Return 1 ;- couldn't create stream to server
    asend($objXMPP, "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>")
    $data = waitars($objXMPP)
    If $data = -1 Then Return 2 ;- couldn't initiate sasl anon
    asend($objXMPP, "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='" & $host & "' version='1.0'>")
    $data = waitars($objXMPP)
    If $data = -1 Then Return 3 ;- couldn't create second stream to server
    asend($objXMPP, "<iq type='get' id='" & $codeID & "'><query xmlns='jabber:iq:auth'><username>" & $username & "</username></query></iq>")
    $data = waitars($objXMPP)
    If $data = -1 Then Return 4 ;- couldn't query credentials
    asend($objXMPP, "<iq type='set' id='" & $codeID & "'><query xmlns='jabber:iq:auth'><username>" & $username & "</username><resource>" & $resourceID & "</resource><password>" & $Password & "</password></query></iq>" & @CRLF)
    $data = waitars($objXMPP)
    If $data = -1 Then Return 5 ;- couldn't log into the server
    If StringInStr($data, '<error code=') Then Return -5
    asend($objXMPP, "<iq type='get'  id='" & $codeID & "'><query xmlns='jabber:iq:roster'/></iq>")
    $data = waitars($objXMPP)
    If $data = -1 Then Return 6 ;- couldn't pull the roster
    If Not StringInStr($data, "item") Then
        $data = waitars($objXMPP)
        If Not StringInStr($data, "item") Then Return 6 ;- couldn't pull the roster on retry
    EndIf
    $cnt = StringRegExp($data, "(?i)(?s)ROSTER_PREFIX_THAT_YOU_WANT", 3, 1)
    If IsArray($cnt) Then
        Global $ContactLIst[UBound($cnt) + 1][2]
        $tmp = StringRegExp($data, "(?s)(?i)<item(.*?)</item>", 3, 1)
        If IsArray($tmp) Then
            $c = -1
            For $i = 0 To UBound($tmp) - 1
                If StringInStr($tmp[$i], "BT_Tech") Then
                    $dta = StringRegExp($tmp[$i], '(?s)(?i)jid="(.*?)(?:\@.*?)"', 3, 1)
                    If IsArray($dta) Then
                        $tjid = $dta[0]
                    Else
                        $tjid = ""
                    EndIf
                    $dta = StringRegExp($tmp[$i], '(?s)(?i)name="(.*?)"', 3, 1)
                    If IsArray($dta) Then
                        $tname = $dta[0]
                    Else
                        $tname = ""
                    EndIf
                    If $tjid <> "" And $tname <> "" Then
                        $c += 1
                        $ContactLIst[$c][0] = $tjid
                        $ContactLIst[$c][1] = $tname
                    EndIf
                EndIf
            Next
        Else
            Return 7 ;- couldn't parse the roster items
        EndIf
    Else
        Return 6 ;- couldn't parse the roster
    EndIf
    Return 0 ;- everything went fine, we are connected, encrypted, and logged in.
EndFunc   ;==>_Connect

That connects to most any ANON SASL server out there (i have tried about 4 lol) The point is to set the auth to ANON so that you can send your commands, encrypted via SSL and then username/password via SASL to the server. It's quite nice. If you look at the stream's RAW data via a sniffer, it's all jibberish B) Of course, you'll want to make sure $SSL = 1 and you are connecting to the proper port, or things will just fry B)

-_-------__--_-_-____---_-_--_-__-__-_ ^^€ñ†®øÞÿ ë×阮§ wï†høµ† ƒë@®, wï†høµ† †ïmë, @ñd wï†høµ† @ †ïmïdï†ÿ ƒø® !ïƒë. €×阮 ñø†, bµ† ïñ§†ë@d wï†hïñ, ñ@ÿ, †h®øµghøµ† †hë 맧ëñ§ë øƒ !ïƒë.

Link to comment
Share on other sites

  • 8 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...