WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

Samples from Users
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Messenger Type Client

 Keywords: Messenger Chat Type Client 

Sample:

The attached file is a very minimal Messenger client written in WinBatch.

NOTE: It does not have much in the way of comments, error handling, it's very limited and may not be that stable.

But it works. It allows you to send and receive messages. I've only tested it with one chat at a time but it might work with more :)

It you want more information about the protocol that MSM uses have a look at http://www.hypothetic.org/docs/msn/

; Basic MS Messenger client in Winbatch
; Protocol details from http://www.hypothetic.org/docs/msn/
; By Iain Dickason (iain@caverock.net) 7/11/02

; Go setup the subroutines and dialog
gosub functions
; Needed extender!
AddExtender("WWWSK34i.DLL")
; Get .Net e-mail address and password
account = AskLine("wbMSM","E-mail address for .Net account to connect with:","")
password = AskPassword("wbMSM","Password:")

;set defaults
state = -1 ; Used for working out where in the connect system we are
retry = 0
reconect = 0
ConnectServer = "messenger.hotmail.com" ; Messenger start server
ConnectPort = "1863"
; List of commands and mime types we know about
;					1	 2	  3	4	 5	  6	7	 8	  9	10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26
CommandList = "ACK,ADD,ANS,BLP,BYE,CAL,CHG,CHL,FLN,GTC,INF,ILN,IRO,JOI,LST,MSG,NAK,NLN,OUT,QRY,REM,RNG,SYN,USR,VAR,XFR"
MSgTypeList = "x-msmsgsprofile,x-msmsgsinitialemailnotification,x-msmsgsemailnotification,x-msmsgsactivemailnotification,x-msmsgscontrol,plain"
Contacts = ArrDimension(3) ; 0 = passport, 1 = screen name, 2 = status
ContactListChange = @True
ArrInitialize(Contacts, "")
Chats = ArrDimension(3) ; 0 = socket handle, 1 = index to Contact, 2 = transaction #
ArrInitialize(Chats, "")
MyStatus = ""
LogData = ""
OldLogData = ""
ChatData = ""
OldChatData = ""
Text = ""
reply = ""
sendline = ""

ButtonPushed=Dialog("wbMSM")

:exit
sClose(socket_handle)
For c = 1 to ItemCount(Chats[0],@tab)
	sClose(Chats[0])
Next
exit

:Functions
; This subroutine is for the inital connection could do with a major re-write.
; each loop round it should do a new section, till it gets moved to a new server and re does the start.
#DefineSubroutine Connect()
	Switch state
		Case 0 ; Open Socket
			transaction = 0
			socket_handle = sOpen ()
			If !(socket_handle) then 
				retry = retry + 1
			Else
				state = state + 1
			EndIf
			break
		Case 1 ; Connect
			If !(sConnect (socket_handle, ConnectServer, ConnectPort)) then 
				state = -1
			Else
				retry = 0
				state = state + 1
				transaction = 0
			EndIf
			break
		Case 2 ; Version
			sendline = StrCat("VER ",transaction," MSNP7 MSNP6 MSNP5 MSNP4 CVR0")
			If !(sSendLine (socket_handle, sendline)) then 
				state = -1
			Else
				retry = 0
				state = state + 1
				transaction = transaction + 1
			EndIf
			break
		Case 3 ; Version reply
			reply = sRecvLine (socket_handle, 256)
			If ItemExtract(3,reply," ") == "0" Then
				sClose(socket_handle)
				state = -1
			Else
				state = state + 1
			EndIf
			break
		Case 4 ; Auth request
			sendline = StrCat("INF ",transaction)
			If !(sSendLine (socket_handle, sendline)) then 
				state = -1
			Else
				retry = 0
				state = state + 1
				transaction = transaction + 1
			EndIf
			break
		Case 5 ; Auth reply
			reply = sRecvLine (socket_handle, 256)
			If ItemExtract(3,reply," ") <> "MD5" Then
				sClose(socket_handle)
				state = -1
			Else
				retry = 0
				state = state + 1
			EndIf
			break
		Case 6 ; Server request
			sendline = StrCat("USR ",transaction," MD5 I ",account)
			If !(sSendLine (socket_handle, sendline)) then 
				state = -1
			Else
				retry = 0
				state = state + 1
				transaction = transaction + 1
			EndIf
			break
		Case 7 ; server reply - 
			reply = sRecvLine (socket_handle, 256)
			If ItemExtract(1,reply," ") == "XFR" Then ; We get told to move to a new server now.
				retry = 0
				state = 0										; Thats why the state is set back to 0
				ConnectServer = ItemExtract(1,ItemExtract(4,reply," "),":")
				ConnectPort = ItemExtract(2,ItemExtract(4,reply," "),":")
				sClose(socket_handle)
			Else
				If ItemExtract(1,reply," ") == "USR" Then
					retry = 0
					hash = ItemExtract(5,reply," ")
					state = 8
				Else
					state = -1
				EndIf
			EndIf
			break
		Case 8 ; Send hashed password
			sendline = StrCat("USR ",transaction," MD5 S ",Md5(password,hash))
			If !(sSendLine (socket_handle, sendline)) then 
				state = -1
			Else
				retry = 0
				state = state + 1
				transaction = transaction + 1
			EndIf
			break
		Case 9 ; Login reply
			reply = sRecvLine (socket_handle, 256)
			If ItemExtract(3,reply," ") == "OK" Then
				retry = 0
				state = state + 1
				transaction = transaction + 1
			Else
				state = -1
			EndIf
			break
	EndSwitch
	If reply <> "" then LogData = StrCat(LogData,">> ",reply,@CRLF)
	If sendline <> "" then LogData = StrCat(LogData,"<< ",sendline,@CRLF)
	reply = ""
	sendline = ""
	Return state
#EndSubroutine

; This gets called once for the main connection and once each for any chats that are open.
#DefineSubroutine sysMessages(socket,trans)
	; check to see if there is anything waiting to be looked at
	If !sOK2Recv (socket, 1) then
		If state == 10 Then ; if this is the first time after we've connected we have to tell the system we are available for chatting
			sendline = StrCat("CHG ",trans," NLN")
			sSendLine (socket, sendline)
			trans = trans + 1
			LogData = StrCat(LogData,"<< ",sendline,@CRLF)
			state = state + 1
		EndIf
		;If AskYesNo("Exit","Exit?") == @Yes then goto exit
		return trans
	EndIf
	recvLine = sRecvLine (socket, 256)
	LogData = StrCat(LogData,">> ",recvline,@CRLF)
	command = ItemExtract(1,recvLine," ") ; All lines should have a 3 letter at the start of them
	Switch ItemLocate(command,CommandList,",") ; find out which command we are looking at by compareing it with our list
		Case 5 ; BYE - Someone has left a chat we are in, for the moment we will pretend that the chat only had us and them so we close it
			ChatName = ItemExtract(2,recvLine," ")
			chat = ItemLocate(ItemLocate(ChatName,Contacts[0],@tab),Chats[1],@tab)
			sClose(ItemExtract(chat,Chats[0],@tab))
			Chats[0] = ItemRemove(Chat,Chats[0],@tab)
			Chats[1] = ItemRemove(Chat,Chats[1],@tab)
			Chats[2] = ItemRemove(Chat,Chats[2],@tab)
			ChatData = StrCat(ChatData,ChatName," has left chat.",@CRLF)
			break
		Case 7 ; CHG - Have been told by the server to change our state (busy, away etc).  Dont do anything about it realy.
			reply_trans = ItemExtract(2,recvLine," ")
			If reply_trans == 0 Then ; being told to change state by server
				MyStatus = ItemExtract(3,recvLine," ")
			Else
				MyStatus = ItemExtract(3,recvLine," ")
			EndIf
			break
		Case 8 ; CHL - We've been chalenged by MSM we must reply!
			hash = ItemExtract(3,recvLine," ")
			sendline = StrCat("QRY ",trans," msmsgs@msnmsgr.com 32",@CRLF,Md5("Q1P7W2E4J9R8U3S5",hash))
			sSendString(socket,sendline)
			LogData = StrCat(LogData,"<< ",sendline,@CRLF)
			trans = trans + 1
			break
		Case 9 ; FLN - a friend has gone ofline, so we remove them from the list of contacts
			ContactListChange = @True
	   	ContactPassport = ItemExtract(2,recvLine," ")
			ContactScreenName = ItemExtract(3,recvLine," ")
			loc = ItemLocate(ContactPassport,Contacts[0],@tab)
			If loc then
				Contacts[0] = ItemRemove(loc, Contacts[0], @Tab)
				Contacts[1] = ItemRemove(loc, Contacts[1], @Tab)
				Contacts[2] = ItemRemove(loc, Contacts[2], @Tab)
			EndIf
		   break
		Case 12 ; ILN - once we connect we will be told if our friends are on, and what state they are in
			ContactListChange = @True
	   	ContactPassport = ItemExtract(4,recvLine," ")
			ContactScreenName = ItemExtract(5,recvLine," ")
			ContactStatus = ItemExtract(3,recvLine," ")
			loc = ItemLocate(ContactPassport,Contacts[0],@tab)
			If !loc then
				Contacts[0] = ItemInsert(ContactPassport, -1, Contacts[0], @Tab)
				Contacts[1] = ItemInsert(ContactScreenName, -1, Contacts[1], @Tab)
				Contacts[2] = ItemInsert(ContactStatus, -1, Contacts[2], @Tab)
			Else
				Contacts[0] = ItemReplace(ContactPassport, loc, Contacts[0], @Tab)
				Contacts[1] = ItemReplace(ContactScreenName, loc, Contacts[1], @Tab)
				Contacts[2] = ItemReplace(ContactStatus, loc, Contacts[2], @Tab)
			EndIf
		   break
		Case 14 ; JOI - someone has joined a chat we invited them to
			If ChatPending <> "" then
				ChatName = ItemExtract(1,ChatPending,@tab)
				Chat = ItemLocate(ChatName,Contacts[0],@tab)
				SendText = ItemRemove(1,ChatPending,@tab)
				msgbody = StrCat("MIME-Version: 1.0",@CRLF,"Content-Type: text/plain; charset=UTF-8",@CRLF)
				msgbody = StrCat(msgbody,"X-MMS-IM-Format: FN=MS%%20Shell%%20Dlg; EF=; CO=0; CS=0; PF=0",@CRLF,@CRLF)
				msgbody = StrCat(msgbody,SendText,@CRLF)
				cmdline = StrCat("MSG ", trans," U ",StrLen(msgbody), @CRLF)
				sendline = StrCat(cmdline,msgbody)
				LogData = StrCat(LogData,"<< ",sendline,@CRLF)
				ChatData = StrCat(ChatData,"To ",ChatName,": ",SendText,@CRLF)
				sSendString(socket,sendline)
				trans = trans + 1
				ChatPending = ""
			EndIf
			break
		Case 16 ; MSG - we have received a mime type message
	   	UserHandle = ItemExtract(2,recvLine," ")
			MessageSize = ItemExtract(4,recvLine," ")
			Msg = ReceiveMessage(socket,MessageSize)
			LogData = StrCat(LogData,Msg,@CRLF)
			MsgTypeLine = ItemExtract(2,Msg,@CR)
			MsgType = StrTrim(ItemExtract(2,ItemExtract(2,ItemExtract(1,MsgTypeLine,";"),":"),"/"))
			If UserHandle == "Hotmail" Then ; is the message a MSM system message?
				Select ItemLocate(MsgType,MsgTypeList,",")
					Case 2; inital mail
						UnreadEmail = StrTrim(ItemExtract(2,ItemExtract(4,Msg,@CR),":"))
						If UnreadEmail > 0 then
							ChatData = StrCat(ChatData,"Unread e-mail Inbox: ",UnreadEmail,@CRLF)
						EndIf
							break
					Case 3; New Mail
						MailFrom = ItemExtract(2,ItemExtract(4,Msg,@CR),":")
						ChatData = StrCat(ChatData,"New mail received from '",MailFrom,"'",@CRLF)
						break
				EndSelect
			Else ; nope.. mostlikly a chat message from a friend. (have to deal with typeing message)
				ChatMsg = Msg
				For line = 1 to 4
					ChatMsg = ItemRemove(1,ChatMsg,@CR)
				Next line
				ChatMsg = StrTrim(StrReplace(ChatMsg,@lf,""))
				ChatData = StrCat(ChatData,UserHandle,":",ChatMsg,@CRLF)
			EndIf
		   break
		Case 18 ; NLN - a friend is now online so we add them to the list of contacts
			ContactListChange = @True
	   	ContactPassport = ItemExtract(3,recvLine," ")
			ContactScreenName = ItemExtract(4,recvLine," ")
			ContactStatus = ItemExtract(2,recvLine," ")
			loc = ItemLocate(ContactPassport,Contacts[0],@tab)
			If !loc then
				Contacts[0] = ItemInsert(ContactPassport, -1, Contacts[0], @Tab)
				Contacts[1] = ItemInsert(ContactScreenName, -1, Contacts[1], @Tab)
				Contacts[2] = ItemInsert(ContactStatus, -1, Contacts[2], @Tab)
			Else
				Contacts[0] = ItemReplace(ContactPassport, loc, Contacts[0], @Tab)
				Contacts[1] = ItemReplace(ContactScreenName, loc, Contacts[1], @Tab)
				Contacts[2] = ItemReplace(ContactStatus, loc, Contacts[2], @Tab)
			EndIf
		   break
		Case 20 ; QRY
			break
		Case 22 ; RNG - Ohh.. we're being invited to a chat....
			SessionID = ItemExtract(2, recvLine, " ")
			sbServer = ItemExtract(3, recvLine, " ")
			ChatHash = ItemExtract(5, recvLine, " ")
			ChatName = ItemExtract(6, recvLine, " ")
			loc = ItemLocate(ChatName, Contacts[0], @tab)
			If loc then
				Chats[0] = ItemInsert(sOpen (), -1, Chats[0],@tab)
				Chats[1] = ItemInsert(loc, -1,Chats[1], @tab)
				Chats[2] = ItemInsert(2,-1,Chats[2],@Tab)
				Chat = ItemLocate(loc,Chats[1],@tab)
				If !sConnect (ItemExtract(Chat,Chats[0],@tab), ItemExtract(1,sbServer,":"), ItemExtract(2,sbServer,":"))
					Chats[0] = ItemRemove(Chat,Chats[0],@tab)
					Chats[1] = ItemRemove(Chat,Chats[1],@tab)
					Chats[2] = ItemRemove(Chat,Chats[2],@tab)
					LogData = StrCat(LogData,"Chat failed",@CRLF)
					break
				EndIf
				sendline = StrCat("ANS 1 ",account," ",ChatHash," ",SessionID,@CRLF)
				sSendString(ItemExtract(Chat,Chats[0],@tab),sendline)
				LogData = StrCat(LogData,"<< ",sendline,@CRLF)
			EndIf
			Break
		Case 24 ; USR - starting off the new chat session, telling the server who we want to chat to.
			ChatName = ItemExtract(ItemExtract(c,Chats[1],@tab),Contacts[0],@tab)
			sendline = StrCat("CAL ",trans," ",ChatName,@CRLF)
			sSendString(ItemExtract(Chat,Chats[0],@tab),sendline)
			LogData = StrCat(LogData,"<< ",sendline,@CRLF)
			break
		Case 26 ; XFR - asking for a switchboard server to start a new chat on.
			sbServer = ItemExtract(4, recvLine, " ")
			ChatHash = ItemExtract(6, recvLine, " ")
			loc = ItemLocate(ItemExtract(1,ChatPending,@tab),Contacts[0],@tab)
			Chats[0] = ItemInsert(sOpen (), -1, Chats[0],@tab)
			Chats[1] = ItemInsert(loc, -1,Chats[1], @tab)
			Chats[2] = ItemInsert(2,-1,Chats[2],@Tab)
			Chat = ItemLocate(loc,Chats[1],@tab)
			If !sConnect (ItemExtract(Chat,Chats[0],@tab), ItemExtract(1,sbServer,":"), ItemExtract(2,sbServer,":"))
				Chats[0] = ItemRemove(Chat,Chats[0],@tab)
				Chats[1] = ItemRemove(Chat,Chats[1],@tab)
				Chats[2] = ItemRemove(Chat,Chats[2],@tab)
				LogData = StrCat(LogData,"Chat failed",@CRLF)
				break
			EndIf
			sendline = StrCat("USR 1 ",account," ",ChatHash,@CRLF)
			sSendString(ItemExtract(Chat,Chats[0],@tab),sendline)
			LogData = StrCat(LogData,"<< ",sendline,@CRLF)
			Break
	EndSwitch
Return trans
#EndSubroutine

; to make the MD5 hash we have to send to the server from time to time
#DefineFunction Md5(text,hash)
	handle = BinaryAlloc(StrLen(text)+StrLen(hash))
	BinaryPokeStr(handle, 0,StrCat(hash,text))
	return StrReplace (BinaryCheckSum(handle,0),"-","")
#EndFunction

;receive the rest of a message, we get told how big the message is so its quite easy
#DefineFunction ReceiveMessage(socket,size)
	ret = ""
	binbuf = BinaryAlloc(1000)
	BinaryEODSet(binbuf,1000)
	binaddr=IntControl(42,binbuf,0,0,0)
	stuff=sRecvBinary(socket, binaddr, size)
	data=BinaryPeekStr(binbuf,0,size)
	return data
#EndFunction


;Standard dialog control subroutine. We are intrested in a timer and button presses.
PROCOPT_INIT    = 0   ; Dialog created .
PROCOPT_TIMER   = 1   ; Timer event
PROCOPT_PUSH    = 2   ; Pass push/picture button presses.
PROCOPT_ITEM    = 7   ; ItemList selected
#DEFINESUBROUTINE dlg_control(DialogHandle, EventCode, ControlNum, Res4, Res5)
	switch( EventCode)
	   case PROCOPT_INIT
			DialogProcOptions(DialogHandle, PROCOPT_TIMER, 100) ; have a go every seccond... could drop this down once connected?
			DialogProcOptions(DialogHandle, PROCOPT_PUSH, 1)
		   break
		case PROCOPT_TIMER
			If (state <> -1) then
				If (state >= 0 & state < 10) then
					Connect()
				Else
					transaction = sysMessages(socket_handle,transaction)
					For c = 1 to ItemCount(Chats[0],@tab)
						new_trans = sysMessages(Chats[0],ItemExtract(c,Chats[2],@tab))
						Chats[2] = ItemReplace(new_trans,c,Chats[2],@tab)
					Next
				EndIf
			EndIf
			If ContactListChange Then ; If the Contact list has changed then update it.
				DialogControlSet(dialoghandle, 1, 5, Contacts[0])
				ContactListChange = @False
			EndIf
			LogData = StrReplace(LogData, @CRLF, @CR)
			If ItemCount(LogData,@CR) > 200 Then LogData = ItemRemove(1,LogData,@CR)
			LogData = StrReplace(LogData, @CRLF, @CR)
			If LogData <> OldLogData Then ; If we've changed the log data then we need to update it.
				DialogControlSet(dialoghandle, 7, 3, LogData)
			EndIf
			ChatData = StrReplace(ChatData, @CRLF, @CR)
			If ItemCount(ChatData,@CR) > 200 Then ChatData = ItemRemove(1,ChatData,@CR)
			ChatData = StrReplace(ChatData, @CR, @CRLF)
			If ChatData <> OldChatData Then ; If we've changed the Chat data then we need to update it.
				DialogControlSet(dialoghandle, 3, 3, ChatData)
			EndIf
			OldLogData = LogData
			OldChatData = ChatData
			break
	   case PROCOPT_PUSH
	      if ControlNum == 6 ; Send
				SendText = DialogControlGet(DialogHandle, 5, 3)
				CurrentContact = DialogControlGet(DialogHandle, 1, 6)
				chat = ItemLocate(CurrentContact,Contacts[0],@tab)
				loc = ItemLocate(chat ,Chats[1],@tab)
				If loc == 0 Then
					sendline = StrCat("XFR ",transaction," SB",@CRLF)
					sSendString(socket_handle,sendline)
					ChatPending = StrCat(CurrentContact,@tab,SendText)
				Else
					msgbody = StrCat("MIME-Version: 1.0",@CRLF,"Content-Type: text/plain; charset=UTF-8",@CRLF)
					msgbody = StrCat(msgbody,"X-MMS-IM-Format: FN=MS%%20Shell%%20Dlg; EF=; CO=0; CS=0; PF=0",@CRLF,@CRLF)
					msgbody = StrCat(msgbody,SendText,@CRLF)
					cmdline = StrCat("MSG ", ItemExtract(loc,Chats[2],@tab)," U ",StrLen(msgbody), @CRLF)
					sendline = StrCat(cmdline,msgbody)
					LogData = StrCat(LogData,loc,"<< ",sendline,@CRLF)
					ChatData = StrCat(ChatData,"To ",CurrentContact,": ",SendText,@CRLF)
					sSendString(ItemExtract(loc,Chats[0],@tab),sendline)
					trans = ItemExtract(loc,Chats[2],@tab) + 1
					Chats[2] = ItemReplace(trans,loc,Chats[2],@tab)
				EndIf
	         return -2 ; Don't termnate the dialog
	      endif
	      if ControlNum == 8 ; Exit
	         return -1 ; Don't termnate the dialog
	      endif
	      if ControlNum == 9 ; Settings
	         return -2 ; Don't termnate the dialog
	      endif
	      if ControlNum == 10 ; Connect
				state = 0
	         return -2 ; Don't termnate the dialog
	      endif
			break
		case PROCOPT_ITEM ; dont use this .
			CurrentContact = DialogControlGet(DialogHandle, 1, 5)
			break
	endswitch

	return -1
#ENDSUBROUTINE

wbMSMFormat=`WWWDLGED,6.1`

wbMSMCaption=`wbMSM`
wbMSMX=-17
wbMSMY=127
wbMSMWidth=274
wbMSMHeight=226
wbMSMNumControls=010
wbMSMProcedure=`dlg_control`
wbMSMFont=`DEFAULT`
wbMSMTextColor=`DEFAULT`
wbMSMBackground=`DEFAULT,DEFAULT`

wbMSM001=`211,009,056,092,ITEMBOX,dlg_contactlist,DEFAULT,DEFAULT,1,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
wbMSM002=`213,001,024,008,STATICTEXT,DEFAULT,"Contacts",DEFAULT,2,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
wbMSM003=`003,011,204,090,MULTILINEBOX,dlg_messages,DEFAULT,DEFAULT,3,8,DEFAULT,DEFAULT,DEFAULT`
wbMSM004=`005,001,044,008,STATICTEXT,DEFAULT,"Messages",DEFAULT,4,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
wbMSM005=`003,103,204,012,EDITBOX,dlg_editline,DEFAULT,DEFAULT,5,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
wbMSM006=`211,105,028,010,PUSHBUTTON,DEFAULT,"Send",1,6,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
wbMSM007=`003,119,264,102,MULTILINEBOX,dlg_log,DEFAULT,DEFAULT,7,8,DEFAULT,DEFAULT,DEFAULT`
wbMSM008=`179,001,028,010,PUSHBUTTON,DEFAULT,"Exit",2,8,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
wbMSM009=`149,001,028,010,PUSHBUTTON,DEFAULT,"Settings",3,8,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
wbMSM010=`119,001,028,010,PUSHBUTTON,DEFAULT,"Connect",4,8,DEFAULT,DEFAULT,DEFAULT,DEFAULT`

;ButtonPushed=Dialog("wbMSM")


return




Article ID:   W15690
File Created: 2003:05:13:11:29:34
Last Updated: 2003:05:13:11:29:34