📄 protocol.tcl
字号:
# Microsoft Messenger Protocol Implementation#=======================================================================if { $initialize_amsn == 1 } { global list_BLP list_cmdhnd sb_list contactlist_loaded set contactlist_loaded 0 #To be deprecated and replaced with ::abook thing set list_BLP -1 #Clear all user infomation ::abook::clearData set list_cmdhnd [list] set sb_list [list] package require base64 package require sha1 package require snit package require SOAP}namespace eval ::MSNFT { namespace export inviteFT acceptFT rejectFT #TODO: Instead of using a list, use many variables: ft_name, ft_sockid... # If type is = 1 then it's an MSNP2P file send proc invitationReceived { filename filesize cookie chatid fromlogin {type "0"}} { variable filedata if { $type == 0 } { set filedata($cookie) [list "$filename" $filesize $chatid $fromlogin "receivewait" "ipaddr"] after 300000 "::MSNFT::DeleteFT $cookie" SendMessageFIFO [list ::amsn::fileTransferRecv $filename $filesize $cookie $chatid $fromlogin] "::amsn::messages_stack($chatid)" "::amsn::messages_flushing($chatid)" #set filetoreceive [list "$filename" $filesize] } elseif { $type == 1 } { set filedata($cookie) [list "$filename" $filesize $chatid $fromlogin] } } proc acceptReceived {cookie chatid fromlogin message} { variable filedata #status_log "DATA: $cookie $chatid $fromlogin $message $body\n" if {![info exists filedata($cookie)]} { return } #set requestdata [string range $requestdata 0 [expr {[string length requestdata] -2}]] set requestdata [$message getField Request-Data] status_log "Ok, so here we have cookie=$cookie, requestdata=$requestdata\n" red if { $requestdata != "IP-Address:" } { status_log "Requested data is not IP-Address!!: $requestdata\n" red return } set ipaddr [$message getField $requestdata] #If IP field is blank, and we are sender, Send the File and requested IP (SendFile) if { ($ipaddr == "") && ([getTransferType $cookie]=="send") } { status_log "Invitation to filetransfer $cookie accepted\n" black SendMessageFIFO [list ::amsn::acceptedFT $chatid $fromlogin [getFilename $cookie]] "::amsn::messages_stack($chatid)" "::amsn::messages_flushing($chatid)" set newcookie [::md5::md5 "$cookie$fromlogin"] set filedata($newcookie) $filedata($cookie) SendFile $newcookie $cookie #TODO: Show accept or reject messages from other users? (If transferType=="receive") } elseif {($ipaddr == "") && ([getTransferType $cookie]!="send")} { SendMessageFIFO [list ::amsn::acceptedFT $chatid $fromlogin [getFilename $cookie]] "::amsn::messages_stack($chatid)" "::amsn::messages_flushing($chatid)" #If message comes from sender, and we are receiver, connect } elseif { ($fromlogin == [lindex $filedata($cookie) 3]) && ([getTransferType $cookie]=="receive")} { after cancel "::MSNFT::timeoutedFT $cookie" set port [$message getField Port] set authcookie [$message getField AuthCookie] #status_log "Body: $body\n" ConnectMSNFTP $ipaddr $port $authcookie $cookie } } proc getUsername { cookie } { variable filedata if {[info exists filedata($cookie)]} { return [lindex $filedata($cookie) 3] } return "" } proc getFilename { cookie } { variable filedata if {[info exists filedata($cookie)]} { return [lindex $filedata($cookie) 0] } return "" } proc getTransferType { cookie } { variable filedata if {[info exists filedata($cookie)]} { return [lindex $filedata($cookie) 4] } return "" } proc cancelFT { cookie } { variable filedata if {[info exists filedata($cookie)]} { ::amsn::FTProgress ca $cookie [lindex $filedata($cookie) 0] set sockid [lindex $filedata($cookie) 6] catch {puts $sockid "CCL\n"} DeleteFT $cookie status_log "File transfer manually canceled\n" } } proc timeoutedFT { cookie } { variable filedata after cancel "::MSNFT::timeoutedFT $cookie" if {[info exists filedata($cookie)]} { ::amsn::FTProgress e $cookie [lindex $filedata($cookie) 0] DeleteFT $cookie status_log "File transfer timeouted\n" } } proc FinishedFT { cookie } { variable filedata set filename [file join [::config::getKey receiveddir] [lindex $filedata($cookie) 0] ] set finishedname [filenoext $filename] if { [string range $filename [expr [string length $filename] - 11] [string length $filename]] == ".incomplete" } { if { [catch { file rename $filename $finishedname } ] } { ::amsn::infoMsg [trans couldnotrename $filename] warning } } DeleteFT $cookie status_log "File transfer finished ok\n" } proc DeleteFT { cookie } { variable filedata if {[info exists filedata($cookie)] } { set sockid [lindex $filedata($cookie) 6] set fileid [lindex $filedata($cookie) 7] status_log "Closing FT socket $sockid\n" catch {fileevent $sockid writable ""} catch {fileevent $sockid readable ""} catch {close $sockid} status_log "Closing FT file $fileid\n" catch {close $fileid} unset filedata($cookie) } } ################################# #All about receiving files ################################# proc acceptFT {chatid cookie} { #Send the acceptation for a file transfer, request IP variable filedata if { ![info exists filedata($cookie)]} { return -1 } after cancel "::MSNFT::DeleteFT $cookie" set filedata($cookie) [lreplace $filedata($cookie) 4 4 "receive"] set msg "MIME-Version: 1.0\r\nContent-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" set msg "${msg}Invitation-Command: ACCEPT\r\n" set msg "${msg}Invitation-Cookie: $cookie\r\n" set msg "${msg}Launch-Application: FALSE\r\n" set msg "${msg}Request-Data: IP-Address:\r\n\r\n" set msg [encoding convertto utf-8 $msg] set msg_len [string length $msg] set sbn [::MSN::SBFor $chatid] if {$sbn == 0 } { cancelFT $cookie return 0 } set sock [$sbn cget -sock] ::MSN::WriteSBNoNL $sbn "MSG" "U $msg_len\r\n$msg" after 20000 "::MSNFT::timeoutedFT $cookie" ::amsn::FTProgress a $cookie [lindex $filedata($cookie) 0] return 1 } proc rejectFT {chatid cookie} { set sbn [::MSN::SBFor $chatid] if {$sbn == 0 } { cancelFT $cookie return 0 } #Send the cancellation for a file transfer set msg "MIME-Version: 1.0\r\nContent-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" set msg "${msg}Invitation-Command: CANCEL\r\n" set msg "${msg}Invitation-Cookie: $cookie\r\n" set msg "${msg}Cancel-Code: REJECT\r\n\r\n" set msg [encoding convertto utf-8 $msg] set msg_len [string length $msg] ::MSN::WriteSBNoNL $sbn "MSG" "U $msg_len\r\n$msg" status_log "Rejecting filetransfer sent\n" red cancelFT $cookie } proc ConnectMSNFTP {ipaddr port authcookie cookie} { #I connect to a remote host to retrieve the file variable filedata if {![info exists filedata($cookie)]} { status_log "ConnectMSNFTP: Ignoring file transfer, filedata($cookie) doesn't exists, cancelled\n" red return } status_log "Connecting to $ipaddr port $port\n" ::amsn::FTProgress c $cookie [lindex $filedata($cookie) 0] $ipaddr $port if { [catch {set sockid [socket -async $ipaddr $port]} res ]} { set filename [lindex $filedata($cookie) 0] cancelFT $cookie ::amsn::FTProgress e $cookie $filename return } lappend filedata($cookie) $sockid #TODO: What are we cancelling here? after cancel "::MSNFT::cancelFT $cookie" fconfigure $sockid -blocking 0 -translation {binary binary} -buffering line fileevent $sockid writable "::MSNFT::ConnectedMSNFTP $sockid $authcookie $cookie" } proc ConnectedMSNFTP {sockid authcookie cookie} { variable filedata if {![info exists filedata($cookie)]} { status_log "ConnectedMSNFTP: Ignoring file transfer, filedata($cookie) doesn't exists, cancelled\n" red return } set error_msg [fconfigure $sockid -error] if {$error_msg != ""} { status_log "Can't connect to server: $error_msg!!\n" white set filename [lindex $filedata($cookie) 0] cancelFT $cookie ::amsn::FTProgress e $cookie $filename return } fileevent $sockid writable "" fileevent $sockid readable "::MSNFT::FTNegotiation $sockid $cookie 0 $authcookie" status_log "Connected, going to give my identity\n" ::amsn::FTProgress i $cookie [lindex $filedata($cookie) 0] status_log "I SEND: VER MSNFTP\r\n" catch {puts $sockid "VER MSNFTP\r"} } proc FTNegotiation { sockid cookie state {authcookie ""}} { variable filedata if {![info exists filedata($cookie)]} { status_log "ConnectedMSNFTP: Ignoring file transfer, filedata($cookie) doesn't exists, cancelled\n" red return } if { [eof $sockid] } { status_log "FTNegotiation:: EOF\n" white set filename [lindex $filedata($cookie) 0] cancelFT $cookie ::amsn::FTProgress l $cookie $filename return } gets $sockid tmpdata status_log "FTNegotiation: I RECEIVE: $tmpdata\n" if { $tmpdata == "" } { update idletasks return } switch $state { 0 { if {[string range $tmpdata 0 9] == "VER MSNFTP"} { catch {fileevent $sockid readable "::MSNFT::FTNegotiation $sockid $cookie 1"} catch {puts $sockid "USR [::config::getKey login] $authcookie\r"} status_log "FTNegotiation: I SEND: USR [::config::getKey login] $authcookie\r\n" } else { status_log "FT failed in state 0\n" red set filename [lindex $filedata($cookie) 0] cancelFT $cookie ::amsn::FTProgress l $cookie $filename } } 1 { if {[string range $tmpdata 0 2] == "FIL"} { set filesize [string range $tmpdata 4 [expr {[string length $tmpdata]-2}]] if { "$filesize" != "[lindex $filedata($cookie) 1]" } { status_log "Filesize is now $filesize and was [lindex $filedata($cookie) 1] before!!\n" white #cancelFT $cookie #return } status_log "FTNegotiation: They send me file with size $filesize\n" catch {puts $sockid "TFR\r"} status_log "Receiving file...\n" set filename [file join [::config::getKey receiveddir] [lindex $filedata($cookie) 0]] set origfile $filename set num 1 while { [file exists $filename] } { set filename "[filenoext $origfile] $num[fileext $origfile]" incr num } if {[catch {open $filename w} fileid]} { # Cannot create this file. Abort. status_log "Could not saved the file '$filename' (write-protected target directory?)\n" red cancelFT $cookie ::amsn::FTProgress l $cookie $filename ::amsn::infoMsg [trans readonlymsgbox] warning return } lappend filedata($cookie) $fileid fconfigure $fileid -blocking 1 -buffering none -translation {binary binary} #Receive the file fconfigure $sockid -blocking 0 -translation {binary binary} -buffering full -buffersize 16384 catch {fileevent $sockid readable "::MSNFT::ReceivePacket $sockid $fileid $filesize $cookie"} } else { status_log "FT failed in state 1\n" red set filename [lindex $filedata($cookie) 0] cancelFT $cookie ::amsn::FTProgress l $cookie $filename } } default { status_log "FTNegotiation: Unknown state!!!\n" white cancelFT $cookie } } } proc ReceivePacket { sockid fileid filesize cookie} { #Get a packet from the file transfer variable filedata if {![info exists filedata($cookie)]} { status_log "ConnectedMSNFTP: Ignoring file transfer, filedata($cookie) doesn't exists, cancelled\n" red return } if { [eof $sockid] } { status_log "ReveivePacket EOF\n" white set filename [lindex $filedata($cookie) 0] cancelFT $cookie ::amsn::FTProgress l $cookie $filename return } fileevent $sockid readable "" set recvbytes [tell $fileid] set packetrest [expr {2045 - ($recvbytes % 2045)}] if {$packetrest == 2045} { #Need a full packet, header included ::amsn::FTProgress r $cookie [lindex $filedata($cookie) 0] $recvbytes $filesize update idletasks fconfigure $sockid -blocking 1 set header [read $sockid 3] set packet1 1 binary scan $header ccc packet1 packet2 packet3 #If packet1 is 1 -- Transfer canceled by the other if { ($packet1 != 0) } { status_log "File transfer cancelled by remote with packet1=$packet1\n" cancelFT $cookie return } #If you want to cancel, send "CCL\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -