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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
-- initialization {{{
local base = _G
local irc = require 'irc'
local irc_debug = require 'irc.debug'
local misc = require 'irc.misc'
local socket = require 'socket'
local coroutine = require 'coroutine'
local io = require 'io'
local string = require 'string'
-- }}}
module 'irc.dcc'
-- defaults {{{
FIRST_PORT = 1028
LAST_PORT = 5000
-- }}}
-- private functions {{{
-- send_file {{{
local function send_file(sock, file, size, packet_size)
local bytes = 0
while true do
local packet = file:read(packet_size)
if not packet then break end
bytes = bytes + packet:len()
local index = 1
while true do
sock:send(packet, index)
local new_bytes = misc.int_to_str(sock:receive(4))
if new_bytes ~= bytes then
index = packet_size - bytes + new_bytes + 1
else
break
end
end
if bytes >= size then break end
coroutine.yield(true)
end
file:close()
sock:close()
irc._unregister_socket(sock, 'w')
return true
end
-- }}}
-- handle_connect {{{
local function handle_connect(ssock, file, size, packet_size)
packet_size = packet_size or 1024
local sock = ssock:accept()
sock:settimeout(0.1)
ssock:close()
irc._unregister_socket(ssock, 'r')
irc._register_socket(sock, 'w',
coroutine.wrap(function(sock)
return send_file(sock, file, size, packet_size)
end))
return true
end
-- }}}
-- accept_file {{{
local function accept_file(sock, file, size, packet_size)
local bytes = 0
while true do
local packet, err, partial_packet = sock:receive(packet_size)
if not packet and err == "timeout" then packet = partial_packet end
if not packet then break end
if packet:len() == 0 then break end
bytes = bytes + packet:len()
sock:send(misc.str_to_int(bytes))
file:write(packet)
coroutine.yield(true)
end
file:close()
sock:close()
irc._unregister_socket(sock, 'r')
return true
end
-- }}}
-- }}}
-- public functions {{{
-- send {{{
function send(nick, filename, port)
port = port or FIRST_PORT
local sock = base.assert(socket.tcp())
repeat
err, msg = sock:bind('*', port)
port = port + 1
until msg ~= "address already in use" and port <= LAST_PORT + 1
base.assert(err, msg)
base.assert(sock:listen(1))
local ip = misc.ip_str_to_int(irc.get_ip())
local file = base.assert(io.open(filename))
local size = file:seek("end")
file:seek("set")
irc._register_socket(sock, 'r',
coroutine.wrap(function(sock)
return handle_connect(sock, file, size)
end))
filename = misc.basename(filename)
if filename:find(" ") then filename = '"' .. filename .. '"' end
irc.send("PRIVMSG", nick, {"DCC SEND " .. filename .. " " ..
ip .. " " .. port - 1 .. " " .. size})
end
-- }}}
-- accept {{{
function accept(filename, address, port, size, packet_size)
packet_size = packet_size or 1024
local sock = base.assert(socket.tcp())
base.assert(sock:connect(misc.ip_int_to_str(address), port))
sock:settimeout(0.1)
local file = base.assert(io.open(misc.get_unique_filename(filename), "w"))
irc._register_socket(sock, 'r',
coroutine.wrap(function(sock)
return accept_file(sock, file, size, packet_size)
end))
end
-- }}}
-- }}}
|