salticid 0.9.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.
@@ -0,0 +1,19 @@
1
+ module Salticid::Host::IP
2
+ # Host methods for IP addresses
3
+
4
+ # Get all active IP addresses.
5
+ def ips
6
+ `ifconfig -a`.split("\n\n").map { |stanza|
7
+ stanza.split("\n").find { |line|
8
+ line =~ /inet addr:\s*([\d\.]{7..15})/
9
+ $1
10
+ }
11
+ }.compact
12
+ end
13
+
14
+ def private_ips
15
+ end
16
+
17
+ def public_ips
18
+ end
19
+ end
@@ -0,0 +1,192 @@
1
+ class Salticid
2
+ class Interface
3
+ require 'ncurses'
4
+ require 'salticid/interface/ncurses'
5
+ require 'salticid/interface/resizable'
6
+ require 'salticid/interface/view'
7
+ require 'salticid/interface/tab_view'
8
+ require 'salticid/interface/host_view'
9
+
10
+ COLORS = {
11
+ :info => Ncurses::COLOR_WHITE,
12
+ :error => Ncurses::COLOR_RED,
13
+ :warn => Ncurses::COLOR_YELLOW,
14
+ :debug => Ncurses::COLOR_CYAN,
15
+ :finished => Ncurses::COLOR_GREEN
16
+ }
17
+ COLOR_PAIRS = {}
18
+
19
+ # Keys
20
+ KEY_SPACE = 32
21
+ KEY_ENTER = 13
22
+ KEY_SCROLL_UP = 258
23
+ KEY_SCROLL_DOWN = 259
24
+
25
+ def self.interfaces
26
+ @interfaces ||= []
27
+ end
28
+
29
+ def self.shutdown *args
30
+ @interfaces.each do |i|
31
+ i.shutdown *args
32
+ end
33
+ end
34
+
35
+ attr_reader :hosts, :salticid
36
+
37
+ def initialize(salticid)
38
+ self.class.interfaces << self
39
+
40
+ # Set up ncurses
41
+ Ncurses.initscr
42
+ Ncurses.cbreak
43
+ Ncurses.noecho
44
+ Ncurses.nonl
45
+ Ncurses.stdscr.intrflush false
46
+ Ncurses.stdscr.keypad true
47
+ Ncurses.start_color
48
+ Ncurses.use_default_colors
49
+
50
+ @salticid = salticid
51
+ @hosts = []
52
+ @tabs = TabView.new(
53
+ self,
54
+ :height => 1
55
+ )
56
+
57
+ @tabs.window.keypad true
58
+
59
+ colorize
60
+ end
61
+
62
+ # Add a new tab interface backed by source.
63
+ def add_tab(host)
64
+ @tabs.active.hide if tab
65
+
66
+ hv = HostView.new(
67
+ self,
68
+ :host => host,
69
+ :top => 1,
70
+ :height => Ncurses.LINES - 1
71
+ )
72
+ hv.on_state_change do |state|
73
+ @tabs.render
74
+ end
75
+ @tabs << hv
76
+ tab.show
77
+ end
78
+
79
+ def colorize
80
+ COLORS.each_with_index do |c, i|
81
+ Ncurses.init_pair i + 1, c.last, -1
82
+ COLOR_PAIRS[c.first] = Ncurses.COLOR_PAIR(i + 1)
83
+ end
84
+ end
85
+
86
+ def delete_tab(target)
87
+ begin
88
+ target.hide
89
+ @tabs.delete target
90
+ ensure
91
+ tab.show if tab
92
+ end
93
+ end
94
+
95
+ # Join the mainloop.
96
+ def join
97
+ @main.join
98
+ end
99
+
100
+ # List channels and topics
101
+ def list(*channels)
102
+ @connection.list *channels
103
+ end
104
+
105
+ # Mainloop
106
+ def main
107
+ @main = Thread.new do
108
+ Thread.current.priority = -1
109
+ trap("WINCH") { resize if Thread.current.alive? }
110
+
111
+ loop do
112
+ # Get character
113
+ if IO.select [$stdin], nil, nil, 1
114
+ char = @tabs.window.getch
115
+ else
116
+ Thread.pass
117
+ next
118
+ end
119
+
120
+ # Do stuff
121
+ case char
122
+ when ?\t
123
+ @tabs.scroll
124
+ when ?q
125
+ shutdown
126
+ when Ncurses::KEY_LEFT
127
+ @tabs.scroll -1
128
+ when Ncurses::KEY_RIGHT
129
+ @tabs.scroll 1
130
+ when Ncurses::KEY_PPAGE
131
+ tab.scroll -tab.height / 2
132
+ when Ncurses::KEY_NPAGE
133
+ tab.scroll tab.height / 2
134
+ when Ncurses::KEY_UP
135
+ tab.scroll -1
136
+ when Ncurses::KEY_DOWN
137
+ tab.scroll 1
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ # Resize to fit display
144
+ def resize
145
+ # We need to nuke ncurses to pick up the new dimensions
146
+ Ncurses.def_prog_mode
147
+ Ncurses.endwin
148
+ Ncurses.reset_prog_mode
149
+ height, width = Ncurses.dimensions
150
+
151
+ # Resize tabs
152
+ @tabs.resize(
153
+ :width => width,
154
+ :height => height
155
+ )
156
+ @tabs.render
157
+ end
158
+
159
+ # Shut down interface
160
+ def shutdown(and_exit = true)
161
+ # Shut down views
162
+ @tabs.shutdown
163
+
164
+ # Shut down ncurses
165
+ Ncurses.echo
166
+ Ncurses.nocbreak
167
+ Ncurses.nl
168
+ Ncurses.endwin
169
+
170
+ # Stop interface
171
+ @main.exit rescue nil
172
+
173
+ # Exit if okay
174
+ exit if and_exit
175
+ end
176
+
177
+ # Switch to a different conversation
178
+ def switch(target = nil)
179
+ if target
180
+ # Switch to a specific tab
181
+ @tabs.switch_to_label target
182
+ else
183
+ # Switch to the next tab
184
+ @tabs.scroll
185
+ end
186
+ end
187
+
188
+ def tab
189
+ @tabs.active
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,150 @@
1
+ module IRC
2
+ require ROOT + '/interface'
3
+ require ROOT + '/view'
4
+ class Interface
5
+ class ConversationView < View
6
+
7
+ attr_accessor :messages, :window
8
+
9
+ COLORS = [
10
+ Ncurses::COLOR_WHITE,
11
+ Ncurses::COLOR_RED,
12
+ Ncurses::COLOR_GREEN,
13
+ Ncurses::COLOR_YELLOW,
14
+ Ncurses::COLOR_BLUE,
15
+ Ncurses::COLOR_MAGENTA,
16
+ Ncurses::COLOR_CYAN
17
+ ]
18
+
19
+ def initialize(interface, params = {})
20
+ @messages = []
21
+
22
+ @scroll_position = -1
23
+
24
+ super
25
+
26
+ @color_index = 0
27
+
28
+ @color_map = Hash.new do |hash, key|
29
+ if key
30
+ hash[key] = @color_index.modulo Ncurses.COLOR_PAIRS
31
+ @color_index += 1
32
+ else
33
+ nil
34
+ end
35
+ end
36
+
37
+ colorize
38
+ end
39
+
40
+ def <<(message)
41
+ # Scroll if at bottom
42
+ @scroll_position += 1 if @scroll_position == @messages.size - 1
43
+
44
+ # Add color
45
+ if message.respond_to? :user
46
+ @color_map[message.user.nick]
47
+ end
48
+
49
+ @messages << message
50
+ render
51
+ end
52
+
53
+ # Set up colors
54
+ def colorize
55
+ COLORS.each_with_index do |color, i|
56
+ Ncurses.init_pair i, color, Ncurses::COLOR_BLACK
57
+ end
58
+ end
59
+
60
+ def render
61
+ if @hidden
62
+ return
63
+ end
64
+
65
+ @window.erase
66
+
67
+ lines_left = @height
68
+ message_i = @scroll_position
69
+ while message_i >= 0
70
+ # Message
71
+ message = @messages[message_i]
72
+ message_i -= 1
73
+
74
+ IRC.log "displaying message #{message}"
75
+
76
+ # Time
77
+ time = message.time.strftime "%H:%M:%S"
78
+
79
+ case message
80
+ when PrivMsg
81
+ color = Ncurses.COLOR_PAIR(@color_map[message.user.nick])
82
+ user = message.user.to_s || ''
83
+ text = message.text
84
+ when Event
85
+ user = ''
86
+ text = message.text
87
+ when Command
88
+ user = message.user.to_s || ''
89
+ text = message.text
90
+ else
91
+ user = message.user.to_s || ''
92
+ text = message.command + ' ' + message.params.join(" ")
93
+ end
94
+
95
+ offset = time.length + user.length + 3
96
+
97
+ lines = [text[0, @width - offset]]
98
+ if remaining = text[@width - offset..-1]
99
+ lines += remaining.lines(@width - offset - 1)
100
+ end
101
+
102
+ # Put lines in reverse
103
+ i = lines.size
104
+ while i > 0
105
+ i -= 1
106
+ line = lines[i]
107
+
108
+ lines_left -= 1
109
+ break if lines_left < 0
110
+
111
+ if i.zero?
112
+ # Put top line
113
+ @window.move lines_left, 0
114
+ @window.addstr time + ' '
115
+ @window.attron Ncurses::A_BOLD
116
+ @window.attron color if color
117
+ @window.addstr user
118
+ @window.attroff color if color
119
+ @window.attroff Ncurses::A_BOLD
120
+ @window.addstr ': '
121
+ @window.addstr line
122
+ else
123
+ # Put hanging line
124
+ @window.move lines_left, offset
125
+ @window.addstr line
126
+ end
127
+
128
+ unless @window.cursor[1] == 0
129
+ # Clear rest of line
130
+ @window.clrtoeol
131
+ end
132
+ end
133
+ end
134
+ @window.refresh
135
+ end
136
+
137
+ # Scrolls the window by delta messages
138
+ def scroll(delta)
139
+ @scroll_position += delta
140
+ if @scroll_position < 0
141
+ @scroll_position = 0
142
+ elsif @scroll_position >= @messages.size
143
+ @scroll_position = @messages.size - 1
144
+ end
145
+
146
+ render
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,123 @@
1
+ class Salticid
2
+ class Interface
3
+ class HostView < View
4
+
5
+ attr_accessor :messages, :window, :state
6
+
7
+ def initialize(interface, params = {})
8
+ @messages = []
9
+
10
+ @scroll_position = -1
11
+
12
+ super
13
+
14
+ @host = params[:host]
15
+ @host.on_log do |message|
16
+ self << message
17
+ end
18
+
19
+ @state = nil
20
+ @on_state_change = proc { |state| }
21
+ end
22
+
23
+ def <<(message)
24
+ # Scroll if at bottom
25
+ @scroll_position += 1 if @scroll_position == @messages.size - 1
26
+
27
+ @messages << message
28
+
29
+ if @state != message.severity
30
+ @state = message.severity
31
+ @on_state_change.call(@state)
32
+ end
33
+
34
+ render
35
+ end
36
+
37
+ def on_state_change(&block)
38
+ @on_state_change = block
39
+ end
40
+
41
+ def render
42
+ return if @hidden
43
+
44
+ @window.erase
45
+
46
+ lines_left = @height
47
+ message_i = @scroll_position
48
+ while message_i >= 0
49
+ # Message
50
+ message = @messages[message_i]
51
+ message_i -= 1
52
+
53
+ # Time
54
+ time = message.time.strftime "%H:%M:%S"
55
+
56
+ text = message.text
57
+ color = Interface::COLOR_PAIRS[message.severity]
58
+
59
+ offset = time.length + 1
60
+
61
+ width = @width - offset
62
+ lines = text.scan(/[^\n]{1,#{width}}/m)
63
+
64
+ # Put lines in reverse
65
+ i = lines.size
66
+ while i > 0
67
+ i -= 1
68
+ line = lines[i]
69
+
70
+ lines_left -= 1
71
+ break if lines_left < 0
72
+
73
+ if i.zero?
74
+ # Put top line
75
+ @window.move lines_left, 0
76
+ @window.addstr time + ' '
77
+ @window.attron Ncurses::A_BOLD
78
+ @window.attron color if color
79
+ @window.addstr line
80
+ else
81
+ # Put hanging line
82
+ @window.attron Ncurses::A_BOLD
83
+ @window.attron color if color
84
+ @window.move lines_left, offset
85
+ @window.addstr line
86
+ end
87
+ @window.attroff color if color
88
+ @window.attroff Ncurses::A_BOLD
89
+
90
+ unless @window.cursor[1] == 0
91
+ # Clear rest of line
92
+ @window.clrtoeol
93
+ end
94
+ end
95
+ end
96
+ @window.refresh
97
+ end
98
+
99
+ def to_s
100
+ @host.name
101
+ end
102
+
103
+ # Scrolls the window by delta messages
104
+ def scroll(delta)
105
+ @scroll_position += delta
106
+ if @scroll_position < 0
107
+ @scroll_position = 0
108
+ elsif @scroll_position >= @messages.size
109
+ @scroll_position = @messages.size - 1
110
+ end
111
+
112
+ render
113
+ end
114
+
115
+ def shutdown
116
+ @host.on_log do |message|
117
+ puts message.text
118
+ end
119
+ @host = nil
120
+ end
121
+ end
122
+ end
123
+ end