XDCC-Fetch 1.386
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|