3 local irc = require 'irc'
4 local irc_debug = require 'irc.debug'
5 local misc = require 'irc.misc'
6 local socket = require 'socket'
7 local coroutine = require 'coroutine'
8 local io = require 'io'
9 local string = require 'string'
19 -- private functions {{{
21 local function send_file(sock, file, size, packet_size)
24 local packet = file:read(packet_size)
25 if not packet then break end
26 bytes = bytes + packet:len()
29 sock:send(packet, index)
30 local new_bytes = misc.int_to_str(sock:receive(4))
31 if new_bytes ~= bytes then
32 index = packet_size - bytes + new_bytes + 1
37 if bytes >= size then break end
42 irc._unregister_socket(sock, 'w')
48 local function handle_connect(ssock, file, size, packet_size)
49 packet_size = packet_size or 1024
50 local sock = ssock:accept()
53 irc._unregister_socket(ssock, 'r')
54 irc._register_socket(sock, 'w',
55 coroutine.wrap(function(sock)
56 return send_file(sock, file, size, packet_size)
63 local function accept_file(sock, file, size, packet_size)
66 local packet, err, partial_packet = sock:receive(packet_size)
67 if not packet and err == "timeout" then packet = partial_packet end
68 if not packet then break end
69 if packet:len() == 0 then break end
70 bytes = bytes + packet:len()
71 sock:send(misc.str_to_int(bytes))
77 irc._unregister_socket(sock, 'r')
83 -- public functions {{{
85 function send(nick, filename, port)
86 port = port or FIRST_PORT
87 local sock = base.assert(socket.tcp())
89 err, msg = sock:bind('*', port)
91 until msg ~= "address already in use" and port <= LAST_PORT + 1
93 base.assert(sock:listen(1))
94 local ip = misc.ip_str_to_int(irc.get_ip())
95 local file = base.assert(io.open(filename))
96 local size = file:seek("end")
98 irc._register_socket(sock, 'r',
99 coroutine.wrap(function(sock)
100 return handle_connect(sock, file, size)
102 filename = misc.basename(filename)
103 if filename:find(" ") then filename = '"' .. filename .. '"' end
104 irc.send("PRIVMSG", nick, {"DCC SEND " .. filename .. " " ..
105 ip .. " " .. port - 1 .. " " .. size})
110 function accept(filename, address, port, size, packet_size)
111 packet_size = packet_size or 1024
112 local sock = base.assert(socket.tcp())
113 base.assert(sock:connect(misc.ip_int_to_str(address), port))
115 local file = base.assert(io.open(misc.get_unique_filename(filename), "w"))
116 irc._register_socket(sock, 'r',
117 coroutine.wrap(function(sock)
118 return accept_file(sock, file, size, packet_size)