05-30-2020, 07:50 +0200
Forum: Overviewworkscript announcements
Basic msn client in Tcl
AuthorPost
HackeMate  05-09-2008, 12:55   | Example to connect Msn Homepage
Member since 05/2008
6 Posts
Location: Spain
This is not a final script to use msn, it just contain the basic part for log in, the else of work only requires read the msn commands. The comments are based in http://www.hypothetic.org/docs/msn/, my English is not so good :)

                                                                                                                              
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#!/usr/bin/tclsh
#
# This is an elemental Msn client using the protocol MSNP8 (windows messenger default)
# Not third-party client. It's an example for your information.
# Written by HackeMate @ QuakeNet
#            Sentencia @ IRC-Hispano
# Sentencia@librepensamiento.es

proc msn:sdata {sock str} {
    puts $sock "$str"
    msn:echo "*** $sock: $str"
}

proc msn:echo {str} {

    switch -- [string range $str 0 3] {
        "::: " {
            set prefix "Msn:>"
            set str [string range $str 4 end]
        }
        "*** " {
            set prefix "02Sending:\>02"
            set str [string range $str 4 end]
        }
        "!!! " {
            set prefix "2Incomming ERROR:02"
            set str [string rane $str 4 end]
        }
        "default" {
            set prefix "Incomming data:"
        }
    }
    puts stdout "$prefix $str"
}

proc msn:nexus {} {

    # Passport authentication begins with the passport nexus, just as logging into messenger begins with the Dispatch Server
    # Using secure http request to the next path.

    package require http
    package require tls
    http::register https 443 ::tls::socket

    set token [http::geturl https://nexus.passport.com/rdr/pprdr.asp]
    upvar #0 $token state
    foreach {name value} $state(meta) {
        if {$name == "PassportURLs"} {
            set data [split $value ","]
            set dalogin [lsearch -all -inline $data "DALogin=*"]
            set dalogin [lindex [split $dalogin "="] 1]
            msn:echo "::: PassPort saved. We are jumping to $dalogin"
            msn:passport $dalogin
            return
        }
    }

    # I admit that this is a dirty way to know when passort auth was failed.
    # Sorry about, I'm lazy.
    msn:echo "!!! Authentication process was not good."
    close $::msn(sock)
    # This exist command will exit from the previous command executed in msn:Login vwait forever
    exit
    return
}

proc msn:passport {url} {

    # The client sends a https get request for the url given to it by the nexus (saved in $dalogin, here $url)
    # The login is waiting the last parameters that we saved in $::msn(auth), like a header.

    package require http
    package require tls
    http::register https 443 ::tls::socket

    set url "https://"
    set account [string map [list "\@" "\%40"] $::msn(account)]
    set token [http::geturl $url -headers [list Authorization "Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=$account,pwd=$::msn(password),$::msn(auth)"]]
    upvar #0 $token state

    # If we fail the authentication, instead HTTP 200 it will return something like HTTP 302, or if
    # the syntax was badly, HTTP 401. If all is Ok, this foreach will connect us.

    foreach {name value} $state(meta) {
        if {$name == "Authentication-Info"} {
            regexp {\'(.*?)\'} $value "" cookie
            incr ::msn(trid)
            msn:sdata $::msn(sock) "USR $::msn(trid) TWN S $cookie"
        }
    }
}
# Configuration

set ::msn(account) "Your@Messenger.account"
set ::msn(password) "AGoodPassword"

# We define here the version protocol.
# This variable will be used only twice.

set ::msn(version) "MSNP8 CVR0"

# (CVR) The CVR command sends version information about a client and operating
# system to the server. For the official client, the server will reply with
# information about a recommended version of the client. It's debatable whether
# third-party clients should send CVR. Microsoft might start blocking users based on
# this command, or they might tread third-party clients better than now if there was
# evidence that a significant number of people used them. Any way, Microsoft
# has no way to verify the information given.

# Independently of all this debat, Where are you from? :) Spanish location is 0x0C0A
# American users send: 0x0409
# For your information: http://www.microsoft.com/globaldev/reference/oslocversion.mspx
# This var may define your Locale configuration
set ::msn(location) "0x0C0A"

# This is our info. It is what a Windows XP & windows messenger sends.

set ::msn(msnms) "winnt 5.1 i386 MSMSGS 4.7.3001 WindowsMessenger"


# End of parameters.

# We are going

proc msn:Login { { server "messenger.hotmail.com" } {port 1863} } {

    # (TrID) The Transaction IDs, abbreviated as TriDs, are used to much a client command with a server
    # response. Commands sent by the client are required to contain a TrID, and commands from the server
    # sent in direct response to that command will contain the same TrID (with some exception).
    # Every TrID is a number between 0 and 4294967295. Using this TrID wrongly may cause confusion and
    # server and client will be unstable.

    if {![info exists ::msn(trid)]} { set ::msn(trid) 1 }

    # Easy to make multi-server, almost all depend of this (and previous) var name.

    set ::msn(sock) [socket $server $port]
    msn:echo "::: Trying to connect $server:$port- sockname: $::msn(sock)"

    # Because we can receive data in any moment, we need read it as fast as we can, that's why I used
    # -buffering line instead full. In certain moment negotiating the connection, the socket can get
    # stuned or we are forced to execute manually gets, if you don't use vwait forever command.
    # I had bad experiencies with this command in x-chat.

    fconfigure $::msn(sock) -buffering line -blocking no

    fileevent $::msn(sock) readable [list msn:gdata $::msn(sock)]
    msn:sdata $::msn(sock) "VER $::msn(trid) $::msn(version)"
    vwait forever
}

proc msn:gdata {socket} {

    if {[eof $socket]} {
        msn:echo "::: Closed connection."
        close $socket
        exit
        return
    }
    set datos [gets $socket]
    foreach data [split $datos \n] {
        msn:echo "$data"
        if {$data == "VER $::msn(trid) $::msn(version)"} {
            incr ::msn(trid)
            msn:sdata $::msn(sock) "CVR $::msn(trid) $::msn(location) $::msn(msnms) $::msn(account)"
        }

        set cvr [join [lrange [split $data] 0 1]]
        if {$cvr == "CVR $::msn(trid)"} {
            incr ::msn(trid)
            msn:sdata $::msn(sock) "USR $::msn(trid) TWN I $::msn(account)"
        }

        set usr [join [lrange [split $data] 0 3]]
        if {$usr == "USR $::msn(trid) TWN S"} {

            # Rude way to save this parameters...
            # Thanks thommey for advice to use a foreach loop
            # It will work, I will change it soon
            set udata [split $data ","]
            set lc [lsearch -all -inline $udata "lc=*"]
            set lc [lindex [split $lc "="] 1]
            set id [lsearch -all -inline $udata "id=*"]
            set id [lindex [split $id "="] 1]
            set tw [lsearch -all -inline $udata "tw=*"]
            set tw [lindex [split $tw "="] 1]
            set ru [lsearch -all -inline $udata "ru=*"]
            set ru [lindex [split $ru "="] 1]
            set ct [lindex [lsearch -all -inline $udata "*ct=*"] 0]
            set ct [lindex [split $ct] 4]
            set ct [lindex [split $ct "="] 1]
            set kpp [lsearch -all -inline $udata "kpp=*"]
            set kpp [lindex [split $kpp "="] 1]
            set kv [lsearch -all -inline $udata "kv=*"]
            set kv [lindex [split $kv "="] 1]
            set ver [lsearch -all -inline $udata "ver=*"]
            set ver [lindex [split $ver "="] 1]
            set rn [lsearch -all -inline $udata "rn=*"]
            set rn [lindex [split $rn "="] 1]
            set tpf [lsearch -all -inline $udata "tpf=*"]
            set tpf [lindex [split $tpf "="] 1]
            set ::msn(auth) "lc=$lc,id=$id,tw=$tw,ru=$ru,ct=$ct,kpp=$kpp,kv=$kv,ver=$ver,rn=$rn,tpf=$tpf"
            msn:nexus
        }

        if {$data == "USR $::msn(trid) OK $::msn(account) $::msn(account) 1 0"} {
            msn:echo "::: Now we are logged in."
            # This command will mark us as connected for else people.
            msn:sdata $::msn(sock) "SYN 8 0"
        }
        # SYN command will return our buddy list
        if {[join [lrange [split $data] 0 1]] == "SYN 8"} {
            msn:sdata $::msn(sock) "CHG 9 NLN 0"
        }
        if {[lindex [split $data] 0] == "ClientIP:"} {
            set ::msn(selfip) [lindex [split $data] 1]
        }

        if {[lindex [split $data] 1] == "ClientPort:"} {
            set ::msn(selfport) [lindex [split $data] 1]
            msn:echo "Our IP is: $::msn(selfip) and the port: $::msn(selfport)"
            msn:sdata "SYN 8 0"
        }

        if {[lindex [split $data] 0] == "XFR"} {
            close $::msn(sock)
            set server [lindex [split $data] 3]
            set port [lindex [split $server ":"] 1]
            set server [lindex [split $server ":"] 0]
            incr ::msn(trid)
            msn:Login $server $port
        }

        # Catching errors (this is just a few list of)

        set cmd [lindex [split $data] 0]
        set cparm [lindex [split $data] 1]
        switch -- $cmd {
            "710" {
                msn:echo "!!! Bad CVR parameters sent."
            }
            "711" {
                msn:echo "!!! Write is blocking."
            }
            "712" {
                msn:echo "!!! Session is overloaded."
            }
            "713" {
                msn:echo "!!! Calling too rapidly. This occurs when the client repeatedly calls someone who is offline or blocking them"
                msn:echo "!!! in response to the commands that the server rejects. This is a way to know who is blocking you."
            }
            "714" {
                msn:echo "!!! Too many sessions."
            }
            "715" {
                if {$cparm == "30"} {
                    msn:echo "!!! PRP setting an invalid phone type of three or less characters."
                }
                if {$cparm == "31"} {
                    msn:echo "!!! ERROR- Changing display name (REA) on an unverified Passport account."
                }
            }
            "731" {
                msn:echo "!!! ERROR- Not expected. Bad formatted CVR."
                close $::msn(sock)
                return
            }
        }
    }
}

puts stdout "Msn Client loaded"


I'm the Player2
This post was edited 1 times, last on 06-04-2008, 00:24 by HackeMate
Advanced options for this topic:

Ignore this topic (Do not list this topic in the "unread topics" search. You are currently not ignoring this topic.)
Hide this topic (Hidden topics are not displayed in the topics list. This topic is currently not hidden.)
Go to forum

Unclassified NewsBoard 1.5.3-d | © 2003-4 by Yves Goergen | Time: 163.8 msec, CPU time: 65.9 msec, 30 Database queries in 115.4 msec | 9 kB (53.4 kB) | Timezone: +0200