XDCC-Fetch 1.386
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +23 -0
- data/XDCC-Fetch.rbw +54 -0
- data/doc/ark.png +0 -0
- data/doc/connect_established.png +0 -0
- data/doc/index.html +300 -0
- data/doc/mega_ark.png +0 -0
- data/doc/package.png +0 -0
- data/doc/package_unknown.png +0 -0
- data/doc/shot1.png +0 -0
- data/doc/shot1_mini.png +0 -0
- data/doc/shot2.png +0 -0
- data/doc/shot2_mini.png +0 -0
- data/doc/xdccfetch.css +155 -0
- data/icons/ark.png +0 -0
- data/icons/ark_big.png +0 -0
- data/icons/camera_test.png +0 -0
- data/icons/cancel.png +0 -0
- data/icons/connect_creating.png +0 -0
- data/icons/connect_established.png +0 -0
- data/icons/connect_failed.png +0 -0
- data/icons/connect_no.png +0 -0
- data/icons/edit_add.png +0 -0
- data/icons/edit_remove.png +0 -0
- data/icons/exit.png +0 -0
- data/icons/fileclose.png +0 -0
- data/icons/folder_inbox.png +0 -0
- data/icons/idea.png +0 -0
- data/icons/mega_ark.png +0 -0
- data/icons/messagebox_critical.png +0 -0
- data/icons/messagebox_info.png +0 -0
- data/icons/messagebox_warning.png +0 -0
- data/icons/messagebox_warning_small.png +0 -0
- data/icons/package.png +0 -0
- data/icons/package_favourite.png +0 -0
- data/icons/package_unknown.png +0 -0
- data/src/Console/Console_Parser.rb +71 -0
- data/src/Console/XDCC_Pack_Match_Template.rb +29 -0
- data/src/Console/xdcc-fetch.rb +123 -0
- data/src/GUI/About_Dialog.rb +50 -0
- data/src/GUI/Application_Builder.rb +280 -0
- data/src/GUI/Context_Menu.rb +81 -0
- data/src/GUI/Custom_Tabs.rb +60 -0
- data/src/GUI/Dialog_Box.rb +116 -0
- data/src/GUI/Download_Finished_Box.rb +41 -0
- data/src/GUI/Empty_Text_Field_Handler.rb +86 -0
- data/src/GUI/Gui_Logic.rb +629 -0
- data/src/GUI/Icon_Loader.rb +58 -0
- data/src/GUI/Main_Window.rb +227 -0
- data/src/GUI/Packet_Item.rb +171 -0
- data/src/GUI/Packet_List.rb +145 -0
- data/src/GUI/Speed_Widget.rb +101 -0
- data/src/GUI/Talk_Back.rb +118 -0
- data/src/GUI/Toggle_Button.rb +56 -0
- data/src/Network/CTCP_Handler.rb +61 -0
- data/src/Network/DCC_File.rb +323 -0
- data/src/Network/DCC_Parser.rb +71 -0
- data/src/Network/IPAddr_Ext.rb +76 -0
- data/src/Network/IRC_Message.rb +161 -0
- data/src/Network/IRC_Server.rb +273 -0
- data/src/Network/IRC_Server_Respond_Map.rb +223 -0
- data/src/Network/IRC_User.rb +58 -0
- data/src/Network/TCP_Connection.rb +168 -0
- data/src/Network/XDCC_Announcement.rb +120 -0
- data/src/Network/XDCC_Announcement_Storage.rb +167 -0
- data/src/Network/XDCC_Download_Handler.rb +412 -0
- data/src/Network/XDCC_Pack.rb +58 -0
- data/src/Network/XDCC_Parser.rb +253 -0
- data/src/Translations/README +61 -0
- data/src/Translations/check_translations +83 -0
- data/src/Translations/de.rb +140 -0
- data/src/Translations/en.rb +145 -0
- data/src/Utilities/Configuration.rb +91 -0
- data/src/Utilities/Events.rb +87 -0
- data/src/Utilities/Globals.rb +138 -0
- data/src/Utilities/PrettyException.rb +1091 -0
- data/src/Utilities/Recursive_Open_Struct.rb +159 -0
- data/src/Utilities/Timer.rb +71 -0
- metadata +135 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
# Copyright (c) 2004-2005, Christoph Heindl
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
# are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# * Redistributions of source code must retain the above copyright notice, this list
|
8
|
+
# of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright notice, this list
|
10
|
+
# of conditions and the following disclaimer in the documentation and/or other materials
|
11
|
+
# provided with the distribution.
|
12
|
+
# * Neither the name of Christoph Heindl nor the names of its contributors may be used to
|
13
|
+
# endorse or promote products derived from this software without specific prior written
|
14
|
+
# permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
17
|
+
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
18
|
+
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
19
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
21
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
22
|
+
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
23
|
+
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
|
+
|
25
|
+
|
26
|
+
# Provides a convient interface for dealing with generic IRC messages.
|
27
|
+
# Name of irc users is always downcased for simplicity
|
28
|
+
class IRC_Message
|
29
|
+
attr_accessor :name, :user, :host #prefix
|
30
|
+
attr_accessor :command #command
|
31
|
+
attr_reader :parameters #parameters
|
32
|
+
|
33
|
+
# Construct a IRC_Message based on a command and variable length
|
34
|
+
# command parameters
|
35
|
+
def initialize(command=nil, *params)
|
36
|
+
@name = nil
|
37
|
+
@user = nil
|
38
|
+
@parameters = Array.new
|
39
|
+
@command = command
|
40
|
+
@ctcp_reply = false
|
41
|
+
@ctcp_command = false
|
42
|
+
params.each do |param|
|
43
|
+
self.add_parameter(param)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add a parameter
|
48
|
+
# If parameter equals a ctcp message, appropriate actions (\001 is being removed and internal stati are set) are taken.
|
49
|
+
def add_parameter(param)
|
50
|
+
if @parameters.length < 14
|
51
|
+
if param =~ /^\001[^\001]*\001$/
|
52
|
+
param.gsub!(/\001/, "")
|
53
|
+
if @command == "PRIVMSG"
|
54
|
+
@ctcp_command = true
|
55
|
+
elsif @command == "NOTICE"
|
56
|
+
@ctcp_reply = true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@parameters.push(param)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Is a message prefix available
|
64
|
+
def prefix?
|
65
|
+
@name || (@user && @host)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Is message origin a user or server
|
69
|
+
def usermessage?
|
70
|
+
self.prefix? && @user && @host
|
71
|
+
end
|
72
|
+
|
73
|
+
# Are there any parameters
|
74
|
+
def parameters?
|
75
|
+
@parameters.length > 0
|
76
|
+
end
|
77
|
+
|
78
|
+
# Does the message contain a non-irc standard ctcp part
|
79
|
+
def ctcp?
|
80
|
+
@ctcp_repy || @ctcp_command
|
81
|
+
end
|
82
|
+
|
83
|
+
# Is the message a ctcp command?
|
84
|
+
def ctcp_command?
|
85
|
+
@ctcp_command
|
86
|
+
end
|
87
|
+
|
88
|
+
# Is the message a ctcp reply?
|
89
|
+
def ctcp_reply?
|
90
|
+
@ctcp_reply
|
91
|
+
end
|
92
|
+
|
93
|
+
# Assemble an irc-protocol conform message.
|
94
|
+
def to_s
|
95
|
+
s = ""
|
96
|
+
s += ":" + @name if self.prefix?
|
97
|
+
s += "!" + @user + "@" + @host if self.usermessage?
|
98
|
+
s += " " if self.prefix?
|
99
|
+
s += @command
|
100
|
+
parameters.each do |param|
|
101
|
+
s += " "
|
102
|
+
if param.include?(" ")
|
103
|
+
s += ":"
|
104
|
+
s += "\001" if self.ctcp?
|
105
|
+
s += param
|
106
|
+
s += "\001" if self.ctcp?
|
107
|
+
else
|
108
|
+
s += param
|
109
|
+
end
|
110
|
+
end
|
111
|
+
s += "\r\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
# -- class methods
|
115
|
+
|
116
|
+
# Construct a IRC_Message object from a string. Returns a IRC_Message or nil on error
|
117
|
+
def IRC_Message.parse(str)
|
118
|
+
irc_msg = nil
|
119
|
+
#split string into [prefix] command [arguments]
|
120
|
+
str_no_crlf = str.chop
|
121
|
+
if mdMessage = $cfg.network.irc.msg_regexp.match(str_no_crlf)
|
122
|
+
irc_msg = IRC_Message.new
|
123
|
+
#parse prefix if available
|
124
|
+
if mdMessage[1] && mdPrefix = $cfg.network.irc.prefix_regexp.match(mdMessage[1])
|
125
|
+
irc_msg.name = mdPrefix[1]
|
126
|
+
irc_msg.user = mdPrefix[2] unless mdPrefix[2].empty?
|
127
|
+
irc_msg.host = mdPrefix[3] unless mdPrefix[3].empty?
|
128
|
+
end
|
129
|
+
#set command
|
130
|
+
irc_msg.command = mdMessage[2]
|
131
|
+
#parse parameters if available
|
132
|
+
if !mdMessage[3].empty?
|
133
|
+
# parameter is either a string enclosed by spaces or the remainding line if parameter
|
134
|
+
# starts with ':'
|
135
|
+
mdMessage[3].scan($cfg.network.irc.params_regexp) do |param|
|
136
|
+
# remove possible leading colons and trailing spaces and add to parameters
|
137
|
+
irc_msg.add_parameter(param.sub(/^:/, "").sub(/\s*$/, ""))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
irc_msg
|
142
|
+
end
|
143
|
+
|
144
|
+
# Delete any color codes, font modes from the given str
|
145
|
+
# These control characters are based on the unofficial mirc implementation
|
146
|
+
# Returns clean version of message
|
147
|
+
# \002 => Bold
|
148
|
+
# \003[??][,??] => Forground color, background color
|
149
|
+
# \x0F => Switch back to plain mode
|
150
|
+
# \x16 => Reverse mode
|
151
|
+
# 0x1F => Underline
|
152
|
+
def IRC_Message.delete_control_codes(str)
|
153
|
+
str.gsub(/\002|\003(\d{1,2})?(,\d{1,2})?|\x0F|\x16|\x1F/, "")
|
154
|
+
end
|
155
|
+
|
156
|
+
# Deletes all trailing and leading spaces from a string
|
157
|
+
# Returns clean string
|
158
|
+
def IRC_Message.delete_spaces(str)
|
159
|
+
str.gsub(/^\s+|\s+$/, "")
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
# Copyright (c) 2004-2005, Christoph Heindl
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
# are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# * Redistributions of source code must retain the above copyright notice, this list
|
8
|
+
# of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright notice, this list
|
10
|
+
# of conditions and the following disclaimer in the documentation and/or other materials
|
11
|
+
# provided with the distribution.
|
12
|
+
# * Neither the name of Christoph Heindl nor the names of its contributors may be used to
|
13
|
+
# endorse or promote products derived from this software without specific prior written
|
14
|
+
# permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
17
|
+
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
18
|
+
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
19
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
21
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
22
|
+
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
23
|
+
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
|
+
|
25
|
+
|
26
|
+
require 'src/Network/TCP_Connection.rb'
|
27
|
+
require 'src/Network/IRC_Message.rb'
|
28
|
+
require 'src/Network/IRC_User.rb'
|
29
|
+
require 'src/Network/IRC_Server_Respond_Map.rb'
|
30
|
+
require 'src/Network/DCC_Parser.rb'
|
31
|
+
require 'src/Network/CTCP_Handler.rb'
|
32
|
+
|
33
|
+
# The IRC_Server class represents a connection to an irc server. It allows the caller to connect/disconnect to/from a
|
34
|
+
# server as well as register for various events. Administrative maintainance of connection is done automatically.
|
35
|
+
# The server also keeps a list of IRC_Users it encounters (on channel join, private message, etc..) up to date.
|
36
|
+
class IRC_Server
|
37
|
+
include IRC_Server_Respond_Map, Event_Publisher
|
38
|
+
|
39
|
+
# Corresponds to a irc_user object, which represents us. Nil before connection established
|
40
|
+
attr_reader :me
|
41
|
+
# Password, if any, used for registration
|
42
|
+
attr_reader :password
|
43
|
+
# DCC parser responsible for recognizing initial dcc requests
|
44
|
+
attr_reader :dcc_parser
|
45
|
+
|
46
|
+
# -- Connectable Events
|
47
|
+
|
48
|
+
# Whenever an irc message is received. Args: IRC_Message
|
49
|
+
ON_IRC_MESSAGE = Event_Publisher.next_global_eventID
|
50
|
+
|
51
|
+
# IRC registration with server complete. Args: none
|
52
|
+
ON_SERVER_REGISTERED = Event_Publisher.next_global_eventID
|
53
|
+
# When we quit from irc, or connection to server was lost. Args: errormessage or nil
|
54
|
+
ON_SERVER_DISCONNECTED = Event_Publisher.next_global_eventID
|
55
|
+
# When we connection to server has been established. Args: none
|
56
|
+
ON_SERVER_CONNECTED = Event_Publisher.next_global_eventID
|
57
|
+
|
58
|
+
# On user joined channel. Args: IRC_User, channel
|
59
|
+
ON_USER_JOIN = Event_Publisher.next_global_eventID
|
60
|
+
# On user left channel. Args: IRC_User, channel, partmessage[?]
|
61
|
+
ON_USER_PART = Event_Publisher.next_global_eventID
|
62
|
+
# Whenever someone is kicked from a channel. Args: IRC_User, channel, kickmessage[?]
|
63
|
+
ON_USER_KICK = Event_Publisher.next_global_eventID
|
64
|
+
# On user quit. Args: IRC_User, quitmessage[?]
|
65
|
+
ON_USER_QUIT = Event_Publisher.next_global_eventID
|
66
|
+
# On user changed its nick. Args: updated IRC_User, old nick
|
67
|
+
ON_USER_NICK = Event_Publisher.next_global_eventID
|
68
|
+
# Whenever changing a nick failed. Args: nickname, errormessage
|
69
|
+
ON_USER_NICK_ERROR = Event_Publisher.next_global_eventID
|
70
|
+
# On user sent a message. Args: IRC_User, message, target[+], raw IRC_Message
|
71
|
+
# This contains private messages and notices
|
72
|
+
ON_USER_MESSAGE = Event_Publisher.next_global_eventID
|
73
|
+
|
74
|
+
# On userlist of channel. Args: channel, [status, IRC_User][+]
|
75
|
+
ON_CHANNEL_USER_LIST = Event_Publisher.next_global_eventID
|
76
|
+
# On channel topic notification. Args: channelname, topic
|
77
|
+
ON_CHANNEL_TOPIC = Event_Publisher.next_global_eventID
|
78
|
+
|
79
|
+
# Whenever an unknown user appears. Args: IRC_User
|
80
|
+
ON_USER_APPEAR_CUSTOM = Event_Publisher.next_global_eventID
|
81
|
+
# Whenever a channel has been sucessfully joined by us. Args: channelname
|
82
|
+
ON_CHANNEL_JOIN_SUCCESS = Event_Publisher.next_global_eventID
|
83
|
+
# Whenever a channel join was unsuccessful. Args: channelname, errormessage
|
84
|
+
ON_CHANNEL_JOIN_ERROR = Event_Publisher.next_global_eventID
|
85
|
+
|
86
|
+
# All server side events packed in one
|
87
|
+
ON_ALL_SERVER_EVENTS = ON_SERVER_REGISTERED|
|
88
|
+
ON_SERVER_DISCONNECTED|
|
89
|
+
ON_SERVER_CONNECTED|
|
90
|
+
ON_IRC_MESSAGE
|
91
|
+
|
92
|
+
|
93
|
+
# All user events packaged in one
|
94
|
+
ON_ALL_USER_EVENTS = ON_USER_JOIN|
|
95
|
+
ON_USER_PART|
|
96
|
+
ON_USER_QUIT|
|
97
|
+
ON_USER_NICK|
|
98
|
+
ON_USER_KICK|
|
99
|
+
ON_USER_NICK_ERROR|
|
100
|
+
ON_USER_MESSAGE
|
101
|
+
|
102
|
+
# All channel events packaged in one
|
103
|
+
ON_ALL_CHANNEL_EVENTS = ON_CHANNEL_USER_LIST|
|
104
|
+
ON_CHANNEL_TOPIC
|
105
|
+
|
106
|
+
# All custom events packaged in one
|
107
|
+
ON_ALL_CUSTOM_EVENTS = ON_USER_APPEAR_CUSTOM|
|
108
|
+
ON_CHANNEL_JOIN_SUCCESS|
|
109
|
+
ON_CHANNEL_JOIN_ERROR
|
110
|
+
|
111
|
+
# All events packaged in one
|
112
|
+
ON_ALL_EVENTS = ON_ALL_SERVER_EVENTS|
|
113
|
+
ON_ALL_USER_EVENTS|
|
114
|
+
ON_ALL_CHANNEL_EVENTS|
|
115
|
+
ON_ALL_CUSTOM_EVENTS
|
116
|
+
|
117
|
+
def initialize
|
118
|
+
@tcp_con = nil
|
119
|
+
@registered = false
|
120
|
+
@command_queue = Array.new
|
121
|
+
@user_list = Hash.new
|
122
|
+
@me = nil
|
123
|
+
init_respond_map
|
124
|
+
self.init_events
|
125
|
+
@dcc_parser = DCC_Parser.new(self)
|
126
|
+
@ctcp_handler = CTCP_Handler.new(self)
|
127
|
+
end
|
128
|
+
|
129
|
+
# -- Connection Management
|
130
|
+
|
131
|
+
# Connect to specified server/port using the given user info
|
132
|
+
def connect(server, port, nick, user, password=nil)
|
133
|
+
if !self.connected?
|
134
|
+
#command queue is only allowed during the phase of registration
|
135
|
+
@command_queue.clear
|
136
|
+
@user_list.clear
|
137
|
+
@password = password
|
138
|
+
@me = IRC_User.new(nick, self)
|
139
|
+
@me.user = user
|
140
|
+
@user_list[@me.name.downcase] = @me
|
141
|
+
@tcp_con = TCP_Connection.text
|
142
|
+
@tcp_con.connect_to_events(TCP_Connection::ON_ALL_EVENTS, self)
|
143
|
+
@tcp_con.open(server, port)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Disconnect from server using the given quit message
|
148
|
+
def disconnect(quitmessage="Using XDCC-Fetch")
|
149
|
+
if self.connected?
|
150
|
+
self.send(IRC_Message.new("QUIT", quitmessage))
|
151
|
+
@tcp_con.close if @tcp_con
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Send a IRC_Message to the server we are registered to.
|
156
|
+
# If not yet registered, command is added to the command queue
|
157
|
+
# and will be executed once we are registered
|
158
|
+
def send(irc_msg)
|
159
|
+
if self.registered?
|
160
|
+
@tcp_con.send(irc_msg.to_s)
|
161
|
+
else
|
162
|
+
@command_queue.push(irc_msg)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# -- Status queries
|
167
|
+
|
168
|
+
# Are we connected yet
|
169
|
+
def connected?
|
170
|
+
@tcp_con && @tcp_con.connected?
|
171
|
+
end
|
172
|
+
|
173
|
+
# Was registration successful
|
174
|
+
def registered?
|
175
|
+
self.connected? && @registered
|
176
|
+
end
|
177
|
+
|
178
|
+
# -- Channel management methods
|
179
|
+
|
180
|
+
def join(channel, password=nil)
|
181
|
+
msg = IRC_Message.new("JOIN")
|
182
|
+
msg.add_parameter(channel)
|
183
|
+
msg.add_parameter(password) if password
|
184
|
+
self.send(msg)
|
185
|
+
end
|
186
|
+
|
187
|
+
def part(channel)
|
188
|
+
self.send(IRC_Message.new("PART", channel))
|
189
|
+
end
|
190
|
+
|
191
|
+
# -- User management methods
|
192
|
+
|
193
|
+
# Update user_list by adding non-existant IRC_Users and/or
|
194
|
+
# modifying existing ones
|
195
|
+
def update_user_list(irc_msg)
|
196
|
+
user = nil
|
197
|
+
event = false
|
198
|
+
if irc_msg.prefix?
|
199
|
+
user = @user_list[irc_msg.name.downcase]
|
200
|
+
if !user
|
201
|
+
# new user detected
|
202
|
+
user = IRC_User.new(irc_msg.name, self)
|
203
|
+
@user_list[user.name.downcase] = user
|
204
|
+
event = true
|
205
|
+
end
|
206
|
+
user.user = irc_msg.user if irc_msg.user
|
207
|
+
user.host = irc_msg.host if irc_msg.host
|
208
|
+
if event
|
209
|
+
self.fire_event(ON_USER_APPEAR_CUSTOM, user)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
user
|
213
|
+
end
|
214
|
+
|
215
|
+
# Add user by name
|
216
|
+
def add_user(name)
|
217
|
+
user = nil
|
218
|
+
user = @user_list[name.downcase]
|
219
|
+
if !user
|
220
|
+
# New user
|
221
|
+
user = IRC_User.new(irc_msg.name, self)
|
222
|
+
@user_list[name.downcase] = user
|
223
|
+
end
|
224
|
+
user
|
225
|
+
end
|
226
|
+
|
227
|
+
# Retrieve single user by given name
|
228
|
+
def get_user_by_name(username)
|
229
|
+
@user_list[username]
|
230
|
+
end
|
231
|
+
|
232
|
+
# Loop through all users and yield those users matching the given regexp
|
233
|
+
def scan_users_by_name(regexp)
|
234
|
+
@user_list.values.each do |user|
|
235
|
+
if user.name =~ regexp
|
236
|
+
yield user
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# -- TCP_Connection notify methods
|
242
|
+
|
243
|
+
def on_event(caller, event, eventargs)
|
244
|
+
if caller == @tcp_con
|
245
|
+
case event
|
246
|
+
when TCP_Connection::ON_CONNECTED
|
247
|
+
# Try registering with service, using the parameters given
|
248
|
+
@tcp_con.send(IRC_Message.new("PASS", @password).to_s) if @password
|
249
|
+
@tcp_con.send(IRC_Message.new("NICK", @me.name).to_s)
|
250
|
+
@tcp_con.send(IRC_Message.new("USER", @me.user, "0", "*", "XDCC-Fetcher client").to_s)
|
251
|
+
self.fire_event(ON_SERVER_CONNECTED)
|
252
|
+
|
253
|
+
when TCP_Connection::ON_DATA
|
254
|
+
msg = IRC_Message.parse(eventargs[0])
|
255
|
+
# Find appropriate action for received data and respond appropriate
|
256
|
+
# See IRC_Server_Respond_Map
|
257
|
+
respond_to(msg)
|
258
|
+
|
259
|
+
|
260
|
+
when TCP_Connection::ON_CLOSED
|
261
|
+
@registered = false
|
262
|
+
@tcp_con.disconnect_from_events(TCP_Connection::ON_ALL_EVENTS, self) if @tcp_con
|
263
|
+
self.fire_event(ON_SERVER_DISCONNECTED, nil)
|
264
|
+
|
265
|
+
when TCP_Connection::ON_ERROR
|
266
|
+
@registered = false
|
267
|
+
@tcp_con.disconnect_from_events(TCP_Connection::ON_ALL_EVENTS, self) if @tcp_con
|
268
|
+
self.fire_event(ON_SERVER_DISCONNECTED, eventargs[0])
|
269
|
+
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
# Copyright (c) 2004-2005, Christoph Heindl
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
# are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# * Redistributions of source code must retain the above copyright notice, this list
|
8
|
+
# of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright notice, this list
|
10
|
+
# of conditions and the following disclaimer in the documentation and/or other materials
|
11
|
+
# provided with the distribution.
|
12
|
+
# * Neither the name of Christoph Heindl nor the names of its contributors may be used to
|
13
|
+
# endorse or promote products derived from this software without specific prior written
|
14
|
+
# permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
17
|
+
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
18
|
+
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
19
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
21
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
22
|
+
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
23
|
+
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
|
+
|
25
|
+
|
26
|
+
# The respond map is used within the context of the IRC_Server in order to react
|
27
|
+
# appropriate to the received command/query. The first array element has to be successfully
|
28
|
+
# matched (regexp) against the IRC_Message.command in order to execute the proc object,
|
29
|
+
# which equals the second array element
|
30
|
+
module IRC_Server_Respond_Map
|
31
|
+
def init_respond_map
|
32
|
+
@respond_map = [
|
33
|
+
|
34
|
+
# -- misc
|
35
|
+
|
36
|
+
# Any irc message
|
37
|
+
# Action: forward message to listeners
|
38
|
+
[
|
39
|
+
/.*/,
|
40
|
+
proc do |irc_msg|
|
41
|
+
self.fire_event(IRC_Server::ON_IRC_MESSAGE, irc_msg)
|
42
|
+
end
|
43
|
+
],
|
44
|
+
|
45
|
+
# -- service messages
|
46
|
+
|
47
|
+
# PING
|
48
|
+
# Action: send PONG to server
|
49
|
+
[
|
50
|
+
/PING/i,
|
51
|
+
proc do |irc_msg|
|
52
|
+
# Do not enqueue message if not yet registered.
|
53
|
+
# Some servers do send a PING message as part of registration process.
|
54
|
+
@tcp_con.send(IRC_Message.new("PONG", irc_msg.parameters[0]).to_s)
|
55
|
+
end
|
56
|
+
],
|
57
|
+
|
58
|
+
# -- channel management
|
59
|
+
|
60
|
+
# RPL_NAMREPLY
|
61
|
+
# Action: extract usernames and stati, forward to listeners, update user_list
|
62
|
+
[
|
63
|
+
/353/,
|
64
|
+
proc do |irc_msg|
|
65
|
+
channel = irc_msg.parameters[2]
|
66
|
+
users = irc_msg.parameters[3].scan(/([@+])?(\S+)/)
|
67
|
+
channel_users = []
|
68
|
+
# Store new users in irc_server user list
|
69
|
+
users.each do |user|
|
70
|
+
@user_list[user[1]] ||= IRC_User.new(user[1], self)
|
71
|
+
channel_users.push([user[0], @user_list[user[1]]])
|
72
|
+
end
|
73
|
+
self.fire_event(IRC_Server::ON_CHANNEL_USER_LIST, channel, channel_users)
|
74
|
+
end
|
75
|
+
],
|
76
|
+
|
77
|
+
# RPL_ENDOFNAMES
|
78
|
+
# Action: trigger join channel success
|
79
|
+
[
|
80
|
+
/366/,
|
81
|
+
proc do |irc_msg|
|
82
|
+
self.fire_event(IRC_Server::ON_CHANNEL_JOIN_SUCCESS, irc_msg.parameters[1])
|
83
|
+
end
|
84
|
+
],
|
85
|
+
|
86
|
+
# Error messages when joining a channel
|
87
|
+
#ERR_BANNEDFROMCHAN
|
88
|
+
#ERR_INVITEONLYCHAN ERR_BADCHANNELKEY
|
89
|
+
#ERR_CHANNELISFULL ERR_BADCHANMASK
|
90
|
+
#ERR_NOSUCHCHANNEL ERR_TOOMANYCHANNELS
|
91
|
+
[
|
92
|
+
/474|473|475|471|476|403|405/,
|
93
|
+
proc do |irc_msg|
|
94
|
+
self.fire_event(IRC_Server::ON_CHANNEL_JOIN_ERROR, irc_msg.parameters[1], irc_msg.parameters[2])
|
95
|
+
end
|
96
|
+
],
|
97
|
+
|
98
|
+
# KICK
|
99
|
+
# Action: Inform listeners
|
100
|
+
[
|
101
|
+
/KICK/,
|
102
|
+
proc do |irc_msg|
|
103
|
+
irc_user = @user_list[irc_msg.parameters[1]]
|
104
|
+
if (irc_user)
|
105
|
+
self.fire_event(IRC_Server::ON_USER_KICK, irc_user, irc_msg.parameters[0], irc_msg.parameters[2])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
],
|
109
|
+
|
110
|
+
# -- user management
|
111
|
+
|
112
|
+
# JOIN
|
113
|
+
# Action: Update user_list, inform listeners
|
114
|
+
[
|
115
|
+
/JOIN/i,
|
116
|
+
proc do |irc_msg|
|
117
|
+
user = self.update_user_list(irc_msg)
|
118
|
+
self.fire_event(IRC_Server::ON_USER_JOIN, user, irc_msg.parameters[0])
|
119
|
+
end
|
120
|
+
],
|
121
|
+
|
122
|
+
# PART
|
123
|
+
# Action: update user_list, inform listeners
|
124
|
+
[
|
125
|
+
/PART/i,
|
126
|
+
proc do |irc_msg|
|
127
|
+
user = self.update_user_list(irc_msg)
|
128
|
+
self.fire_event(
|
129
|
+
IRC_Server::ON_USER_PART,
|
130
|
+
user,
|
131
|
+
irc_msg.parameters[0],
|
132
|
+
irc_msg.parameters[1])
|
133
|
+
end
|
134
|
+
],
|
135
|
+
|
136
|
+
# NICK
|
137
|
+
# Action: update user_list, inform listeners
|
138
|
+
[
|
139
|
+
/NICK/i,
|
140
|
+
proc do |irc_msg|
|
141
|
+
# Get user from user_list, possibly update data
|
142
|
+
user = self.update_user_list(irc_msg)
|
143
|
+
# Delete old user
|
144
|
+
new_user = @user_list.delete(user.name.downcase)
|
145
|
+
new_user.name = irc_msg.parameters[0]
|
146
|
+
@user_list[new_user.name.downcase] = new_user
|
147
|
+
self.fire_event(
|
148
|
+
IRC_Server::ON_USER_NICK,
|
149
|
+
new_user,
|
150
|
+
user.name)
|
151
|
+
end
|
152
|
+
],
|
153
|
+
|
154
|
+
# NICK errors
|
155
|
+
# ERR_NONICKNAMEGIVEN
|
156
|
+
# ERR_ERRONEUSNICKNAME (invalid nickname)
|
157
|
+
# ERR_NICKNAMEINUSE
|
158
|
+
# ERR_NICKCOLLISION
|
159
|
+
[
|
160
|
+
/431|432|433|436/,
|
161
|
+
proc do |irc_msg|
|
162
|
+
self.fire_event(IRC_Server::ON_USER_NICK_ERROR, irc_msg.parameters[1], irc_msg.parameters[2])
|
163
|
+
end
|
164
|
+
],
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
# QUIT
|
169
|
+
# Action: update user_list and inform listeners
|
170
|
+
[
|
171
|
+
/QUIT/i,
|
172
|
+
proc do |irc_msg|
|
173
|
+
user = @user_list.delete(irc_msg.name)
|
174
|
+
if user
|
175
|
+
self.fire_event(IRC_Server::ON_USER_QUIT, user, irc_msg.parameters[0])
|
176
|
+
end
|
177
|
+
end
|
178
|
+
],
|
179
|
+
|
180
|
+
# PRIVMSG && NOTICE
|
181
|
+
# Action: inform listeners
|
182
|
+
[
|
183
|
+
/PRIVMSG|NOTICE/i,
|
184
|
+
proc do |irc_msg|
|
185
|
+
user = @user_list[irc_msg.name]
|
186
|
+
if !user
|
187
|
+
# private message from unknown user
|
188
|
+
user = IRC_User.new(irc_msg.name, self)
|
189
|
+
user.user = irc_msg.user
|
190
|
+
user.host = irc_msg.host
|
191
|
+
@user_list[user.name] = user
|
192
|
+
end
|
193
|
+
msg = irc_msg.parameters[-1]
|
194
|
+
targets = irc_msg.parameters[0..-2]
|
195
|
+
self.fire_event(IRC_Server::ON_USER_MESSAGE, user, msg, targets, irc_msg)
|
196
|
+
end
|
197
|
+
],
|
198
|
+
|
199
|
+
# -- others
|
200
|
+
|
201
|
+
# RPL_WELCOME
|
202
|
+
# Action: mark irc_server registered and inform listeners. Send queued commands
|
203
|
+
[
|
204
|
+
/001/,
|
205
|
+
proc do |irc_msg|
|
206
|
+
@registered = true
|
207
|
+
self.fire_event(IRC_Server::ON_SERVER_REGISTERED)
|
208
|
+
@command_queue.each do |cmd|
|
209
|
+
self.send(cmd)
|
210
|
+
end
|
211
|
+
@command_queue.clear
|
212
|
+
end
|
213
|
+
]
|
214
|
+
]
|
215
|
+
end
|
216
|
+
|
217
|
+
def respond_to(msg)
|
218
|
+
@respond_map.each do |response|
|
219
|
+
response[1].call(msg) if msg.command =~ response[0]
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|