XDCC-Fetch 1.386

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/COPYING +23 -0
  2. data/XDCC-Fetch.rbw +54 -0
  3. data/doc/ark.png +0 -0
  4. data/doc/connect_established.png +0 -0
  5. data/doc/index.html +300 -0
  6. data/doc/mega_ark.png +0 -0
  7. data/doc/package.png +0 -0
  8. data/doc/package_unknown.png +0 -0
  9. data/doc/shot1.png +0 -0
  10. data/doc/shot1_mini.png +0 -0
  11. data/doc/shot2.png +0 -0
  12. data/doc/shot2_mini.png +0 -0
  13. data/doc/xdccfetch.css +155 -0
  14. data/icons/ark.png +0 -0
  15. data/icons/ark_big.png +0 -0
  16. data/icons/camera_test.png +0 -0
  17. data/icons/cancel.png +0 -0
  18. data/icons/connect_creating.png +0 -0
  19. data/icons/connect_established.png +0 -0
  20. data/icons/connect_failed.png +0 -0
  21. data/icons/connect_no.png +0 -0
  22. data/icons/edit_add.png +0 -0
  23. data/icons/edit_remove.png +0 -0
  24. data/icons/exit.png +0 -0
  25. data/icons/fileclose.png +0 -0
  26. data/icons/folder_inbox.png +0 -0
  27. data/icons/idea.png +0 -0
  28. data/icons/mega_ark.png +0 -0
  29. data/icons/messagebox_critical.png +0 -0
  30. data/icons/messagebox_info.png +0 -0
  31. data/icons/messagebox_warning.png +0 -0
  32. data/icons/messagebox_warning_small.png +0 -0
  33. data/icons/package.png +0 -0
  34. data/icons/package_favourite.png +0 -0
  35. data/icons/package_unknown.png +0 -0
  36. data/src/Console/Console_Parser.rb +71 -0
  37. data/src/Console/XDCC_Pack_Match_Template.rb +29 -0
  38. data/src/Console/xdcc-fetch.rb +123 -0
  39. data/src/GUI/About_Dialog.rb +50 -0
  40. data/src/GUI/Application_Builder.rb +280 -0
  41. data/src/GUI/Context_Menu.rb +81 -0
  42. data/src/GUI/Custom_Tabs.rb +60 -0
  43. data/src/GUI/Dialog_Box.rb +116 -0
  44. data/src/GUI/Download_Finished_Box.rb +41 -0
  45. data/src/GUI/Empty_Text_Field_Handler.rb +86 -0
  46. data/src/GUI/Gui_Logic.rb +629 -0
  47. data/src/GUI/Icon_Loader.rb +58 -0
  48. data/src/GUI/Main_Window.rb +227 -0
  49. data/src/GUI/Packet_Item.rb +171 -0
  50. data/src/GUI/Packet_List.rb +145 -0
  51. data/src/GUI/Speed_Widget.rb +101 -0
  52. data/src/GUI/Talk_Back.rb +118 -0
  53. data/src/GUI/Toggle_Button.rb +56 -0
  54. data/src/Network/CTCP_Handler.rb +61 -0
  55. data/src/Network/DCC_File.rb +323 -0
  56. data/src/Network/DCC_Parser.rb +71 -0
  57. data/src/Network/IPAddr_Ext.rb +76 -0
  58. data/src/Network/IRC_Message.rb +161 -0
  59. data/src/Network/IRC_Server.rb +273 -0
  60. data/src/Network/IRC_Server_Respond_Map.rb +223 -0
  61. data/src/Network/IRC_User.rb +58 -0
  62. data/src/Network/TCP_Connection.rb +168 -0
  63. data/src/Network/XDCC_Announcement.rb +120 -0
  64. data/src/Network/XDCC_Announcement_Storage.rb +167 -0
  65. data/src/Network/XDCC_Download_Handler.rb +412 -0
  66. data/src/Network/XDCC_Pack.rb +58 -0
  67. data/src/Network/XDCC_Parser.rb +253 -0
  68. data/src/Translations/README +61 -0
  69. data/src/Translations/check_translations +83 -0
  70. data/src/Translations/de.rb +140 -0
  71. data/src/Translations/en.rb +145 -0
  72. data/src/Utilities/Configuration.rb +91 -0
  73. data/src/Utilities/Events.rb +87 -0
  74. data/src/Utilities/Globals.rb +138 -0
  75. data/src/Utilities/PrettyException.rb +1091 -0
  76. data/src/Utilities/Recursive_Open_Struct.rb +159 -0
  77. data/src/Utilities/Timer.rb +71 -0
  78. metadata +135 -0
@@ -0,0 +1,81 @@
1
+ # Copyright (c) 2004, 2005 Martin Ankerl
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 Martin Ankerl 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
+ # Context_Menu is a more convenient way to use context menus. It allows the creation of states that enable/disable items.
26
+ class Context_Menu
27
+ attr_accessor :data
28
+
29
+ # Creates a new Context_Menu for given parent. If you provide a block,
30
+ # this code is called whenever the menu is shown.
31
+ def initialize(parent, title="", icon=nil, &proc) # :yields: self, sender, sel, data
32
+ @proc = proc
33
+ @data = nil
34
+ @menu_commands = Array.new
35
+ @states = Hash.new
36
+ @parent = parent
37
+ @pane = FXMenuPane.new(parent)
38
+ @title = FXMenuTitle.new(parent, title, icon, @pane)
39
+
40
+ #@parent.connect(SEL_RIGHTBUTTONRELEASE, method(:on_right_click))
41
+ end
42
+
43
+ # Add an FXMenuSeparator separator.
44
+ def add_separator
45
+ FXMenuSeparator.new(@pane)
46
+ @pane.recalc
47
+ end
48
+
49
+ # Add a new entry to the context menu. The supplied code is called
50
+ # when this entry is activated.
51
+ def add(text, icon=nil, &proc) # :yields: self, sender, sel, data
52
+ cmd = FXMenuCommand.new(@pane, text, icon)
53
+ @menu_commands.push cmd
54
+ cmd.connect(SEL_COMMAND) { |sender, sel, data| proc.call(self, sender, sel, data) }
55
+ @pane.recalc
56
+ cmd
57
+ end
58
+
59
+ # Create a new state which can later be accessed using the key state_name.
60
+ # For each menu entry, you need to specify if it should be enabled or disabled (true/false).
61
+ def new_state(state_name, *args)
62
+ raise "need #{@menu_commands.size} stati, but got #{args.size}" if @menu_commands.size != args.size
63
+ @states[state_name] = args
64
+ end
65
+
66
+ # Loads a state which has previously been set using #new_state.
67
+ def load_state(state_name)
68
+ state = @states[state_name]
69
+ state.each_index do |i|
70
+ @menu_commands[i].enabled = state[i]
71
+ end
72
+ end
73
+
74
+ # Shows the context menu.
75
+ def execute(sender, sel, data)
76
+ @proc.call(self, sender, sel, data) if @proc
77
+ @pane.create
78
+ @pane.popup(nil, data.root_x, data.root_y)
79
+ @parent.app.runModalWhileShown(@pane)
80
+ end
81
+ end
@@ -0,0 +1,60 @@
1
+ # Copyright (c) 2004, 2005 Martin Ankerl
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 Martin Ankerl 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
+ # The Fox tabs do not look very nice. This simple handler uses buttons to show/hide frames to
26
+ # emulate a similar, better looking widget.
27
+ class Custom_Tabs
28
+
29
+ # Creates a new hander. btn_to_frame needs to be a hash where each key is
30
+ # a button and each value a frame associated to the button.
31
+ def initialize(btn_to_frame)
32
+ @btn_to_frame = btn_to_frame
33
+ create_tabs
34
+ end
35
+
36
+ # Show the frame associated with the button show_btn.
37
+ def show(show_btn)
38
+ # disable everything
39
+ @btn_to_frame.each_value do |frame|
40
+ frame.hide
41
+ end
42
+ @btn_to_frame.each_key do |btn|
43
+ btn.state = STATE_DOWN
44
+ end
45
+ # enable current tab
46
+ @btn_to_frame[show_btn].show
47
+ @btn_to_frame[show_btn].parent.recalc
48
+ show_btn.state = STATE_UP
49
+ end
50
+
51
+ private
52
+
53
+ # connect buttons
54
+ def create_tabs
55
+ @btn_to_frame.each do |btn, frame|
56
+ btn.connect(SEL_COMMAND) { show(btn) }
57
+ btn.connect(SEL_LEFTBUTTONPRESS) { show(btn) }
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,116 @@
1
+ # Copyright (c) 2004,2005 Martin Ankerl
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 Martin Ankerl 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/GUI/Empty_Text_Field_Handler'
27
+
28
+ # A convinient dialog box for standard user input like username, password, etc.
29
+ class Dialog_Box < FXDialogBox
30
+ # Entry stores the data of one user-input entry of the dialog box
31
+ Entry = Struct.new("Entry", :handler, :opts, :default_value, :is_required, :empty_text)
32
+
33
+ # Creates a new Dialog_Box for the parent with the given title.
34
+ def initialize(parent, title)
35
+ super(parent, title, DECOR_TITLE|DECOR_BORDER, 0,0,0,0, 0,0,0,0)
36
+ @parent = parent
37
+ @entries = Array.new
38
+ build_controls
39
+ build_connections
40
+ end
41
+
42
+ # Add a new entry to the dialog box. for the opts you can specify any FXTextField options like
43
+ # TEXTFIELD_PASSWD,TEXTFIELD_INTEGER etc.
44
+ def add(title, opts=0, default_value=nil, is_required=true, empty_text="")
45
+ # use data to fill dialog box
46
+ FXLabel.new(@matrixFrame, title, nil, LAYOUT_CENTER_Y|JUSTIFY_RIGHT|LAYOUT_FILL_X)
47
+ text_field = FXTextField.new(@matrixFrame, 1, nil, 0, opts|LAYOUT_FILL_COLUMN|LAYOUT_FILL_X|LAYOUT_FIX_WIDTH, 0,0,$cfg.dialogbox.textwidth,0)
48
+ handler = Empty_Text_Field_Handler.new(text_field, empty_text)
49
+ @entries.push Entry.new(handler, opts, default_value, is_required, empty_text)
50
+ text_field.connect(SEL_COMMAND) do |sender, sel, data|
51
+ lastFocus = @matrixFrame.focus
52
+ @ok_btn.setFocus if lastFocus
53
+ on_ok_button if lastFocus
54
+ end
55
+ end
56
+
57
+ # Displays the dialog box. If OK is pressed, the given block is called with all the user
58
+ # input as parameters.
59
+ def execute(&proc)
60
+ # clear controls
61
+ @entries.each do |entry|
62
+ entry.handler.text = entry.default_value
63
+ end
64
+ # focus first item
65
+ @entries.first.handler.setFocus
66
+ # show dialog
67
+ @proc = proc
68
+ self.show(PLACEMENT_SCREEN)
69
+ app.runModalWhileShown(self)
70
+ end
71
+
72
+ private
73
+
74
+ def build_controls
75
+ FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0,0,0) do |base|
76
+ FXMatrix.new(base, 2, MATRIX_BY_COLUMNS|LAYOUT_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y) do |matrix|
77
+ @matrixFrame = matrix
78
+ end
79
+ FXHorizontalSeparator.new(base, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|SEPARATOR_GROOVE)
80
+ FXHorizontalFrame.new(base, LAYOUT_FILL_X, 0,0,0,0) do |button_frame|
81
+ FXHorizontalFrame.new(button_frame, LAYOUT_FILL_X, 0,0,0,0)
82
+ @ok_btn = FXButton.new(button_frame, "&Ok", nil, nil, 0, FRAME_RAISED)
83
+ @cancel_btn = FXButton.new(button_frame, "&Cancel", nil,self, ID_HIDE, FRAME_RAISED)
84
+ end
85
+ end
86
+ end
87
+
88
+ def build_connections
89
+ @ok_btn.connect(SEL_COMMAND) { on_ok_button }
90
+ end
91
+
92
+ # Ensure all required data is available, convert data, and call given proc.
93
+ def on_ok_button
94
+ # check that each text_field contains data
95
+ empty_field = @entries.detect { |entry| entry.is_required && entry.handler.empty? }
96
+ if empty_field
97
+ empty_field.handler.setFocus
98
+ else
99
+ # collect data
100
+ data = Array.new
101
+ @entries.each do |entry|
102
+ if (entry.handler.text == "")
103
+ data.push nil
104
+ elsif (entry.opts & TEXTFIELD_INTEGER != 0)
105
+ data.push entry.handler.text.to_i
106
+ elsif (entry.opts & TEXTFIELD_REAL != 0)
107
+ data.push entry.handler.text.to_f
108
+ else
109
+ data.push entry.handler.text
110
+ end
111
+ end
112
+ self.hide
113
+ @proc.call(data)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,41 @@
1
+ # Copyright (c) 2004, Christoph Heindl and Martin Ankerl
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 and Martin Ankerl nor the names of its contributors
13
+ # may be used to endorse or promote products derived from this software without specific
14
+ # prior written 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
+ class Download_Finished_Box
26
+ def initialize(parent, pack_name)
27
+ @download_finished_box = FXDialogBox.new(parent, "", DECOR_BORDER, 0,0,0,0, 0,0,0,0,0,0) do |dlg|
28
+ FXLabel.new(dlg, $cfg.text.download_finished_box + ":\n" + pack_name, $cfg.icons.active, JUSTIFY_LEFT|ICON_BEFORE_TEXT)
29
+ end
30
+ @download_finished_box.create
31
+ timed_show(5)
32
+ end
33
+
34
+ def timed_show(timeout)
35
+ @download_finished_box.show
36
+ Thread.new do
37
+ sleep(timeout)
38
+ @download_finished_box.hide
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,86 @@
1
+ # Copyright (c) 2004, 2005 Martin Ankerl
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 Martin Ankerl 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
+ # Shows a grey text in an FXTextField if the user did not enter any input. This is a nice way to
26
+ # give the user more information about what to enter into a text field, without the need of additional
27
+ # space in the GUI.
28
+ class Empty_Text_Field_Handler
29
+
30
+ # Create a new handler for the specified textfield, with the given text. From now on you have to use the
31
+ # created object to get and set text, not the textfield or this handler would come out of sync
32
+ def initialize(textField, myText)
33
+ @textField = textField
34
+ @myText = myText
35
+ @isEmpty = true
36
+ onTextFieldFocusOut
37
+ # create connections
38
+ @textField.connect(SEL_FOCUSIN, method(:onTextFieldFocusIn))
39
+ @textField.connect(SEL_FOCUSOUT, method(:onTextFieldFocusOut))
40
+ end
41
+
42
+ # Check if textfield is empty (no user input).
43
+ def empty?
44
+ @isEmpty
45
+ end
46
+
47
+ # Set new text for the textfield
48
+ def text=(newText)
49
+ onTextFieldFocusIn
50
+ @textField.text = newText.to_s
51
+ onTextFieldFocusOut
52
+ end
53
+
54
+ # Get the textfield's text, if the user has entered something.
55
+ def text
56
+ if empty? && !@inside
57
+ ""
58
+ else
59
+ @textField.text
60
+ end
61
+ end
62
+
63
+ # Set focus to the textfield.
64
+ def setFocus
65
+ @textField.setFocus
66
+ end
67
+
68
+ private
69
+
70
+ def onTextFieldFocusIn(*args)
71
+ @inside = true
72
+ return if !@isEmpty
73
+ @textField.textColor = FXColor::Black
74
+ @textField.text = ""
75
+ end
76
+
77
+ def onTextFieldFocusOut(*args)
78
+ @inside = false
79
+ @textField.killSelection
80
+ @isEmpty = @textField.text == ""
81
+ return if !@isEmpty
82
+ @textField.textColor = FXColor::DarkGrey
83
+ @textField.text = @myText
84
+ @isEmpty = true
85
+ end
86
+ end
@@ -0,0 +1,629 @@
1
+ # Copyright (c) 2004, 2005 Martin Ankerl
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 Martin Ankerl 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
+ require 'thread'
26
+
27
+ # The module Business_Logic is included into the Main_Window. It contains all the logic required for the GUI except
28
+ # creation stuff.
29
+ class Gui_Logic
30
+ CONNECTED = 1
31
+ CONNECTING = 2
32
+ DISCONNECTED = 3
33
+ CONNECTION_FAILED = 4
34
+
35
+ def initialize(gui, data)
36
+ @gui = gui
37
+ @data = data
38
+ end
39
+
40
+ # Adds a new IRC_server and connects to it.
41
+ def on_add_server_click(menu, sender, sel, data)
42
+ @gui.add_server_box.execute do |ip, port, nick, pwd|
43
+ add_server(ip, port, nick, pwd, true)
44
+ # add to config
45
+ $cfg.config.servers[ip] = {
46
+ :port => port,
47
+ :nick => nick,
48
+ :pwd => pwd,
49
+ :channels => { },
50
+ :connected => true
51
+ }
52
+ @data.config.save
53
+ end
54
+ end
55
+
56
+ # Retrieves the clicked item of the connection widget, which is a FXTreeList. For FXIconLists like Packet_List
57
+ # use #current_item.
58
+ def current_connections_item
59
+ @gui.connections.cursorItem
60
+ end
61
+
62
+ # Retrieves the clicked item of the given Packet_List, or any other FXIconList.
63
+ def current_item(list)
64
+ pos = list.cursorItem
65
+ return list.getItem(pos) if (pos != -1)
66
+ nil
67
+ end
68
+
69
+ # Convert a string containing a packetsize into the real size which is used for
70
+ # sorting.Possible strings are e.g. "100M", "43G", "9.9k", etc.
71
+ def size_to_nr(x)
72
+ return 0 if x.nil? || x==""
73
+ x = x.upcase.strip
74
+ fact = 1.0
75
+ char = x[-1]
76
+ # check if there is MB, KB etc.
77
+ char = x[-2] if char == ?B
78
+ case char
79
+ when ?K then fact = 1024
80
+ when ?M then fact = 1024**2
81
+ when ?G then fact = 1024**3
82
+ end
83
+ x.to_f * fact
84
+ end
85
+
86
+ # Converts a given md5 status text into a representation used for sorting.
87
+ def sortable_md5_status(x)
88
+ case x
89
+ when $cfg.text.md5.ok then 1
90
+ when $cfg.text.md5.disabled then 2
91
+ when $cfg.text.md5.unavailable then 3
92
+ when $cfg.text.md5.failed then 4
93
+ else 5
94
+ end
95
+ end
96
+
97
+ # Converts a given download status text into a representation used for sorting.
98
+ def sortable_status(x)
99
+ # 2e7: failed
100
+ # 1e7: download finished
101
+ # 0..100: download percentage
102
+ # 0.5: download started
103
+ # -1..-1e7: remote queue position
104
+ # -1e7..-2e7: local queue position
105
+ # - 4e7: waiting
106
+ prev = x
107
+ if x.include?($cfg.text.download_failed)
108
+ x = 2e7
109
+ elsif x == $cfg.text.download_finished
110
+ x = 1e7
111
+ elsif x =~ /%/
112
+ x = x.to_f
113
+ elsif x == $cfg.text.download_started
114
+ x = 0.5
115
+ elsif x.include?($cfg.text.queue_remote)
116
+ /.*\s(\d+)/.match(x)
117
+ x = - $1.to_i
118
+ elsif x.include?($cfg.text.queue_local)
119
+ /.*\s(\d+)/.match(x)
120
+ x = - $1.to_i - 1e7
121
+ elsif x == $cfg.text.download_waiting
122
+ x = -4e7
123
+ else
124
+ x = 3e7
125
+ end
126
+ x
127
+ end
128
+
129
+ # Update the text for the number of displayed packs.
130
+ def update_search_status_text
131
+ @gui.search_status_label.text = " #{@gui.packet_list.numItems} #{$cfg.text.of} #{@data.allpack_to_item.size} #{$cfg.text.packs}"
132
+ end
133
+
134
+ # Find out if item is matched by current search criteria.
135
+ def match?(item, match_data)
136
+ # check icon
137
+ return false unless @data.packet_icon_to_toggle_btn[item.icon].toggled?
138
+
139
+ # check text
140
+ return true if match_data.empty?
141
+ item_str = item.sortable(1)
142
+ match_data.each do |match_str|
143
+ if match_str[0] == ?-
144
+ # the next items are not allowed to be contained in pack name
145
+ return false if (match_str[1..-1]!="") && (item_str.include?(match_str[1..-1]))
146
+ else
147
+ return false if !item_str.include?(match_str)
148
+ end
149
+ end
150
+ true
151
+ end
152
+
153
+ # Executed whenever a search criteria changes to update the packet list.
154
+ def on_search
155
+ # restart current search
156
+ # TODO what happens when new announcements come every 0.2 second or so?
157
+ # the list will never be updated... :-/
158
+ @end_time = Time.now + 0.5
159
+ @restart_search = true
160
+ @gui.search_label.enabled = false
161
+ return if @search_thread && @search_thread.status
162
+
163
+ @search_thread = Thread.new(@search_thread) do
164
+ begin
165
+ @gui.search_label.enabled = false
166
+ # wait untill deadline
167
+ while (t = (@end_time - Time.now)) > 0
168
+ sleep(t)
169
+ end
170
+
171
+ @data.gui_mutex.synchronize do
172
+ # the thread has to use the gui mutex inside
173
+ @restart_search = false
174
+
175
+ @match_data = @gui.search_field.text.downcase.split
176
+
177
+ # remove all items
178
+ @gui.packet_list.dirty_clear
179
+
180
+ # add all items that match the search criteria
181
+ sort_deadline = Time.now
182
+ status_text_deadline = Time.now
183
+ @data.allpack_to_item.each_value do |item|
184
+ #item.parent = @gui.packet_list if match?(item, match_data)
185
+ if match?(item, @match_data)
186
+ item.show
187
+
188
+ # take only about 10% of the cpu to sort items.
189
+ # with few items this results to very fast sorts,
190
+ # with many items this leads to fast updates.
191
+ if (sort_deadline < Time.now)
192
+ before = Time.now
193
+ @gui.packet_list.sortItems
194
+ after = Time.now
195
+ sort_deadline = after + (after-before) *10
196
+ end
197
+
198
+ # update every 0.1 second
199
+ if (status_text_deadline < Time.now)
200
+ update_search_status_text
201
+ status_text_deadline = Time.now + 0.1
202
+ end
203
+ end
204
+ break if @restart_search
205
+ end
206
+ update_search_status_text
207
+ @gui.packet_list.sortItems
208
+ @gui.search_label.enabled = true
209
+
210
+ FXApp::instance.flush
211
+ end # synchronize
212
+ end while @restart_search# || @match_data != @gui.search_field.text.downcase.split
213
+ end #thread.new
214
+ end
215
+
216
+ def add_server(ip, port, nick, pwd, do_connect)
217
+ name = "#{ip}"
218
+ server_item = @gui.connections.addItemLast(nil, name, $cfg.icons.disconnected, $cfg.icons.disconnected)
219
+ @data.server_item_to_status[server_item] = CONNECTING
220
+ # create server
221
+ server = IRC_Server.new
222
+ @data.ann_parser.attach_to_server(server)
223
+ @data.irc_server_to_item[server] = server_item
224
+ server_item.data = server
225
+ server_item.expanded = true
226
+ @gui.connections.sortItems
227
+ if do_connect
228
+ server_item.openIcon = $cfg.icons.connecting
229
+ server_item.closedIcon = $cfg.icons.connecting
230
+ server.connect(ip, port, nick, $cfg.alternative_user_name, pwd)
231
+ end
232
+ connect_to_server_events(server)
233
+ # server -> channelarray
234
+ @data.server_to_channels[server_item] = Array.new
235
+ server_item
236
+ end
237
+
238
+ # Connect to all servers stored in $cfg.config.servers
239
+ def connect_to_saved_servers
240
+ $cfg.config.servers.each do |ip, data|
241
+ server_item = add_server(ip, data[:port], data[:nick], data[:pwd], data[:connected])
242
+ @data.server_item_to_status[server_item] = data[:connected] ? CONNECTING : DISCONNECTED
243
+ # add channels
244
+ connect_to_saved_channels(server_item)
245
+ end
246
+ end
247
+
248
+ def connect_to_saved_channels(server_item)
249
+ server_data = $cfg.config.servers[server_item.text]
250
+ server_data[:channels].each do |channel_name, data|
251
+ add_channel(server_item, channel_name.dup, data[:pwd], server_data[:connected])
252
+ end
253
+ end
254
+
255
+ # Disconnects from a server.
256
+ def on_remove_server_click(menu, sender, sel, data)
257
+ server_item = menu.data
258
+ # remove from config
259
+ $cfg.config.servers.delete(server_item.text)
260
+ @data.config.save
261
+ # remove
262
+ @data.ann_parser.detach_from_server(server_item.data)
263
+ server_item.data.disconnect
264
+ @data.irc_server_to_item.delete(server_item.data)
265
+ @gui.connections.removeItem(server_item)
266
+ end
267
+
268
+ def on_server_disconnect_click(menu, sender, sel, data)
269
+ server_item = menu.data
270
+ # set to disconnected, before actually disconnecting.
271
+ # This is used to distinguish between user disconnects, and forced disconnects.
272
+ @data.server_item_to_status[server_item] = DISCONNECTED
273
+ server_item.data.disconnect
274
+ # update config
275
+ $cfg.config.servers[server_item.text][:connected] = false
276
+ @data.config.save
277
+ end
278
+
279
+ def on_server_connect_click(menu, sender, sel, data)
280
+ server_item = menu.data
281
+ # update config
282
+ $cfg.config.servers[server_item.text][:connected] = true
283
+ @data.config.save
284
+ # connect irc server
285
+ irc_server = server_item.data
286
+ irc_server.disconnect
287
+ server_data = $cfg.config.servers[server_item.text]
288
+ irc_server.connect(server_item.text, server_data[:port], server_data[:nick], $cfg.alternative_user_name, server_data[:pwd])
289
+ # update icons
290
+ server_item.openIcon = $cfg.icons.connecting
291
+ server_item.closedIcon = $cfg.icons.connecting
292
+ # recreate all channels
293
+ @data.server_to_channels[server_item].each do |channel_item|
294
+ @gui.connections.removeItem(channel_item)
295
+ end
296
+ @data.server_to_channels[server_item] = Array.new
297
+ connect_to_saved_channels(server_item)
298
+
299
+ @data.server_item_to_status[server_item] = CONNECTING
300
+ @gui.connections.recalc
301
+ end
302
+
303
+ # Joins a channel at the clicked IRC_server.
304
+ def on_add_channel_click(menu, sender, sel, data)
305
+ @gui.join_channel_box.execute do |channel_name, password|
306
+ server_item = menu.data
307
+ do_connect = (@data.server_item_to_status[server_item] != DISCONNECTED &&
308
+ @data.server_item_to_status[server_item] != CONNECTION_FAILED)
309
+ real_channel_name = add_channel(server_item, channel_name, password, do_connect)
310
+ # add to config
311
+ $cfg.config.servers[server_item.text][:channels][real_channel_name] = { :pwd => password }
312
+ @data.config.save
313
+ end
314
+ end
315
+
316
+ def add_channel(server_item, channel_name, password, do_connect)
317
+ server_item.expanded = true
318
+ # automatically prepend #
319
+ channel_name = "#" + channel_name unless channel_name[0] == ?#
320
+ channel_name.downcase!
321
+ # check if channel already available
322
+ return if @data.server_to_channels[server_item].detect { |channel_item| channel_item.text == channel_name }
323
+ # create item
324
+ channel_item = @gui.connections.addItemLast(server_item, channel_name, $cfg.icons.disconnected, $cfg.icons.disconnected)
325
+ if do_connect
326
+ channel_item.openIcon = $cfg.icons.connecting
327
+ channel_item.closedIcon = $cfg.icons.connecting
328
+ server_item.data.join(channel_name, password)
329
+ end
330
+ @data.server_to_channels[server_item].push channel_item
331
+ @gui.connections.sortChildItems(server_item)
332
+ channel_name
333
+ end
334
+
335
+ # Part channel.
336
+ def on_remove_channel_click(menu, sender, sel, data)
337
+ channel_item = menu.data
338
+ # remove from config
339
+ $cfg.config.servers[channel_item.parent.text][:channels].delete(channel_item.text)
340
+ @data.config.save
341
+ # remove
342
+ channel_item.parent.data.part(channel_item.text)
343
+ @data.server_to_channels[channel_item.parent].delete channel_item
344
+ @gui.connections.removeItem(channel_item)
345
+ end
346
+
347
+ # Show a nifty �ber-cool about dialog.
348
+ def on_about_click
349
+ About_Dialog.new(@gui.main_window).execute
350
+ end
351
+
352
+
353
+ # Let user select a target directory and initiate download if user clicks OK.
354
+ def on_download_click(menu, sender, sel, data)
355
+ fox_item = menu.data
356
+ return if !fox_item
357
+ item = fox_item.packet_item
358
+ packet = item.data
359
+ return if !packet
360
+ dir_dlg = FXDirDialog.new(@gui.main_window, $cfg.text.target_directory)
361
+ dir_dlg.directory = $cfg.config.download_directory
362
+ return if (dir_dlg.execute == 0)
363
+ # save new directory settings, if modified
364
+ new_dir = dir_dlg.directory
365
+ if (new_dir != $cfg.config.download_directory)
366
+ $cfg.config.download_directory = new_dir
367
+ @data.config.save
368
+ end
369
+
370
+ # get download handler
371
+ handler = nil
372
+ if (handler = @data.download_handlers[packet.irc_user_bot]) == nil
373
+ handler = @data.download_handlers[packet.irc_user_bot] = XDCC_Download_Handler.new(packet.irc_user_bot)
374
+ handler.connect_to_events(XDCC_Download_Handler::ON_ALL_EVENTS, self)
375
+ end
376
+
377
+ # add download item
378
+ item = @gui.active_list.create_item($cfg.icons.packet, item[0], item[1], item[2], $cfg.text.download_waiting, "")
379
+ item.fox_item.miniIcon = $cfg.icons.packet
380
+ item.data = packet
381
+
382
+ # get pack
383
+ @data.downloadpack_to_item[packet] = item
384
+ handler.add_pack(packet, $cfg.config.download_directory)
385
+ end
386
+
387
+ # Cancels a download.
388
+ def on_cancel_download_click(menu, sender, sel, data)
389
+ fox_item = menu.data
390
+ return if !fox_item
391
+ item = fox_item.packet_item
392
+ packet = item.data
393
+ return if !packet
394
+
395
+ handler = @data.download_handlers[packet.irc_user_bot]
396
+ item[3] = $cfg.text.download_cancelling
397
+ handler.cancel_pack(packet)
398
+ end
399
+
400
+ # Remove all items from the error list
401
+ def on_clear_error_list
402
+ @gui.error_list.clear
403
+ end
404
+
405
+ # Remove all items from the completed list
406
+ def on_clear_completed_list
407
+ @gui.completed_list.clear
408
+ end
409
+
410
+ def on_show_warning(menu, sender, sel, data)
411
+ server_item = menu.data
412
+ box = FXMessageBox.new(
413
+ FXApp::instance,
414
+ $cfg.text.message.connection_error_title,
415
+ @data.server_item_to_warning[server_item],
416
+ $cfg.icons.warning_big, MBOX_OK)
417
+ box.create
418
+ box.show(PLACEMENT_OWNER)
419
+ end
420
+
421
+
422
+ # Connect to all required events of an IRC_Server.
423
+ def connect_to_server_events(server)
424
+ server.connect_to_events(IRC_Server::ON_SERVER_REGISTERED, self)
425
+ server.connect_to_events(IRC_Server::ON_CHANNEL_JOIN_SUCCESS, self)
426
+ server.connect_to_events(IRC_Server::ON_SERVER_DISCONNECTED, self)
427
+ server.connect_to_events(IRC_Server::ON_USER_KICK, self)
428
+ end
429
+
430
+ # Handles all callbacks from IRC_Server, XDCC_Announcement_Storage and XDCC_Download_Handler.
431
+ def on_event(caller, event_type, args)
432
+ @data.gui_mutex.synchronize do
433
+ case event_type
434
+ when IRC_Server::ON_SERVER_REGISTERED
435
+ server_item = @data.irc_server_to_item[caller]
436
+ return if !server_item
437
+ @data.server_item_to_status[server_item] = CONNECTED
438
+ server_item.closedIcon = $cfg.icons.connected
439
+ server_item.openIcon = $cfg.icons.connected
440
+ @gui.connections.recalc
441
+
442
+ when IRC_Server::ON_SERVER_DISCONNECTED
443
+ error_msg = args[0] || ""
444
+ server_item = @data.irc_server_to_item[caller]
445
+ return if !server_item
446
+ # disconnected by the user, or forced disconnect?
447
+ icon = $cfg.icons.disconnected
448
+ unless @data.server_item_to_status[server_item] == DISCONNECTED
449
+ @data.server_item_to_status[server_item] = CONNECTION_FAILED
450
+ @data.server_item_to_warning[server_item] = $cfg.text.message.connection_error + ":\n" + error_msg
451
+ icon = $cfg.icons.connection_failed
452
+ else
453
+ @data.server_item_to_status[server_item] = DISCONNECTED
454
+ end
455
+ server_item.closedIcon = icon
456
+ server_item.openIcon = icon
457
+ # set all channel items to disconnected
458
+ server_item.each do |channel_item|
459
+ channel_item.closedIcon = icon
460
+ channel_item.openIcon = icon
461
+ end
462
+ @gui.connections.recalc
463
+
464
+ when IRC_Server::ON_CHANNEL_JOIN_SUCCESS
465
+ channel_name, channel_mode = args
466
+ channel_name.downcase!
467
+ server_item = @data.irc_server_to_item[caller]
468
+ channel = @data.server_to_channels[server_item].detect { |channel| channel.text==channel_name }
469
+
470
+ # Follow automatic channel forwards
471
+ if !channel
472
+ # create icon
473
+ channel_name = "#" + channel_name unless channel_name[0] == ?#
474
+ channel_name.downcase!
475
+ server_item.expanded = true
476
+ # check if channel already available
477
+ return if @data.server_to_channels[server_item].detect { |channel_item| channel_item.text == channel_name }
478
+ # create item
479
+ channel = @gui.connections.addItemLast(server_item, channel_name, $cfg.icons.connecting, $cfg.icons.connecting)
480
+ @data.server_to_channels[server_item].push channel
481
+ @gui.connections.sortChildItems(server_item)
482
+ end
483
+ channel.closedIcon = $cfg.icons.connected
484
+ channel.openIcon = $cfg.icons.connected
485
+ @gui.connections.recalc
486
+
487
+ when XDCC_Announcement_Storage::ON_ANNOUNCEMENT_NEW
488
+ ann = args[0]
489
+ bot = ann.irc_user_bot.name
490
+
491
+ # set slot representing icon
492
+ if ann.ann_type == XDCC_Announcement::ANN_FULL
493
+ icon = $cfg.icons.packet
494
+ icon = $cfg.icons.free_slots if ann.openslot_cnt > 0
495
+ else
496
+ icon = $cfg.icons.slots_unknown
497
+ end
498
+
499
+ is_added = false
500
+ match_data = @gui.search_field.text.downcase.split
501
+ ann.packs.each do |pack|
502
+ # create an unconnected item
503
+ item = Packet_Item.new(nil, icon, bot, pack.name, pack.size)
504
+ item.data = pack
505
+ @data.allpack_to_item[pack] = item
506
+
507
+ # item needs to be added to a list, before calling match()
508
+ item.parent = @gui.packet_list
509
+ if match?(item, match_data)
510
+ item.show
511
+ is_added = true
512
+ end
513
+ end
514
+ if is_added
515
+ update_search_status_text
516
+ @gui.packet_list.sortItems
517
+ end
518
+ #on_search
519
+
520
+ when XDCC_Announcement_Storage::ON_ANNOUNCEMENT_LOST
521
+ ann = args[0]
522
+ ann.packs.each do |pack|
523
+ item = @data.allpack_to_item.delete(pack)
524
+ item.parent = nil
525
+ end
526
+ update_search_status_text
527
+
528
+ when XDCC_Download_Handler::ON_DOWNLOAD_STARTED
529
+ item = @data.downloadpack_to_item[args[0]]
530
+ item.fox_item.miniIcon = $cfg.icons.free_slots
531
+ item[3] = $cfg.text.download_started
532
+ @gui.active_list.sortItems
533
+
534
+ when XDCC_Download_Handler::ON_DOWNLOAD_FINISHED
535
+ pack = args[0]
536
+ item = @data.downloadpack_to_item[pack]
537
+ @gui.speed_widget.delete(item)
538
+ item.parent = @gui.completed_list
539
+ item.show
540
+ item.fox_item.miniIcon = $cfg.icons.completed
541
+ item[3] = $cfg.text.download_finished
542
+ @gui.completed_list.sortItems
543
+ # show "download finished" box
544
+ Download_Finished_Box.new(@gui.main_window, item[1])
545
+
546
+ when XDCC_Download_Handler::ON_MD5_STATUS
547
+ pack, status = args
548
+ item = @data.downloadpack_to_item[pack]
549
+ item[3] = case status
550
+ when XDCC_Download_Handler::MD5_DISABLED
551
+ $cfg.text.md5.disabled
552
+ when XDCC_Download_Handler::MD5_UNAVAILABLE
553
+ $cfg.text.md5.unavailable
554
+ when XDCC_Download_Handler::MD5_OK
555
+ $cfg.text.md5.ok
556
+ when XDCC_Download_Handler::MD5_FAILED
557
+ $cfg.text.md5.failed
558
+ end
559
+ @gui.completed_list.sortItems
560
+
561
+ when XDCC_Download_Handler::ON_DOWNLOAD_FAILED
562
+ pack, error_msg = args
563
+ item = @data.downloadpack_to_item[pack]
564
+ @gui.speed_widget.delete(item)
565
+ item.parent = @gui.error_list
566
+ item.show
567
+ item.fox_item.miniIcon = $cfg.icons.package_failed
568
+ item[3] = error_msg
569
+
570
+ when XDCC_Download_Handler::ON_DOWNLOAD_PROGRESS
571
+ pack, percentage, received_bytes, speed = args
572
+ item = @data.downloadpack_to_item[pack]
573
+ @gui.speed_widget[item] = speed
574
+ item[3] = sprintf("%.1f%%", percentage)
575
+ item[4] = sprintf("%.1fkb", speed)
576
+ @gui.active_list.sortItems
577
+
578
+ when XDCC_Download_Handler::ON_QUEUED_LOCALLY
579
+ pack, queue_pos, queue_length = args
580
+ if queue_length
581
+ queue_length = queue_length.to_s
582
+ else
583
+ queue_length = "?"
584
+ end
585
+ item = @data.downloadpack_to_item[pack]
586
+ item[3] = sprintf($cfg.text.queue_local + " %d/%s", queue_pos, queue_length)
587
+ @gui.active_list.sortItems
588
+
589
+ when XDCC_Download_Handler::ON_QUEUED_REMOTELY
590
+ pack, queue_pos, queue_length = args
591
+ if queue_length
592
+ queue_length = queue_length.to_s
593
+ else
594
+ queue_length = "?"
595
+ end
596
+ item = @data.downloadpack_to_item[pack]
597
+ return if !item
598
+ item[3] = sprintf($cfg.text.queue_remote + " %d/%s", queue_pos, queue_length)
599
+ @gui.active_list.sortItems
600
+
601
+ when XDCC_Download_Handler::ON_PACK_REQUESTED
602
+ pack = args[0]
603
+ item = @data.downloadpack_to_item[pack]
604
+ str = item[3]
605
+
606
+ if str.include?($cfg.text.download_requesting)
607
+ # animate with ... to visualize something is happening :-)
608
+ if str[-3..-1] == "..."
609
+ item[3] = $cfg.text.download_requesting
610
+ else
611
+ item[3] += "."
612
+ end
613
+ else
614
+ item[3] = $cfg.text.download_requesting
615
+ end
616
+ @gui.active_list.sortItems
617
+
618
+ when IRC_Server::ON_USER_KICK
619
+ irc_user, channel_name, kick_msg = args
620
+ if irc_user == caller.me
621
+ server_item = @data.irc_server_to_item[caller]
622
+ channel_item = @data.server_to_channels[server_item].detect { |channel_item| channel_item.text == channel_name }
623
+ channel_item.closedIcon = $cfg.icons.connection_failed
624
+ channel_item.openIcon = $cfg.icons.connection_failed
625
+ end
626
+ end
627
+ end
628
+ end
629
+ end