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.
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