ratchet 0.3.0
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/gem_bin/ratchet +23 -0
- data/lib/ratchet.rb +613 -0
- data/lib/ratchet/aliases.rb +106 -0
- data/lib/ratchet/bufferparser.rb +409 -0
- data/lib/ratchet/commandbuffer.rb +66 -0
- data/lib/ratchet/commandparser.rb +668 -0
- data/lib/ratchet/configuration.rb +278 -0
- data/lib/ratchet/connections.rb +403 -0
- data/lib/ratchet/constants.rb +111 -0
- data/lib/ratchet/contrib/instance_exec.rb +21 -0
- data/lib/ratchet/eventparser.rb +486 -0
- data/lib/ratchet/gtk/bufferlistview.rb +514 -0
- data/lib/ratchet/gtk/bufferview.rb +167 -0
- data/lib/ratchet/gtk/configwindow.rb +229 -0
- data/lib/ratchet/gtk/connectionwindow.rb +218 -0
- data/lib/ratchet/gtk/keybinding.rb +356 -0
- data/lib/ratchet/gtk/linkwindow.rb +137 -0
- data/lib/ratchet/gtk/mainwindow.rb +504 -0
- data/lib/ratchet/gtk/networkpresenceconf.rb +567 -0
- data/lib/ratchet/gtk/pluginconfig.rb +94 -0
- data/lib/ratchet/gtk/pluginwindow.rb +146 -0
- data/lib/ratchet/gtk/userlistview.rb +161 -0
- data/lib/ratchet/help.rb +64 -0
- data/lib/ratchet/items.rb +271 -0
- data/lib/ratchet/lines.rb +63 -0
- data/lib/ratchet/networks.rb +652 -0
- data/lib/ratchet/plugins.rb +616 -0
- data/lib/ratchet/queue.rb +47 -0
- data/lib/ratchet/ratchet-version.rb +21 -0
- data/lib/ratchet/replies.rb +134 -0
- data/lib/ratchet/replyparser.rb +441 -0
- data/lib/ratchet/tabcomplete.rb +98 -0
- data/lib/ratchet/users.rb +237 -0
- data/lib/ratchet/utils.rb +178 -0
- data/share/defaults.yaml +169 -0
- data/share/glade/config.glade +2634 -0
- data/share/glade/connect.glade +950 -0
- data/share/glade/keybindings.glade +109 -0
- data/share/glade/linkwindow.glade +188 -0
- data/share/glade/mainwindow.glade +335 -0
- data/share/glade/network-presences.glade +1373 -0
- data/share/glade/pluginconf.glade +97 -0
- data/share/glade/plugins.glade +360 -0
- data/share/plugins/colorewrite.rb +193 -0
- data/share/plugins/highlighter.rb +115 -0
- data/share/plugins/mpdplay.rb +123 -0
- data/share/plugins/numberswitcher.rb +30 -0
- data/share/plugins/sysinfo.rb +82 -0
- metadata +96 -0
data/gem_bin/ratchet
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
#get the datadir, which is relative to this file's location
|
|
4
|
+
DATADIR = File.expand_path(__FILE__).
|
|
5
|
+
split(File::SEPARATOR)[0...-2].join(File::SEPARATOR)+File::SEPARATOR+'share'
|
|
6
|
+
begin
|
|
7
|
+
require 'ratchet'
|
|
8
|
+
rescue LoadError
|
|
9
|
+
require 'rubygems'
|
|
10
|
+
require_gem 'ratchet'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
$0 = "ratchet"
|
|
14
|
+
|
|
15
|
+
#start the ball rolling...
|
|
16
|
+
begin
|
|
17
|
+
main = Ratchet::Main.new
|
|
18
|
+
main.start
|
|
19
|
+
rescue Interrupt => detail
|
|
20
|
+
puts 'got keyboard interrupt'
|
|
21
|
+
main.windows.each{|win| win.quit(false)}
|
|
22
|
+
main.quit
|
|
23
|
+
end
|
data/lib/ratchet.rb
ADDED
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
This file is part of the Ratchet project, a client for Icecap.
|
|
3
|
+
Copyright (C) 2005-6 Andrew Thompson
|
|
4
|
+
|
|
5
|
+
This program is free software; you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program; if not, write to the Free Software
|
|
17
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
18
|
+
=end
|
|
19
|
+
|
|
20
|
+
#### ratchet.rb ####
|
|
21
|
+
# This file contains the core methods of the Ratchet::Main class,
|
|
22
|
+
# which is the object at the heart of a ratchet instance
|
|
23
|
+
####
|
|
24
|
+
|
|
25
|
+
require 'libglade2'
|
|
26
|
+
require 'socket'
|
|
27
|
+
require 'rbconfig'
|
|
28
|
+
require 'base64'
|
|
29
|
+
require 'thread'
|
|
30
|
+
require 'monitor'
|
|
31
|
+
require 'yaml'
|
|
32
|
+
require 'scw'
|
|
33
|
+
require 'observer'
|
|
34
|
+
require 'pathname'
|
|
35
|
+
|
|
36
|
+
require 'ratchet/ratchet-version'
|
|
37
|
+
|
|
38
|
+
require 'ratchet/utils'
|
|
39
|
+
|
|
40
|
+
require 'ratchet/contrib/instance_exec'
|
|
41
|
+
|
|
42
|
+
if RUBY_PLATFORM.include?('win32') or RUBY_PLATFORM.include?('mingw32')
|
|
43
|
+
$platform = 'win32'
|
|
44
|
+
$ratchetfolder = File.join(ENV['APPDATA'], 'ratchet')
|
|
45
|
+
else
|
|
46
|
+
$platform = 'linux'
|
|
47
|
+
$ratchetfolder = File.join(ENV['HOME'], '.ratchet')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# begin
|
|
51
|
+
# $:.unshift "lib"
|
|
52
|
+
# require 'net/ssh'
|
|
53
|
+
# $netssh = true
|
|
54
|
+
# rescue LoadError
|
|
55
|
+
$netssh = false
|
|
56
|
+
# end
|
|
57
|
+
|
|
58
|
+
$args = {}
|
|
59
|
+
|
|
60
|
+
Thread.current.priority = 1
|
|
61
|
+
|
|
62
|
+
def parse_args
|
|
63
|
+
args = ARGV
|
|
64
|
+
args.each do |arg|
|
|
65
|
+
while arg[0].chr == '-'
|
|
66
|
+
arg = arg[1, arg.length]
|
|
67
|
+
end
|
|
68
|
+
name, value = arg.split('=')
|
|
69
|
+
if value
|
|
70
|
+
$args[name] = value
|
|
71
|
+
else
|
|
72
|
+
$args[name] = true
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
parse_args
|
|
78
|
+
|
|
79
|
+
#useful for debugging
|
|
80
|
+
Thread.abort_on_exception = true
|
|
81
|
+
|
|
82
|
+
#load all my home rolled ruby files here
|
|
83
|
+
require 'ratchet/help'
|
|
84
|
+
require 'ratchet/constants'
|
|
85
|
+
require 'ratchet/queue'
|
|
86
|
+
require 'ratchet/lines'
|
|
87
|
+
require 'ratchet/configuration'
|
|
88
|
+
require 'ratchet/items'
|
|
89
|
+
require 'ratchet/bufferparser'
|
|
90
|
+
require 'ratchet/plugins'
|
|
91
|
+
require 'ratchet/aliases'
|
|
92
|
+
require 'ratchet/commandparser'
|
|
93
|
+
require 'ratchet/eventparser'
|
|
94
|
+
require 'ratchet/replyparser'
|
|
95
|
+
require 'ratchet/tabcomplete'
|
|
96
|
+
require 'ratchet/users'
|
|
97
|
+
require 'ratchet/gtk/userlistview'
|
|
98
|
+
require 'ratchet/gtk/bufferview'
|
|
99
|
+
require 'ratchet/commandbuffer'
|
|
100
|
+
# #require 'ratchet/buffers'
|
|
101
|
+
require 'ratchet/networks'
|
|
102
|
+
require 'ratchet/gtk/bufferlistview'
|
|
103
|
+
require 'ratchet/replies'
|
|
104
|
+
require 'ratchet/connections'
|
|
105
|
+
require 'ratchet/gtk/keybinding'
|
|
106
|
+
require 'ratchet/gtk/mainwindow'
|
|
107
|
+
require 'ratchet/gtk/configwindow'
|
|
108
|
+
require 'ratchet/gtk/connectionwindow'
|
|
109
|
+
require 'ratchet/gtk/networkpresenceconf'
|
|
110
|
+
require 'ratchet/gtk/linkwindow'
|
|
111
|
+
require 'ratchet/gtk/pluginwindow'
|
|
112
|
+
require 'ratchet/gtk/pluginconfig'
|
|
113
|
+
|
|
114
|
+
module Ratchet
|
|
115
|
+
class Main
|
|
116
|
+
attr_reader :windows, :replies, :connectionwindow, :drift, :config, :console, :networks, :protocols, :buffers
|
|
117
|
+
#extend Plugins
|
|
118
|
+
include PluginAPI
|
|
119
|
+
include EventParser
|
|
120
|
+
include ReplyParser
|
|
121
|
+
#include CommandParser
|
|
122
|
+
|
|
123
|
+
def initialize
|
|
124
|
+
@connection = nil
|
|
125
|
+
@replies = {}
|
|
126
|
+
@keys = {}
|
|
127
|
+
@drift = 0
|
|
128
|
+
@config = Configuration.new
|
|
129
|
+
@windows = []
|
|
130
|
+
@networks = ItemList.new(Network)
|
|
131
|
+
@protocols = ItemList.new(Protocol)
|
|
132
|
+
@inputqueue = MessageQueue.new
|
|
133
|
+
@outputqueue = MessageQueue.new
|
|
134
|
+
@console = ConsoleBuffer.new(self)
|
|
135
|
+
|
|
136
|
+
@buffers = {}
|
|
137
|
+
@inputwatcher = Watcher.new(@inputqueue) {|x| command_parse(*x)}
|
|
138
|
+
@outputwatcher = Watcher.new(@outputqueue) {|x| handle_output(x)}
|
|
139
|
+
Plugin.main = self
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# start the GUI
|
|
143
|
+
def start
|
|
144
|
+
Gtk.init
|
|
145
|
+
settings = Gtk::Settings.default
|
|
146
|
+
settings.gtk_entry_select_on_focus = false
|
|
147
|
+
|
|
148
|
+
reply_reaper
|
|
149
|
+
@connectionwindow = ConnectionWindow.new(self) unless @connectionwindow and @connectionwindow.open?
|
|
150
|
+
if @connectionwindow.autoconnect == true
|
|
151
|
+
@connectionwindow.start_connect
|
|
152
|
+
end
|
|
153
|
+
Gtk.main
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
#connect to icecap, called from connectionwindow
|
|
157
|
+
def connect(type, settings)
|
|
158
|
+
return if @connection
|
|
159
|
+
@connectionwindow.send_text('Connecting...')
|
|
160
|
+
begin
|
|
161
|
+
@connection = ConnectionFactory.spawn(type, self, settings, @connectionwindow)
|
|
162
|
+
rescue IOError
|
|
163
|
+
@connectionwindow.send_text("Error: "+$!)
|
|
164
|
+
return
|
|
165
|
+
rescue ArgumentError
|
|
166
|
+
@connectionwindow.send_text("Error: "+$!+" This is a bug. Please report it.")
|
|
167
|
+
return
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
@connectionwindow.send_text("Connected to irssi2!")
|
|
171
|
+
@connection.listen(self)
|
|
172
|
+
|
|
173
|
+
#@config.get_config
|
|
174
|
+
unless $args['noconfig']
|
|
175
|
+
send_command('getconfig', 'config get;*')
|
|
176
|
+
while @replies['getconfig']
|
|
177
|
+
sleep 1
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
restyle
|
|
181
|
+
@console.buffer.redraw
|
|
182
|
+
|
|
183
|
+
@config['plugins'].each {|plugin| plugin_load(plugin)}
|
|
184
|
+
@config['plugins'] = Plugin.list.values.map{|x| x[:name]}#trim any plugins that failed to load
|
|
185
|
+
@config['windows'].each do |hash|
|
|
186
|
+
puts hash.inspect
|
|
187
|
+
window = MainWindow.new(self, hash)
|
|
188
|
+
@windows.push(window)
|
|
189
|
+
window.draw_from_config
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
@connectionwindow.destroy
|
|
193
|
+
|
|
194
|
+
send_command('protocols', 'protocol list')
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Creates a thread which polls events without completed replies and
|
|
198
|
+
# processes depending on the state of the reply.
|
|
199
|
+
# TODO: This is an ugly function
|
|
200
|
+
def reply_reaper
|
|
201
|
+
# Create the thread, turn down the priority, and loop forever
|
|
202
|
+
@reaperthread = Thread.new do
|
|
203
|
+
Thread.current.priority = -3
|
|
204
|
+
while true
|
|
205
|
+
@replies.each do |key, reply|
|
|
206
|
+
if reply.complete
|
|
207
|
+
@replies.delete(key)
|
|
208
|
+
reply_parse(reply)
|
|
209
|
+
elsif (Time.new - reply.start).to_i > 15
|
|
210
|
+
if reply.retries < 1
|
|
211
|
+
@replies.delete(key)
|
|
212
|
+
send_command(key, reply.origcommand)
|
|
213
|
+
@replies[key].retries = reply.retries+1
|
|
214
|
+
else
|
|
215
|
+
@replies.delete(key)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
sleep 5
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
#TODO: This is an ugly function
|
|
226
|
+
def syncchannels
|
|
227
|
+
@syncchannels = true
|
|
228
|
+
Thread.new do
|
|
229
|
+
Thread.current.priority = -2
|
|
230
|
+
@windows.each do |win|
|
|
231
|
+
win.buffers.channels.each do |channel|
|
|
232
|
+
if !channel.usersync and channel.joined?
|
|
233
|
+
send_command('listchan-'+channel.network.name+channel.name, "channel names;network="+channel.network.name+";channel="+channel.name+";mypresence="+channel.presence)
|
|
234
|
+
while !channel.usersync
|
|
235
|
+
sleep 2
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
win.buffers.channels.each do |channel|
|
|
241
|
+
if !channel.eventsync and channel.joined?
|
|
242
|
+
send_command('events-'+channel.network.name+channel.name, 'event get;end=*;limit=100;filter=&(channel='+channel.name+')(network='+channel.network.name+')(mypresence='+channel.presence+')(!(|(event=client_command_reply)(init=*)(deinit=*)(raw=*)))(time>1)')
|
|
243
|
+
while !channel.eventsync
|
|
244
|
+
sleep 2
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
#~ @serverlist.servers.each do |server|
|
|
250
|
+
#~ server.channels.each do |channel|
|
|
251
|
+
#~ if !channel.usersync and channel.connected
|
|
252
|
+
#~ send_command('listchan-'+server.name+channel.name, "channel names;network="+server.name+";channel="+channel.name+";mypresence="+server.presence)
|
|
253
|
+
#~ while !channel.usersync
|
|
254
|
+
#~ sleep 2
|
|
255
|
+
#~ end
|
|
256
|
+
#~ end
|
|
257
|
+
#~ end
|
|
258
|
+
|
|
259
|
+
#~ server.channels.each do |channel|
|
|
260
|
+
#~ if !channel.eventsync and channel.connected
|
|
261
|
+
#~ send_command('events-'+server.name+channel.name, 'event get;end=*;limit=100;filter=&(channel='+channel.name+')(network='+server.name+')(mypresence='+server.presence+')(!(|(event=client_command_reply)(init=*)(deinit=*)(raw=*)))(time>1)')
|
|
262
|
+
#~ while !channel.eventsync
|
|
263
|
+
#~ sleep 2
|
|
264
|
+
#~ end
|
|
265
|
+
#~ end
|
|
266
|
+
#~ end
|
|
267
|
+
#~ if server.connected
|
|
268
|
+
#~ end
|
|
269
|
+
#~ end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
@syncchannels = nil
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Resets the scw configuration after a ratchet configuration change
|
|
276
|
+
# This is an ugly function, just by the means it has to be done,
|
|
277
|
+
# but there's nothing that can be done about it for the time being
|
|
278
|
+
# since the SCW API is shitty in this respect.
|
|
279
|
+
def restyle
|
|
280
|
+
even = @config['scw_even'].to_hex
|
|
281
|
+
odd = @config['scw_odd'].to_hex
|
|
282
|
+
|
|
283
|
+
# puts even, odd
|
|
284
|
+
|
|
285
|
+
Gtk::RC.parse_string("style \"scwview\" {\
|
|
286
|
+
ScwView::even-row-color = \"#{even}\"\
|
|
287
|
+
ScwView::odd-row-color = \"#{odd}\"\
|
|
288
|
+
ScwView::column-spacing = 5\
|
|
289
|
+
ScwView::row-padding = 2\
|
|
290
|
+
}\n\
|
|
291
|
+
widget \"*.ScwView\" style \"scwview\"")
|
|
292
|
+
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
#CRITICAL TODO: AUGH MY EYES!
|
|
296
|
+
def remove_buffer(buffer)
|
|
297
|
+
@buffers.delete_if{|k,v| v == buffer}
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def add_buffer(*key)
|
|
301
|
+
if buffer = find_buffer(*key)
|
|
302
|
+
return buffer
|
|
303
|
+
end
|
|
304
|
+
#puts key.inspect
|
|
305
|
+
if key[2]
|
|
306
|
+
testkey = key[0..2]
|
|
307
|
+
if network = find_buffer(*key[0..1])
|
|
308
|
+
buffer = ChannelBuffer.new(key[2], network, self)
|
|
309
|
+
else
|
|
310
|
+
puts "undefined network #{key[0..1].inspect}"
|
|
311
|
+
end
|
|
312
|
+
elsif key[3]
|
|
313
|
+
testkey = [key[0], key[1], key[3]]
|
|
314
|
+
if network = find_buffer(*key[0..1])
|
|
315
|
+
buffer = ChatBuffer.new(key[3], network, self)
|
|
316
|
+
else
|
|
317
|
+
puts "undefined network #{key[0..1].inspect}"
|
|
318
|
+
end
|
|
319
|
+
else
|
|
320
|
+
testkey = key[0..1]
|
|
321
|
+
buffer = NetworkBuffer.new(key[0], key[1], self)
|
|
322
|
+
end
|
|
323
|
+
assign_buffer_to_window(buffer) if buffer
|
|
324
|
+
@buffers[testkey] = buffer
|
|
325
|
+
buffer
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def find_buffer(*key)
|
|
329
|
+
if key[2]
|
|
330
|
+
testkey = key[0..2]
|
|
331
|
+
elsif key[3]
|
|
332
|
+
testkey = [key[0], key[1], key[3]]
|
|
333
|
+
else
|
|
334
|
+
testkey = key[0..1]
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
@buffers[testkey]
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def assign_buffer_to_window(buffer)
|
|
341
|
+
#TODO - filter to allow intelligent buffer assignment
|
|
342
|
+
@windows[0].buffers.add_buffer(buffer)#if @windows[0]
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def reassign_buffer_to_window(buffer, window)
|
|
346
|
+
#TODO
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def find_windows_with_buffer(buffer)
|
|
350
|
+
res = []
|
|
351
|
+
@windows.each do |window|
|
|
352
|
+
res << window if window.buffers.include? buffer
|
|
353
|
+
end
|
|
354
|
+
res
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
#what do do when we get disconnected from icecap
|
|
358
|
+
def disconnect
|
|
359
|
+
@connection.close if @connection
|
|
360
|
+
@connection = nil
|
|
361
|
+
@serverlist.servers.each do |server|
|
|
362
|
+
server.disconnect
|
|
363
|
+
server.channels.each {|channel| channel.disconnect}
|
|
364
|
+
end
|
|
365
|
+
@connectionwindow = ConnectionWindow.new unless @connectionwindow and @connectionwindow.open?
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
#connect to a network
|
|
369
|
+
def network_add(name, protocol, address, port)
|
|
370
|
+
unless @serverlist.get_network_by_name(name)
|
|
371
|
+
send_command('addnet', "network add;network="+name+";protocol="+protocol)
|
|
372
|
+
temp = "gateway add;host="+address+";network="+name
|
|
373
|
+
temp += ";port="+port if port != '' and port
|
|
374
|
+
send_command('addhost', temp)
|
|
375
|
+
@networks.add(name, protocol)
|
|
376
|
+
else
|
|
377
|
+
throw_error('Network '+network+' is already defined')
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def network_connect(network, presence)
|
|
382
|
+
if !@serverlist.get_network_by_name(network) and !@networks[network]
|
|
383
|
+
throw_error('Undefined network '+network)
|
|
384
|
+
elsif !@serverlist[network, presence] and !@networks[network].presences[presence]
|
|
385
|
+
throw_error('Undefined presence '+presence)
|
|
386
|
+
else
|
|
387
|
+
send_command('connect', "presence connect;network="+network+";mypresence="+presence)
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def presence_add(network, presence)
|
|
392
|
+
if !@serverlist.get_network_by_name(network) and !@networks[network]
|
|
393
|
+
throw_error('Undefined network '+network)
|
|
394
|
+
elsif @serverlist[network, presence] or @networks[network].presences[presence]
|
|
395
|
+
return true
|
|
396
|
+
else
|
|
397
|
+
cmdstring = "presence add;mypresence="+presence+";network="+network
|
|
398
|
+
if @keys[presence] and @keys[presence]['silc_pub']
|
|
399
|
+
cmdstring += ";pub_key="+@keys[presence]['silc_pub']+";prv_key="+@keys[presence]['silc_priv']
|
|
400
|
+
cmdstring += ";passphrase="+@keys[presence]['silc_pass'] if @keys[presence]['silc_pass']
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
cmdstring.gsub!("\n", "\\n")
|
|
404
|
+
send_command('addpres', cmdstring)
|
|
405
|
+
@networks[network].add_presence(presence)
|
|
406
|
+
return true
|
|
407
|
+
end
|
|
408
|
+
return false
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def channel_add(network, presence, channel)
|
|
412
|
+
if @serverlist[network, presence] and channel
|
|
413
|
+
send_command('add', 'channel add;network='+network+';mypresence='+presence+';channel='+channel)
|
|
414
|
+
else
|
|
415
|
+
throw_error('Invalid Network')
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def throw_error(error, buffer=@console)
|
|
420
|
+
line = Line[ERR => 'Client Error: '+error]
|
|
421
|
+
buffer.send_user_event(line, EVENT_ERROR)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def throw_message(message, buffer=@console)
|
|
425
|
+
line = Line[MSG => 'Client Message: '+message]
|
|
426
|
+
@console.send_user_event(line, EVENT_NOTICE)
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def queue_input(msg)
|
|
430
|
+
@inputqueue.enq(msg)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def queue_output(msg)
|
|
434
|
+
@outputqueue.enq(msg)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def parse_line(line)
|
|
438
|
+
@console.send_user_event({'msg' =>line.chomp}, EVENT_NOTICE) if $args['debug']
|
|
439
|
+
queue_output(line)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
#split by line and parse each line
|
|
443
|
+
def parse_lines(lines)
|
|
444
|
+
lines.each do |line|
|
|
445
|
+
@console.send_user_event({'msg' =>line.chomp}, EVENT_NOTICE) if $args['debug']
|
|
446
|
+
queue_output(line)
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
#send a command to irssi2
|
|
451
|
+
def send_command(tag, command, length=nil)
|
|
452
|
+
if !@connection
|
|
453
|
+
disconnect
|
|
454
|
+
return
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
@replies[tag] = Reply.new(self, tag, command)
|
|
458
|
+
|
|
459
|
+
if length
|
|
460
|
+
cmdstr = '+'+length.to_s+';'+tag+';'+command+"\n"
|
|
461
|
+
else
|
|
462
|
+
cmdstr = tag+';'+command+"\n"
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
puts "[SENT] #{cmdstr}" if $args['debug']
|
|
466
|
+
|
|
467
|
+
sent = @connection.send(cmdstr)
|
|
468
|
+
|
|
469
|
+
if !sent
|
|
470
|
+
@connection = nil
|
|
471
|
+
disconnect
|
|
472
|
+
end
|
|
473
|
+
return @replies[tag]
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
#handle output from icecap
|
|
477
|
+
def handle_output(string)
|
|
478
|
+
return if string.length == 0
|
|
479
|
+
|
|
480
|
+
tag, event = string.split(';', 2)
|
|
481
|
+
|
|
482
|
+
#its an event
|
|
483
|
+
if tag == '*'
|
|
484
|
+
type, event = event.split(';', 2)
|
|
485
|
+
#puts type, event
|
|
486
|
+
line= Line.new
|
|
487
|
+
|
|
488
|
+
line[:event_type] = type
|
|
489
|
+
line['original'] = string
|
|
490
|
+
|
|
491
|
+
items = event.split(';')
|
|
492
|
+
|
|
493
|
+
items.each do |x|
|
|
494
|
+
vals = x.split('=', 2)
|
|
495
|
+
if vals[1] and vals[1] != ''
|
|
496
|
+
line[vals[0].to_sym] = unescape(vals[1])
|
|
497
|
+
elsif x.count('=') == 0
|
|
498
|
+
line[x.to_sym] = true
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
calculate_clock_drift(line['time']) if line['time']
|
|
502
|
+
|
|
503
|
+
if @config['canonicaltime'] == 'client'
|
|
504
|
+
line[:time] = Time.at(line[:time].to_i + @drift)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
event_parse(line)
|
|
508
|
+
#its a reply
|
|
509
|
+
else
|
|
510
|
+
if @replies[tag]
|
|
511
|
+
reply = @replies[tag]
|
|
512
|
+
Thread.new do
|
|
513
|
+
#Thread.current.priority = -3
|
|
514
|
+
reply.addline(string)
|
|
515
|
+
end
|
|
516
|
+
if @replies[tag] and @replies[tag].complete
|
|
517
|
+
Thread.new do
|
|
518
|
+
reply_parse(reply)
|
|
519
|
+
@replies.delete(reply.name)
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
return
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
#keep an eye on the difference between client & server time
|
|
528
|
+
#TODO: There could be a better way to do this
|
|
529
|
+
def calculate_clock_drift(servertime)
|
|
530
|
+
server = Time.at(servertime.to_i)
|
|
531
|
+
client = Time.new
|
|
532
|
+
@drift = (client - server).to_i
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
def handle_error(line, reply)
|
|
536
|
+
channel ||= reply.command['channel']
|
|
537
|
+
network ||= reply.command['network']
|
|
538
|
+
presence ||= reply.command['mypresence']
|
|
539
|
+
|
|
540
|
+
puts line
|
|
541
|
+
return
|
|
542
|
+
|
|
543
|
+
if network = assign_window.buffers.find_network(network, presence)
|
|
544
|
+
target = network
|
|
545
|
+
elsif @serverlist[network, presence] and channel = @serverlist[network, presence][channel]
|
|
546
|
+
target = channel
|
|
547
|
+
else
|
|
548
|
+
target = @window.networks.console
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
if line['bad']
|
|
552
|
+
err = 'Bad line - '+reply.origcommand
|
|
553
|
+
elsif line['args']
|
|
554
|
+
err = 'Bad arguments - '+reply.origcommand
|
|
555
|
+
elsif line['state']
|
|
556
|
+
err = 'Bad state - '+reply.origcommand
|
|
557
|
+
elsif line['unknown']
|
|
558
|
+
err = 'Unknown command - '+reply.command['command']
|
|
559
|
+
elsif line['nogateway']
|
|
560
|
+
err = 'No gateway'
|
|
561
|
+
err += ' for network - '+reply.command['network'] if reply.command['network']
|
|
562
|
+
elsif line['noprotocol']
|
|
563
|
+
err = 'Invalid Protocol'
|
|
564
|
+
err += ' - '+reply.command['protocol'] if reply.command['protocol']
|
|
565
|
+
elsif line['noconnection']
|
|
566
|
+
elsif line['nonetwork']
|
|
567
|
+
err = 'Invalid network'
|
|
568
|
+
err += ' - '+reply.command['network'] if reply.command['network']
|
|
569
|
+
elsif line['nopresence']
|
|
570
|
+
err = 'Invalid or protected presence'
|
|
571
|
+
err += ' - '+reply.command['mypresence'] if reply.command['mypresence']
|
|
572
|
+
elsif line['exists']
|
|
573
|
+
err ='Already Exists'
|
|
574
|
+
elsif line['notfound']
|
|
575
|
+
err = 'Not Found'
|
|
576
|
+
elsif line['reply_lost']
|
|
577
|
+
err = 'Reply to command - '+reply.origcommand+' lost.'
|
|
578
|
+
else
|
|
579
|
+
puts 'unhandled error '+line['original']
|
|
580
|
+
return
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
@window.networks.send_user_event(target, Line['err' => err], EVENT_ERROR)
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
def quit
|
|
587
|
+
#if the connection is dead, don't bother trying to comunicate with irssi2
|
|
588
|
+
if !@connection
|
|
589
|
+
do_quit
|
|
590
|
+
|
|
591
|
+
#update the config and wait for quit response
|
|
592
|
+
else
|
|
593
|
+
send_command('sendconfig', @config.changes)
|
|
594
|
+
send_command('quit', 'quit')
|
|
595
|
+
# puts 'sending quit (timeout 5 seconds...)'
|
|
596
|
+
# sleep 5
|
|
597
|
+
# unless @quit
|
|
598
|
+
# puts 'failed to get quit confirmation, doing it manually'
|
|
599
|
+
# do_quit
|
|
600
|
+
# end
|
|
601
|
+
end
|
|
602
|
+
true
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def do_quit
|
|
606
|
+
@connection.close if @connection
|
|
607
|
+
@reaperthread.kill if @reaperthread
|
|
608
|
+
Gtk.main_quit
|
|
609
|
+
puts 'bye byeeeeee...'
|
|
610
|
+
exit
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
end
|