idb 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +65 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/idb +5 -0
- data/idb.gemspec +41 -0
- data/lib/LICENSE +20 -0
- data/lib/README.md +54 -0
- data/lib/config/.dummy +0 -0
- data/lib/config/settings.yml +8 -0
- data/lib/gui/app_binary_tab_widget.rb +45 -0
- data/lib/gui/app_details_group_box.rb +213 -0
- data/lib/gui/app_list_dialog.rb +67 -0
- data/lib/gui/app_list_widget_item.rb +9 -0
- data/lib/gui/binary_strings_widget.rb +33 -0
- data/lib/gui/browse_filesystem_widget.rb +4 -0
- data/lib/gui/ca_manager_dialog.rb +137 -0
- data/lib/gui/cache_db_widget.rb +61 -0
- data/lib/gui/certificate_item.rb +5 -0
- data/lib/gui/console_widget.rb +163 -0
- data/lib/gui/cycript_console_widget.rb +68 -0
- data/lib/gui/cycript_thread.rb +81 -0
- data/lib/gui/device_info_group_box.rb +55 -0
- data/lib/gui/device_status_dialog.rb +351 -0
- data/lib/gui/file_system_events_widget.rb +4 -0
- data/lib/gui/fs_viewer_tab_widget.rb +245 -0
- data/lib/gui/i_device_syslog_thread.rb +47 -0
- data/lib/gui/images/check.png +0 -0
- data/lib/gui/images/folder.ico +0 -0
- data/lib/gui/images/iphone.ico +0 -0
- data/lib/gui/images/screenshot.png +0 -0
- data/lib/gui/key_chain_widget.rb +86 -0
- data/lib/gui/local_storage_tab_widget.rb +37 -0
- data/lib/gui/log_plain_text_edit.rb +18 -0
- data/lib/gui/log_widget.rb +71 -0
- data/lib/gui/main_tab_widget.rb +179 -0
- data/lib/gui/pasteboard_monitor_widget.rb +116 -0
- data/lib/gui/path_list_widget_item.rb +5 -0
- data/lib/gui/pb_watcher_thread.rb +63 -0
- data/lib/gui/plist_file_widget.rb +66 -0
- data/lib/gui/qt_ruby_variant.rb +16 -0
- data/lib/gui/screenshot_wizard.rb +169 -0
- data/lib/gui/settings_dialog.rb +69 -0
- data/lib/gui/settings_tab_widget.rb +149 -0
- data/lib/gui/shared_libraries_widget.rb +47 -0
- data/lib/gui/snoop_it_fs_events_widget.rb +150 -0
- data/lib/gui/snoop_it_keychain_widget.rb +172 -0
- data/lib/gui/snoop_it_sensitive_api_widget.rb +128 -0
- data/lib/gui/snoop_it_tab_widget.rb +27 -0
- data/lib/gui/snoop_it_update_thread.rb +48 -0
- data/lib/gui/sqlite_widget.rb +73 -0
- data/lib/gui/ssh_port_forward_tab_widget.rb +209 -0
- data/lib/gui/tool_widget.rb +94 -0
- data/lib/gui/url_handler_widget.rb +26 -0
- data/lib/gui/url_scheme_fuzz_widget.rb +103 -0
- data/lib/gui/url_scheme_widget.rb +60 -0
- data/lib/gui/weak_class_dump_widget.rb +89 -0
- data/lib/helper/ssh_port_forwarder.rb +72 -0
- data/lib/idb.rb +295 -0
- data/lib/idb/version.rb +3 -0
- data/lib/lib/CgBI.rb +153 -0
- data/lib/lib/abstract_device.rb +31 -0
- data/lib/lib/app.rb +286 -0
- data/lib/lib/app_binary.rb +57 -0
- data/lib/lib/ca_interface.rb +151 -0
- data/lib/lib/configuration.rb +0 -0
- data/lib/lib/console_launcher.rb +24 -0
- data/lib/lib/device.rb +438 -0
- data/lib/lib/device_ca_interface.rb +36 -0
- data/lib/lib/host_file_wrapper.rb +27 -0
- data/lib/lib/i_device_diagnostics_wrapper.rb +90 -0
- data/lib/lib/keychain_plist_parser.rb +15 -0
- data/lib/lib/local_operations.rb +67 -0
- data/lib/lib/otool_wrapper.rb +116 -0
- data/lib/lib/plist_util.rb +72 -0
- data/lib/lib/qt_thread_fix.rb +29 -0
- data/lib/lib/rsync_git_manager.rb +81 -0
- data/lib/lib/screen_shot_util.rb +59 -0
- data/lib/lib/settings.rb +67 -0
- data/lib/lib/simulator.rb +60 -0
- data/lib/lib/simulator_ca_interface.rb +16 -0
- data/lib/lib/snoop_it_wrapper.rb +80 -0
- data/lib/lib/ssh_operations.rb +136 -0
- data/lib/lib/ssh_port_forwarder.rb +43 -0
- data/lib/lib/tools.rb +11 -0
- data/lib/lib/url_scheme_fuzzer.rb +98 -0
- data/lib/lib/usb_muxd_wrapper.rb +32 -0
- data/lib/lib/weak_class_dump_wrapper.rb +62 -0
- data/lib/utils/dumpdecrypted/README +4 -0
- data/lib/utils/dumpdecrypted/dumpdecrypted_armv6.dylib +0 -0
- data/lib/utils/dumpdecrypted/dumpdecrypted_armv7.dylib +0 -0
- data/lib/utils/ios-ssl-kill-switch/com.isecpartners.nabla.sslkillswitch_v0.5-iOS_6.1.deb +0 -0
- data/lib/utils/keychain_dump/README +2 -0
- data/lib/utils/keychain_dump/keychain_dump +0 -0
- data/lib/utils/pbwatcher/pbwatcher +0 -0
- data/lib/utils/pcviewer/protectionclassviewer +0 -0
- data/lib/utils/weak_class_dump/README +5 -0
- data/lib/utils/weak_class_dump/weak_classdump.cy +726 -0
- metadata +412 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
require_relative '../lib/snoop_it_wrapper'
|
2
|
+
require_relative 'snoop_it_update_thread'
|
3
|
+
require_relative 'qt_ruby_variant'
|
4
|
+
|
5
|
+
|
6
|
+
module Idb
|
7
|
+
#TODO: implement something like this to make model update faster
|
8
|
+
class FSEventItemModel < Qt::StandardItemModel
|
9
|
+
include Idb
|
10
|
+
|
11
|
+
def initialize *args
|
12
|
+
super *args
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_bulk
|
16
|
+
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
class SnoopItFSEventsWidget < Qt::Widget
|
27
|
+
|
28
|
+
|
29
|
+
def initialize *args
|
30
|
+
super *args
|
31
|
+
|
32
|
+
@model = Qt::StandardItemModel.new
|
33
|
+
|
34
|
+
@selection_model = Qt::ItemSelectionModel.new @model
|
35
|
+
@selection_model.model
|
36
|
+
|
37
|
+
@events_tab = Qt::TableView.new
|
38
|
+
@events_tab.setModel @selection_model.model
|
39
|
+
@events_tab.setSelectionModel(@selection_model)
|
40
|
+
|
41
|
+
@events_tab.setSelectionBehavior(Qt::AbstractItemView::SelectRows)
|
42
|
+
@events_tab.setEditTriggers(Qt::AbstractItemView::NoEditTriggers )
|
43
|
+
|
44
|
+
@start = Qt::PushButton.new "Start"
|
45
|
+
@start.connect(SIGNAL :released) {
|
46
|
+
@start.setEnabled(false)
|
47
|
+
@stop.setEnabled(true)
|
48
|
+
start_stream
|
49
|
+
}
|
50
|
+
|
51
|
+
@stop = Qt::PushButton.new "Stop"
|
52
|
+
@stop.setEnabled(false)
|
53
|
+
@stop.connect(SIGNAL :released) {
|
54
|
+
@start.setEnabled(true)
|
55
|
+
@stop.setEnabled(false)
|
56
|
+
stop_stream
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
layout = Qt::VBoxLayout.new do |v|
|
61
|
+
v.add_widget(@events_tab)
|
62
|
+
v.add_widget(@start)
|
63
|
+
v.add_widget(@stop)
|
64
|
+
end
|
65
|
+
setLayout(layout)
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
def reset
|
72
|
+
@model.clear
|
73
|
+
@model.setHorizontalHeaderItem(0, Qt::StandardItem.new("Subject"))
|
74
|
+
@model.setHorizontalHeaderItem(1, Qt::StandardItem.new("Expiry"))
|
75
|
+
@model.setHorizontalHeaderItem(2, Qt::StandardItem.new("Issuer"))
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
def start_stream
|
80
|
+
|
81
|
+
|
82
|
+
@thread = SnoopItUpdateThread.new
|
83
|
+
@thread.connect(SIGNAL('new_events(QVariant)')) { |events|
|
84
|
+
if not events.value.nil?
|
85
|
+
@events_tab.blockSignals(true)
|
86
|
+
events.value.each { |e|
|
87
|
+
#TODO if there are many, display status
|
88
|
+
row = parse_event e
|
89
|
+
@model.appendRow(row)
|
90
|
+
Qt::Application::processEvents
|
91
|
+
|
92
|
+
}
|
93
|
+
@events_tab.blockSignals(false)
|
94
|
+
@events_tab.resizeColumnsToContents
|
95
|
+
@events_tab.resizeRowsToContents
|
96
|
+
end
|
97
|
+
}
|
98
|
+
@thread.delete_all
|
99
|
+
@thread.stream 'fsevents_after_id'
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
private
|
105
|
+
def parse_event e
|
106
|
+
row = Array.new
|
107
|
+
row << Qt::StandardItem.new(e.value["id"].value.to_s)
|
108
|
+
|
109
|
+
row << Qt::StandardItem.new(Time.at(e.value["timestamp"].value).to_s)
|
110
|
+
|
111
|
+
mode = nil
|
112
|
+
|
113
|
+
case e.value["accessMode"].value
|
114
|
+
when 0
|
115
|
+
mode = "Error"
|
116
|
+
when 1
|
117
|
+
mode = "Read-Only"
|
118
|
+
when 2
|
119
|
+
mode = "Write-Only"
|
120
|
+
when 3
|
121
|
+
mode = "Read/Write"
|
122
|
+
end
|
123
|
+
|
124
|
+
row << Qt::StandardItem.new(mode)
|
125
|
+
|
126
|
+
row << Qt::StandardItem.new(e.value["path"].value.to_s)
|
127
|
+
|
128
|
+
dp_class = nil
|
129
|
+
case e.value["class"].value
|
130
|
+
when 1
|
131
|
+
dp_class = "NSFileProtectionNone"
|
132
|
+
when 2
|
133
|
+
dp_class = "NSFileProtectionComplete"
|
134
|
+
when 3
|
135
|
+
dp_class = "NSFileProtectionCompleteUnlessOpen"
|
136
|
+
when 4
|
137
|
+
dp_class = "NSFileProtectionCompleteUntilFirstUserAuthentication"
|
138
|
+
end
|
139
|
+
row << Qt::StandardItem.new(dp_class)
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
row << Qt::StandardItem.new(e.value["sandbox"].value.to_s)
|
144
|
+
row
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require_relative 'snoop_it_update_thread'
|
2
|
+
require_relative '../lib/snoop_it_wrapper'
|
3
|
+
|
4
|
+
module Idb
|
5
|
+
class SnoopItKeychainWidget < Qt::Widget
|
6
|
+
|
7
|
+
def initialize *args
|
8
|
+
super *args
|
9
|
+
|
10
|
+
@model = Qt::StandardItemModel.new
|
11
|
+
|
12
|
+
@selection_model = Qt::ItemSelectionModel.new @model
|
13
|
+
@selection_model.model
|
14
|
+
|
15
|
+
@events_tab = Qt::TableView.new
|
16
|
+
@events_tab.setModel @selection_model.model
|
17
|
+
@events_tab.setSelectionModel(@selection_model)
|
18
|
+
|
19
|
+
@events_tab.setSelectionBehavior(Qt::AbstractItemView::SelectRows)
|
20
|
+
@events_tab.setEditTriggers(Qt::AbstractItemView::NoEditTriggers )
|
21
|
+
|
22
|
+
@snoop = SnoopItWrapper.new
|
23
|
+
|
24
|
+
|
25
|
+
@selection_model.connect(SIGNAL('selectionChanged(QItemSelection,QItemSelection)')) {|x,y|
|
26
|
+
selected_row = x.indexes[0].row
|
27
|
+
id = @model.item(selected_row, 0).text
|
28
|
+
details = @snoop.keychain_details id
|
29
|
+
puts details[0].inspect
|
30
|
+
@query_val.setText(details[0]["query"].to_s)
|
31
|
+
@data_val.setText(details[0]["data"].to_s)
|
32
|
+
}
|
33
|
+
|
34
|
+
|
35
|
+
@start = Qt::PushButton.new "Start"
|
36
|
+
@start.connect(SIGNAL :released) {
|
37
|
+
@start.setEnabled(false)
|
38
|
+
@stop.setEnabled(true)
|
39
|
+
start_stream
|
40
|
+
}
|
41
|
+
|
42
|
+
@stop = Qt::PushButton.new "Stop"
|
43
|
+
@stop.setEnabled(false)
|
44
|
+
@stop.connect(SIGNAL :released) {
|
45
|
+
@start.setEnabled(true)
|
46
|
+
@stop.setEnabled(false)
|
47
|
+
stop_stream
|
48
|
+
}
|
49
|
+
|
50
|
+
@details = Qt::GroupBox.new
|
51
|
+
@details.setTitle "Details"
|
52
|
+
@detail_layout = Qt::GridLayout.new
|
53
|
+
@details.setLayout(@detail_layout)
|
54
|
+
|
55
|
+
@query_label = Qt::Label.new "<b>Query</b>", @details
|
56
|
+
@query_val = Qt::Label.new "", self, 0
|
57
|
+
@detail_layout.addWidget @query_label, 0, 0
|
58
|
+
@detail_layout.addWidget @query_val, 0, 1
|
59
|
+
|
60
|
+
|
61
|
+
@data_label = Qt::Label.new "<b>Data</b>", @details
|
62
|
+
@data_val = Qt::Label.new "", self, 0
|
63
|
+
@detail_layout.addWidget @data_label, 1, 0
|
64
|
+
@detail_layout.addWidget @data_val, 1, 1
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
layout = Qt::VBoxLayout.new do |v|
|
72
|
+
v.add_widget(@events_tab)
|
73
|
+
v.add_widget(@details)
|
74
|
+
v.add_widget(@start)
|
75
|
+
v.add_widget(@stop)
|
76
|
+
end
|
77
|
+
setLayout(layout)
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def start_stream
|
85
|
+
|
86
|
+
|
87
|
+
@thread = SnoopItUpdateThread.new
|
88
|
+
@thread.connect(SIGNAL('new_events(QVariant)')) { |events|
|
89
|
+
if not events.value.nil?
|
90
|
+
@events_tab.blockSignals(true)
|
91
|
+
events.value.each { |e|
|
92
|
+
#TODO if there are many, display status
|
93
|
+
row = parse_event e
|
94
|
+
@model.appendRow(row)
|
95
|
+
Qt::Application::processEvents
|
96
|
+
|
97
|
+
}
|
98
|
+
@events_tab.blockSignals(false)
|
99
|
+
@events_tab.resizeColumnsToContents
|
100
|
+
@events_tab.resizeRowsToContents
|
101
|
+
end
|
102
|
+
}
|
103
|
+
@thread.stream 'keychain_after_id'
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
private
|
109
|
+
def parse_event e
|
110
|
+
row = Array.new
|
111
|
+
row << Qt::StandardItem.new(e.value["id"].value.to_s)
|
112
|
+
|
113
|
+
row << Qt::StandardItem.new(Time.at(e.value["timestamp"].value).to_s)
|
114
|
+
|
115
|
+
mode = nil
|
116
|
+
|
117
|
+
case e.value["action"].value
|
118
|
+
when 1
|
119
|
+
mode = "Added"
|
120
|
+
when 2
|
121
|
+
mode = "Modified"
|
122
|
+
when 3
|
123
|
+
mode = "Deleted"
|
124
|
+
when 4
|
125
|
+
mode = "Read"
|
126
|
+
end
|
127
|
+
|
128
|
+
row << Qt::StandardItem.new(mode)
|
129
|
+
|
130
|
+
sec_class = nil
|
131
|
+
case e.value["secClass"].value
|
132
|
+
when 0
|
133
|
+
sec_class = "Unknown"
|
134
|
+
when 1
|
135
|
+
sec_class = "kSecClassGenericPassword"
|
136
|
+
when 2
|
137
|
+
sec_class = "kSecClassInternetPassword"
|
138
|
+
when 3
|
139
|
+
sec_class = "kSecClassCertificate"
|
140
|
+
when 4
|
141
|
+
sec_class = "kSecClassKey"
|
142
|
+
when 5
|
143
|
+
sec_class = "kSecClassIdentity"
|
144
|
+
end
|
145
|
+
row << Qt::StandardItem.new(sec_class)
|
146
|
+
|
147
|
+
access = nil
|
148
|
+
case e.value["accessible"].value
|
149
|
+
when 0
|
150
|
+
access = "Unkown"
|
151
|
+
when 1
|
152
|
+
access = "kSecAttrAccessibleWhenUnlocked"
|
153
|
+
when 2
|
154
|
+
access = "kSecAttrAccessibleAfterFirstUnlock"
|
155
|
+
when 3
|
156
|
+
access = "kSecAttrAccessibleAlways"
|
157
|
+
when 4
|
158
|
+
access = "kSecAttrAccessibleWhenUnlockedThisDeviceOnly"
|
159
|
+
when 5
|
160
|
+
access = "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly"
|
161
|
+
when 6
|
162
|
+
access = "kSecAttrAccessibleAlwaysThisDeviceOnly"
|
163
|
+
end
|
164
|
+
row << Qt::StandardItem.new(access)
|
165
|
+
|
166
|
+
row
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require_relative '../lib/snoop_it_wrapper'
|
2
|
+
|
3
|
+
module Idb
|
4
|
+
class SnooptItSensitiveAPIWidget < Qt::Widget
|
5
|
+
|
6
|
+
|
7
|
+
def initialize *args
|
8
|
+
super *args
|
9
|
+
|
10
|
+
@snoop = SnoopItWrapper.new
|
11
|
+
|
12
|
+
@model = Qt::StandardItemModel.new
|
13
|
+
|
14
|
+
@selection_model = Qt::ItemSelectionModel.new @model
|
15
|
+
@selection_model.model
|
16
|
+
|
17
|
+
@events_tab = Qt::TableView.new
|
18
|
+
@events_tab.setModel @selection_model.model
|
19
|
+
@events_tab.setSelectionModel(@selection_model)
|
20
|
+
|
21
|
+
@events_tab.setSelectionBehavior(Qt::AbstractItemView::SelectRows)
|
22
|
+
@events_tab.setEditTriggers(Qt::AbstractItemView::NoEditTriggers )
|
23
|
+
|
24
|
+
@start = Qt::PushButton.new "Start"
|
25
|
+
@start.connect(SIGNAL :released) {
|
26
|
+
@start.setEnabled(false)
|
27
|
+
@stop.setEnabled(true)
|
28
|
+
start_stream
|
29
|
+
}
|
30
|
+
|
31
|
+
@stop = Qt::PushButton.new "Stop"
|
32
|
+
@stop.setEnabled(false)
|
33
|
+
@stop.connect(SIGNAL :released) {
|
34
|
+
@start.setEnabled(true)
|
35
|
+
@stop.setEnabled(false)
|
36
|
+
stop_stream
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
layout = Qt::VBoxLayout.new do |v|
|
41
|
+
v.add_widget(@events_tab)
|
42
|
+
v.add_widget(@start)
|
43
|
+
v.add_widget(@stop)
|
44
|
+
end
|
45
|
+
setLayout(layout)
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def reset
|
52
|
+
@model.clear
|
53
|
+
@model.setHorizontalHeaderItem(0, Qt::StandardItem.new("Subject"))
|
54
|
+
@model.setHorizontalHeaderItem(1, Qt::StandardItem.new("Expiry"))
|
55
|
+
@model.setHorizontalHeaderItem(2, Qt::StandardItem.new("Issuer"))
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def start_stream
|
60
|
+
|
61
|
+
|
62
|
+
@thread = SnoopItUpdateThread.new
|
63
|
+
@thread.connect(SIGNAL('new_events(QVariant)')) { |events|
|
64
|
+
if not events.value.nil?
|
65
|
+
@events_tab.blockSignals(true)
|
66
|
+
events.value.each { |e|
|
67
|
+
#TODO if there are many, display status
|
68
|
+
row = parse_event e
|
69
|
+
@model.appendRow(row)
|
70
|
+
Qt::Application::processEvents
|
71
|
+
|
72
|
+
}
|
73
|
+
@events_tab.blockSignals(false)
|
74
|
+
@events_tab.resizeColumnsToContents
|
75
|
+
@events_tab.resizeRowsToContents
|
76
|
+
end
|
77
|
+
}
|
78
|
+
@snoop.sensitiveapi_delete
|
79
|
+
@thread.stream 'sensitiveapi_after_id'
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
private
|
85
|
+
def parse_event e
|
86
|
+
row = Array.new
|
87
|
+
row << Qt::StandardItem.new(e.value["id"].value.to_s)
|
88
|
+
|
89
|
+
row << Qt::StandardItem.new(Time.at(e.value["timestamp"].value).to_s)
|
90
|
+
|
91
|
+
mode = nil
|
92
|
+
|
93
|
+
case e.value["api"].value
|
94
|
+
when 1
|
95
|
+
mode = "Unique Device ID (UDID)"
|
96
|
+
when 2
|
97
|
+
mode = "Wifi MAC Address"
|
98
|
+
when 3
|
99
|
+
mode = "Addressbook (via API)"
|
100
|
+
when 4
|
101
|
+
mode = "Calendar (via API)"
|
102
|
+
when 5
|
103
|
+
mode = "Photos / Videos"
|
104
|
+
when 6
|
105
|
+
mode = "Location"
|
106
|
+
when 7
|
107
|
+
mode = "Addressbook (File Access)"
|
108
|
+
when 8
|
109
|
+
mode = "Calendar (File Access)"
|
110
|
+
when 9
|
111
|
+
mode = "Audio recording"
|
112
|
+
when 10
|
113
|
+
mode = "Camera"
|
114
|
+
when 11
|
115
|
+
mode = "General Pasteboard"
|
116
|
+
when 12
|
117
|
+
mode = "Find Paasteboard"
|
118
|
+
when 13
|
119
|
+
mode = "Custom Pasteboard"
|
120
|
+
end
|
121
|
+
|
122
|
+
row << Qt::StandardItem.new(mode)
|
123
|
+
|
124
|
+
row
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|