Module: IRCParser::RFCWireFormat

Defined in:
lib/ircparser/wire/rfc.rb

Overview

Internal: Implements objectification and stringification for the RFC wire format.

Defined Under Namespace

Classes: MessageTokenizer

Constant Summary collapse

MATCH_PREFIX =

Internal: A regular expression which matches a n!u@h mask.

/^:(?<nick>[^@!]+)  (?:!(?<user>[^@]+))?  (?:@(?<host>.+))?$/x.freeze
MATCH_TAG =

Internal: A regular expression which matches a tag.

/^(?<name>[^\s=]+?)(?:=(?<value>[^\s;]+))?$/.freeze
TAG_ESCAPES =

Internal: The characters which need to be escaped in tag values.

{
	'\\\\' => '\\',
	'\:'   => ';',
	'\s'   => "\s",
	'\r'   => "\r",
	'\n'   => "\n",
}.freeze

Class Method Summary collapse

Class Method Details

.__objectify_prefix(prefix) ⇒ Object

Internal: Objectifies the prefix from the RFC wire format to an IRCParser::Prefix.

token - A String containing the prefix in the RFC wire format.



156
157
158
159
160
161
# File 'lib/ircparser/wire/rfc.rb', line 156

def self.__objectify_prefix prefix
	unless MATCH_PREFIX =~ prefix
		raise IRCParser::Error.new(prefix), 'prefix is not a user mask or server name'
	end
	return IRCParser::Prefix.new nick: $~[:nick], user: $~[:user], host: $~[:host]
end

.__objectify_tags(token) ⇒ Object

Internal: Objectifies tags from the RFC wire format to a Hash.

token - A String containing tags in the RFC wire format.



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/ircparser/wire/rfc.rb', line 166

def self.__objectify_tags token
	tags = Hash.new
	token[1..-1].split(';').each do |tag|
		if tag =~ MATCH_TAG
			value = String.new
			value_index = 0
			while !$~['value'].nil? && value_index < $~['value'].size
				if $~['value'][value_index] == '\\'
					escape = $~['value'].slice(value_index, 2)
					if TAG_ESCAPES.include? escape
						value += TAG_ESCAPES[escape]
						value_index += 1
					end
				else
					value += $~['value'][value_index]
				end
				value_index += 1
			end
			tags[$~['name']] = value
		else
			raise IRCParser::Error.new(tag), 'tag is malformed'
		end
	end
	return tags
end

.__stringify_parameters(parameters) ⇒ Object

Internal: Stringifies parameters from an Array to the RFC wire format.

parameters - An Array to stringify to the RFC wire format.



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/ircparser/wire/rfc.rb', line 195

def self.__stringify_parameters parameters
	buffer = String.new
	parameters.each_with_index do |parameter, index|
		trailing = parameter.include? ' '
		if trailing && index != parameters.size-1
			raise IRCParser::Error.new(parameter), 'only the last parameter may contain spaces'
		end

		buffer += ' '
		if trailing || parameter.empty?
			buffer += ':'
			buffer += parameter
			break
		end
		buffer += parameter
	end
	return buffer
end

.__stringify_prefix(prefix) ⇒ Object

Internal: Stringifies the prefix from an IRCParser::Prefix to the RFC wire format.

tags - An IRCParser::Prefix to stringify to the RFC wire format.



217
218
219
220
221
222
# File 'lib/ircparser/wire/rfc.rb', line 217

def self.__stringify_prefix prefix
	buffer = prefix.nick
	buffer += "!#{prefix.user}" unless prefix.user.nil?
	buffer += "@#{prefix.host}" unless prefix.host.nil?
	return buffer
end

.__stringify_tags(tags) ⇒ Object

Internal: Stringifies tags from a Hash to the RFC wire format.

tags - A Hash of tags to stringify to the RFC wire format.



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/ircparser/wire/rfc.rb', line 227

def self.__stringify_tags tags
	buffer = String.new
	tags.each.with_index do |tag, idx|
		key, value = tag
		buffer += key
		unless value.nil? || value.empty?
			buffer += '='
			value.each_char do |chr|
				buffer += if TAG_ESCAPES.value? chr
					TAG_ESCAPES.key chr
				else
					chr
				end
			end
		end
		buffer += ';' if idx < tags.size - 1
	end
	return buffer
end

.objectify(str) ⇒ Object

Internal: Objectifies a message from the RFC wire format to an IRCParser::Message.

str - A String containing a message in the RFC wire format.



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
# File 'lib/ircparser/wire/rfc.rb', line 60

def self.objectify str

	# Ruby really needs some kind of basic type checking.
	unless str.is_a? String
		raise IRCParser::Error.new(str), 'message is not a String'
	end

	# Split the message up into an array of tokens.
	tokenizer = MessageTokenizer.new str
	current_token = tokenizer.read_middle
	components = Hash.new

	# Have we encountered IRCv3 message tags?
	components[:tags] = Hash.new
	if !current_token.nil? && current_token[0] == '@'
		components[:tags] = self.__objectify_tags current_token
		current_token = tokenizer.read_middle
	end

	# Have we encountered the prefix of this message?
	if !current_token.nil? && current_token[0] == ':'
		components[:prefix] = self.__objectify_prefix current_token
		current_token = tokenizer.read_middle
	end

	# The command parameter is mandatory.
	unless current_token.nil?
		components[:command] = current_token.upcase
		current_token = tokenizer.read_trailing
	else
		raise IRCParser::Error.new(str), 'message is missing the command name'
	end

	# Try to parse all of the remaining parameters.
	components[:parameters] = Array.new
	while !current_token.nil?
		components[:parameters] << current_token
		current_token = tokenizer.read_trailing
	end

	return IRCParser::Message.new **components
end

.stringify(obj) ⇒ Object

Internal: Stringifies a message from an IRCParser::Message to the RFC wire format.

obj - An IRCParser::Message to stringify to the RFC wire format.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/ircparser/wire/rfc.rb', line 106

def self.stringify obj

	# Ruby really needs some kind of basic type checking.
	unless obj.is_a? IRCParser::Message
		raise IRCParser::Error.new(obj), 'message is not an IRCParser::Message'
	end

	# Stringify the tags.
	buffer = String.new
	unless obj.tags.empty?
		buffer += '@'
		buffer += self.__stringify_tags obj.tags
		buffer += ' '
	end

	# Stringify the prefix.
	unless obj.prefix.nil?
		buffer += ':'
		buffer += self.__stringify_prefix obj.prefix
		buffer += ' '
	end

	# Stringify the command.
	buffer += obj.command

	# Stringify the parameters
	buffer += self.__stringify_parameters obj.parameters

	# We're done!
	return buffer
end