]> git.lizzy.rs Git - luairc.git/blob - src/irc/dcc.lua
f227d4b15736c7918a460d7ce6f27a53e738dc86
[luairc.git] / src / irc / dcc.lua
1 -- initialization {{{
2 local base =      _G
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'
10 -- }}}
11
12 module 'irc.dcc'
13
14 -- defaults {{{
15 FIRST_PORT = 1028
16 LAST_PORT = 5000
17 -- }}}
18
19 -- private functions {{{
20 -- send_file {{{
21 local function send_file(sock, file, size, packet_size)
22     local bytes = 0
23     while true do
24         local packet = file:read(packet_size)
25         if not packet then break end
26         bytes = bytes + packet:len()
27         local index = 1
28         while true do
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
33             else
34                 break
35             end
36         end
37         if bytes >= size then break end
38         coroutine.yield(true)
39     end
40     file:close()
41     sock:close()
42     irc._unregister_socket(sock, 'w')
43     return true
44 end
45 -- }}}
46
47 -- handle_connect {{{
48 local function handle_connect(ssock, file, size, packet_size)
49     packet_size = packet_size or 1024
50     local sock = ssock:accept()
51     sock:settimeout(0.1)
52     ssock:close()
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)
57                          end))
58     return true
59 end
60 -- }}}
61
62 -- accept_file {{{
63 local function accept_file(sock, file, size, packet_size)
64     local bytes = 0
65     while true do
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))
72         file:write(packet)
73         coroutine.yield(true)
74     end
75     file:close()
76     sock:close()
77     irc._unregister_socket(sock, 'r')
78     return true
79 end
80 -- }}}
81 -- }}}
82
83 -- public functions {{{
84 -- send {{{
85 function send(nick, filename, port)
86     port = port or FIRST_PORT
87     local sock = base.assert(socket.tcp())
88     repeat
89         err, msg = sock:bind('*', port)
90         port = port + 1
91     until msg ~= "address already in use" and port <= LAST_PORT + 1
92     base.assert(err, msg)
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")
97     file:seek("set")
98     irc._register_socket(sock, 'r',
99                          coroutine.wrap(function(sock)
100                              return handle_connect(sock, file, size)
101                          end))
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})
106 end
107 -- }}}
108
109 -- accept {{{
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))
114     sock:settimeout(0.1)
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)
119                          end))
120 end
121 -- }}}
122 -- }}}