ClickSpotter 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,237 @@
1
+ #
2
+ # GlobalSettings.rb - ClickSpotter
3
+ #
4
+ # Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of version 2 of the GNU General Public License as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # $Id: GlobalSettings.rb 13 2006-01-23 20:50:55Z cs $
10
+ #
11
+
12
+ require 'Qt'
13
+ require 'GSServerLogSettings'
14
+ require 'yaml'
15
+ require 'set'
16
+
17
+ class GlobalSettings
18
+
19
+ attr_accessor :browserCmd, :serverLogFiles, :currentLogFile
20
+ attr_reader :robotPatterns
21
+
22
+ def initialize(loadOnStartLog)
23
+ @logFile = nil
24
+ @browserCmd = 'kfmclient exec'
25
+ @loadOnStartLog = loadOnStartLog
26
+ @currentLogFile = nil
27
+ @serverLogFiles = []
28
+ @auxFileExtensions = Set.new [ ".jpg", ".gif", ".png", ".bmp", ".js",
29
+ ".css", ".ico" ]
30
+ @robotPatterns = [
31
+ { "name" => "MSB", "ip" => ".*", "browser" => "^msnbot/.*" },
32
+ { "name" => "Yahoo", "ip" => ".*", "browser" => ".*Yahoo\! Slurp.*" },
33
+ { "name" => "Google", "ip" => ".*",
34
+ "browser" => ".*Googlebot/.*" },
35
+ { "name" => "Google Image", "ip" => ".*",
36
+ "browser" => ".*Googlebot-Image/.*" },
37
+ { "name" => "ASK.com", "ip" => ".*",
38
+ "browser" => ".*Ask Jeeves/Teoma.*\.ask\.com" },
39
+ { "name" => "Rambler", "ip" => ".*",
40
+ "browser" => "^StackRambler/2.0 \(MSIE incompatible\).*" },
41
+ { "name" => "Exabot", "ip" => ".*", "browser" => "^NG/.*" },
42
+ { "name" => "NimbleCrawler", "ip" => ".*",
43
+ "browser" => ".*NimbleCrawler .* obeys UserAgent NimbleCrawler.*" },
44
+ { "name" => "ConveraCrawler", "ip" => ".*",
45
+ "browser" => "ConveraCrawler.*" },
46
+ { "name" => "Voyager", "ip" => ".*", "browser" => "voyager/.*" },
47
+ { "name" => "Omni-Explorer", "ip" => ".*",
48
+ "browser" => "OmniExplorer_Bot/.* WorldIndexer" },
49
+ { "name" => "YahooMMCrawler", "ip" => ".*",
50
+ "browser" => "Yahoo-MMCrawler/.*" },
51
+ { "name" => "Alexa Crawler", "ip" => ".*", "browser" => "ia_archiver" },
52
+ { "name" => "QuickFinder.*", "ip" => ".*",
53
+ "browser" => "QuickFinder Crawler" },
54
+ { "name" => "Noxtrum", "ip" => ".*", "browser" => "noxtrumbot/.*" },
55
+ { "name" => "Exabot", "ip" => ".*", "browser" => "Exabot/.*" },
56
+ { "name" => "Picsearch", "ip" => ".*", "browser" => "psbot/.*" }
57
+ ]
58
+
59
+ @persistentSettings = {
60
+ "DNSResolver" => true,
61
+ "Geolocator" => true,
62
+ "TraceRouter" => true,
63
+ "MainWindowW" => 0,
64
+ "MainWindowH" => 1,
65
+ "LargeMapW" => 0,
66
+ "LargeMapH" => 0,
67
+ "CurrentStatusSplitter" => [],
68
+ "VisitorWindowW" => 0,
69
+ "VisitorWindowH" => 0,
70
+ "PageWindowW" => 0,
71
+ "PageWindowH" => 0,
72
+ "RefererWindowW" => 0,
73
+ "RefererWindowH" => 0,
74
+ "MonitorWindow" => 10,
75
+ "ShowSurfers" => 1,
76
+ "ShowRobots" => 0,
77
+ "ShowRegularPages" => 1,
78
+ "ShowAuxPages" => 0,
79
+ "BrowserCommand" => "kfmclient exec",
80
+ "DNSCache" => {},
81
+ "GeoLocatorCache" => {},
82
+ "TraceRouterCache" => {},
83
+ "LogFileDataTimeout" => 24,
84
+ "DNSTimeout" => 7,
85
+ "GeolocTimeout" => 30,
86
+ "TracerTimeout" => 48,
87
+ "GeolocHost" => "api.hostip.info",
88
+ "GeolocPort" => 80,
89
+ "WMShowIPs" => false,
90
+ "WMShowHostNames" => false,
91
+ "WMShowCityNames" => false,
92
+ "WMShowRouters" => false,
93
+ "WMShowRoutes" => false,
94
+ "WMShowLast" => false,
95
+ "WMLastMinutes" => 1
96
+ }
97
+
98
+ @mainWindowW = 0
99
+ @mainWindowH = 0
100
+ @currentStatusSplitter = []
101
+
102
+ loadSettings()
103
+ end
104
+
105
+ def setSetting(name, value)
106
+ if !@persistentSettings.has_key?(name)
107
+ raise "Unknown setting #{name}"
108
+ end
109
+ vClass = @persistentSettings[name].class
110
+ unless ((vClass == FalseClass || vClass == TrueClass) &&
111
+ (value.class != FalseClass || value.class != TrueClass)) ||
112
+ vClass == value.class
113
+ raise "Bad setting type for #{name}! " +
114
+ "#{@persistentSettings[name].class()} != #{value.class()}"
115
+ end
116
+ @persistentSettings[name] = value
117
+ end
118
+
119
+ def getSetting(name)
120
+ if !@persistentSettings.has_key?(name)
121
+ raise "Unknown setting #{name}"
122
+ end
123
+ return @persistentSettings[name]
124
+ end
125
+
126
+ def loadSettings
127
+ qs = Qt::Settings.new()
128
+ qs.setPath("ClickSpotterProject", "ClickSpotter")
129
+ qs.beginGroup("/clickspotter");
130
+ ok = Qt::Boolean.new
131
+ @persistentSettings.each do |name, value|
132
+ if value.class == Fixnum
133
+ val = Qt::Integer.new(value)
134
+ newValue = qs.readNumEntry("/#{name}", val, ok)
135
+ elsif value.class == String
136
+ newValue = qs.readEntry("/#{name}", value, ok)
137
+ elsif value.class == FalseClass || value.class == TrueClass
138
+ val = Qt::Integer.new(value ? 1 : 0)
139
+ newValue = qs.readNumEntry("/#{name}", val, ok) != 0
140
+ elsif value.class == Array || value.class == Hash
141
+ data = qs.readEntry("/#{name}", YAML.dump(value), ok)
142
+ newValue = YAML.load(data) if data && ok
143
+ else
144
+ raise "#{name} has unsupported type #{value.class()}"
145
+ end
146
+ @persistentSettings[name] = newValue if ok
147
+ end
148
+ data = qs.readEntry('/ServerLogFiles', nil, ok)
149
+ @serverLogFiles = YAML.load(data) if data && ok
150
+ @serverLogFiles.each do |sl|
151
+ if sl.name == @loadOnStartLog
152
+ @currentLogFile = sl
153
+ break;
154
+ end
155
+ end
156
+ qs.endGroup()
157
+ end
158
+
159
+ def saveSettings
160
+ qs = Qt::Settings.new()
161
+ qs.setPath("ClickSpotterProject", "ClickSpotter")
162
+ qs.beginGroup("/clickspotter");
163
+ @persistentSettings.each do |name, value|
164
+ if value.class == Fixnum || value.class == String
165
+ qs.writeEntry("/#{name}", value)
166
+ elsif value.class == FalseClass || value.class == TrueClass
167
+ qs.writeEntry("/#{name}", value ? 1 : 0)
168
+ elsif value.class == Array || value.class == Hash
169
+ qs.writeEntry("/#{name}", YAML.dump(value))
170
+ end
171
+ end
172
+ qs.writeEntry('/ServerLogFiles', YAML.dump(@serverLogFiles))
173
+ qs.endGroup()
174
+ qs.sync
175
+ qs.dispose
176
+ end
177
+
178
+ def readEntryList(qs, name, list)
179
+ i = 0
180
+ ok = Qt::Boolean.new
181
+ while true
182
+ value = qs.readEntry("#{name}_#{i}", nil, ok)
183
+ break if not !ok.nil?
184
+ list.push(value) if
185
+ i += 1
186
+ end
187
+ end
188
+
189
+ def writeEntryList(qs, name, list)
190
+ i = 0
191
+ list.each do |value|
192
+ qs.writeEntry("/#{name}_#{i}", value)
193
+ i += 1
194
+ end
195
+ end
196
+
197
+ def addServerLogFile(slf)
198
+ @serverLogFiles << slf
199
+ end
200
+
201
+ def setAsCurrentLogFile(name)
202
+ @currentLogFile = @serverLogFiles.find { |sl| sl.name == name }
203
+ end
204
+
205
+ def defaultServerURL
206
+ @currentLogFile.default
207
+ end
208
+
209
+ def serverNames
210
+ @currentLogFile.hostNames
211
+ end
212
+
213
+ def isAuxFile(fn)
214
+ return false unless dot = fn.rindex('.')
215
+ ext = fn[dot .. -1]
216
+ return false if ext.empty?
217
+ @auxFileExtensions.include?(ext)
218
+ end
219
+
220
+ def logFile
221
+ return nil unless @currentLogFile
222
+ @currentLogFile.logFile
223
+ end
224
+
225
+ def isRobot(ip, browser, url)
226
+ @robotPatterns.each do |rp|
227
+ if Regexp.new(rp["ip"]) =~ ip &&
228
+ Regexp.new(rp["browser"]) =~ browser
229
+ return rp["name"]
230
+ end
231
+ end
232
+ return 'Unknown' if url == '/robots.txt'
233
+ return nil
234
+ end
235
+
236
+ end
237
+
@@ -0,0 +1,39 @@
1
+ #
2
+ # HitRecord.rb - ClickSpotter
3
+ #
4
+ # Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of version 2 of the GNU General Public License as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # $Id: HitRecord.rb 8 2006-01-22 15:19:51Z cs $
10
+ #
11
+
12
+ class HitRecord
13
+
14
+ attr_reader :timeStamp, :bytes, :code, :request
15
+ attr_accessor :visitor, :page, :referer, :entry, :exit
16
+
17
+ def initialize(rec)
18
+ @uid = rec['uid']
19
+ @timeStamp = rec['timeStamp']
20
+ @request = rec['request']
21
+ @code = rec['code']
22
+ @bytes = rec['bytes']
23
+ @visitor = nil
24
+ @page = nil
25
+ @referer = nil
26
+ @entry = false
27
+ @exit = false
28
+ end
29
+
30
+ def to_s
31
+ puts "#{@timeStamp} Request: '#{@request}' Bytes: #{@bytes}"
32
+ end
33
+
34
+ def url
35
+ return page.url
36
+ end
37
+
38
+ end
39
+
@@ -0,0 +1,83 @@
1
+ # Form implementation generated from reading ui file 'HostNameDlg.ui'
2
+ #
3
+ # Created: Mon Jan 23 23:21:52 2006
4
+ # by: The QtRuby User Interface Compiler (rbuic)
5
+ #
6
+ # WARNING! All changes made in this file will be lost!
7
+
8
+
9
+ require 'Qt'
10
+
11
+ class HostNameDlg < Qt::Dialog
12
+
13
+ attr_reader :okBtn
14
+ attr_reader :cancelBtn
15
+ attr_reader :textLabel7
16
+ attr_reader :hostName
17
+ attr_reader :textLabel8
18
+
19
+
20
+ def initialize(parent = nil, name = nil, modal = false, fl = 0)
21
+ super
22
+
23
+ if name.nil?
24
+ setName("HostNameDlg")
25
+ end
26
+ setSizeGripEnabled(true)
27
+
28
+ @HostNameDlgLayout = Qt::GridLayout.new(self, 1, 1, 11, 6, 'HostNameDlgLayout')
29
+
30
+ @Layout1 = Qt::HBoxLayout.new(nil, 0, 6, 'Layout1')
31
+ @Horizontal_Spacing2 = Qt::SpacerItem.new(20, 20, Qt::SizePolicy::Expanding, Qt::SizePolicy::Minimum)
32
+ @Layout1.addItem(@Horizontal_Spacing2)
33
+
34
+ @okBtn = Qt::PushButton.new(self, "okBtn")
35
+ @okBtn.setAutoDefault( true )
36
+ @okBtn.setDefault( true )
37
+ @Layout1.addWidget(@okBtn)
38
+
39
+ @cancelBtn = Qt::PushButton.new(self, "cancelBtn")
40
+ @cancelBtn.setAutoDefault( true )
41
+ @Layout1.addWidget(@cancelBtn)
42
+
43
+ @HostNameDlgLayout.addLayout(@Layout1, 3, 0)
44
+
45
+ @textLabel7 = Qt::Label.new(self, "textLabel7")
46
+
47
+ @HostNameDlgLayout.addWidget(@textLabel7, 2, 0)
48
+
49
+ @hostName = Qt::LineEdit.new(self, "hostName")
50
+
51
+ @HostNameDlgLayout.addWidget(@hostName, 1, 0)
52
+
53
+ @textLabel8 = Qt::Label.new(self, "textLabel8")
54
+
55
+ @HostNameDlgLayout.addWidget(@textLabel8, 0, 0)
56
+ languageChange()
57
+ resize( Qt::Size.new(295, 126).expandedTo(minimumSizeHint()) )
58
+ clearWState( WState_Polished )
59
+
60
+ Qt::Object.connect(@okBtn, SIGNAL("clicked()"), self, SLOT("accept()") )
61
+ Qt::Object.connect(@cancelBtn, SIGNAL("clicked()"), self, SLOT("reject()") )
62
+
63
+ setTabOrder(@hostName, @okBtn)
64
+ setTabOrder(@okBtn, @cancelBtn)
65
+ end
66
+
67
+ #
68
+ # Sets the strings of the subwidgets using the current
69
+ # language.
70
+ #
71
+ def languageChange()
72
+ setCaption(trUtf8("Enter Server URL"))
73
+ @okBtn.setText( trUtf8("&OK") )
74
+ @okBtn.setAccel( Qt::KeySequence.new(trUtf8("Alt+O")) )
75
+ @cancelBtn.setText( trUtf8("&Cancel") )
76
+ @cancelBtn.setAccel( Qt::KeySequence.new(trUtf8("Alt+C")) )
77
+ @textLabel7.setText( trUtf8("e.g. http://www.mydomain.org") )
78
+ @textLabel8.setText( trUtf8("Please enter a base URL of your server.") )
79
+ end
80
+ protected :languageChange
81
+
82
+
83
+ end
@@ -0,0 +1,65 @@
1
+ #
2
+ # LogFileSelector.rb - ClickSpotter
3
+ #
4
+ # Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of version 2 of the GNU General Public License as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # $Id: LogFileSelector.rb 8 2006-01-22 15:19:51Z cs $
10
+ #
11
+
12
+ require 'LogFileSelectorDlg'
13
+ require 'CSListView'
14
+ require 'GlobalSettings'
15
+
16
+ class LogFileSelector < LogFileSelectorDlg
17
+
18
+ slots 'selectionChanged(QListViewItem*)', 'clicked(QListViewItem*)'
19
+
20
+ def initialize(parent = nil, name = nil)
21
+ super(parent, name)
22
+
23
+ @fileListCSLV = CSListView.new(@fileList)
24
+ @fileList.setSorting(1, true)
25
+
26
+ addLogsToList
27
+
28
+ connect(@fileList, SIGNAL('selectionChanged(QListViewItem*)'),
29
+ SLOT('selectionChanged(QListViewItem*)'))
30
+ connect(@fileList, SIGNAL('clicked(QListViewItem*)'),
31
+ SLOT('clicked(QListViewItem*)'))
32
+
33
+ show
34
+ end
35
+
36
+ def addLogsToList
37
+ @fileListCSLV.startUpdate
38
+ $globals.serverLogFiles.each do |slf|
39
+ @fileListCSLV.insertItem(slf, slf.name, slf.logFile)
40
+ end
41
+ @fileListCSLV.finishUpdate
42
+ end
43
+
44
+ def selectedLogFile
45
+ @fileListCSLV.selectedItemList[0]
46
+ end
47
+
48
+ def selectionChanged(item)
49
+ @monitorBtn.setEnabled(item != nil)
50
+ end
51
+
52
+ def clicked(item)
53
+ @monitorBtn.setEnabled(false) unless item
54
+ end
55
+
56
+ def otherLogBtnClicked
57
+ settings = GSServerLogSettings.new
58
+ if ServerLogSettings.new(settings, self).exec() == Qt::Dialog.Accepted
59
+ $globals.addServerLogFile(settings)
60
+ addLogsToList
61
+ end
62
+ end
63
+
64
+ end
65
+
@@ -0,0 +1,97 @@
1
+ # Form implementation generated from reading ui file 'LogFileSelectorDlg.ui'
2
+ #
3
+ # Created: Mon Jan 23 23:21:52 2006
4
+ # by: The QtRuby User Interface Compiler (rbuic)
5
+ #
6
+ # WARNING! All changes made in this file will be lost!
7
+
8
+
9
+ require 'Qt'
10
+
11
+ class LogFileSelectorDlg < Qt::Dialog
12
+
13
+ slots 'languageChange()',
14
+ 'otherLogBtnClicked()'
15
+
16
+ attr_reader :fileList
17
+ attr_reader :textLabel1
18
+ attr_reader :otherLogBtn
19
+ attr_reader :monitorBtn
20
+ attr_reader :cancelBtn
21
+
22
+
23
+ def initialize(parent = nil, name = nil, modal = false, fl = 0)
24
+ super
25
+
26
+ if name.nil?
27
+ setName("LogFileSelectorDlg")
28
+ end
29
+ setSizeGripEnabled(true)
30
+
31
+ @LogFileSelectorDlgLayout = Qt::GridLayout.new(self, 1, 1, 11, 6, 'LogFileSelectorDlgLayout')
32
+
33
+ @fileList = Qt::ListView.new(self, "fileList")
34
+ @fileList.addColumn(trUtf8("Name"))
35
+ @fileList.addColumn(trUtf8("File"))
36
+ @fileList.setAllColumnsShowFocus( true )
37
+
38
+ @LogFileSelectorDlgLayout.addWidget(@fileList, 1, 0)
39
+
40
+ @textLabel1 = Qt::Label.new(self, "textLabel1")
41
+
42
+ @LogFileSelectorDlgLayout.addWidget(@textLabel1, 0, 0)
43
+
44
+ @layout2 = Qt::HBoxLayout.new(nil, 0, 6, 'layout2')
45
+
46
+ @otherLogBtn = Qt::PushButton.new(self, "otherLogBtn")
47
+ @layout2.addWidget(@otherLogBtn)
48
+ @Horizontal_Spacing2 = Qt::SpacerItem.new(230, 20, Qt::SizePolicy::Expanding, Qt::SizePolicy::Minimum)
49
+ @layout2.addItem(@Horizontal_Spacing2)
50
+
51
+ @monitorBtn = Qt::PushButton.new(self, "monitorBtn")
52
+ @monitorBtn.setEnabled( false )
53
+ @monitorBtn.setAutoDefault( true )
54
+ @monitorBtn.setDefault( true )
55
+ @layout2.addWidget(@monitorBtn)
56
+
57
+ @cancelBtn = Qt::PushButton.new(self, "cancelBtn")
58
+ @cancelBtn.setAutoDefault( true )
59
+ @layout2.addWidget(@cancelBtn)
60
+
61
+ @LogFileSelectorDlgLayout.addLayout(@layout2, 2, 0)
62
+ languageChange()
63
+ resize( Qt::Size.new(511, 282).expandedTo(minimumSizeHint()) )
64
+ clearWState( WState_Polished )
65
+
66
+ Qt::Object.connect(@fileList, SIGNAL("doubleClicked(QListViewItem*)"), self, SLOT("accept()") )
67
+ Qt::Object.connect(@cancelBtn, SIGNAL("clicked()"), self, SLOT("reject()") )
68
+ Qt::Object.connect(@otherLogBtn, SIGNAL("clicked()"), self, SLOT("otherLogBtnClicked()") )
69
+ Qt::Object.connect(@monitorBtn, SIGNAL("clicked()"), self, SLOT("accept()") )
70
+ end
71
+
72
+ #
73
+ # Sets the strings of the subwidgets using the current
74
+ # language.
75
+ #
76
+ def languageChange()
77
+ setCaption(trUtf8("Log File Selector"))
78
+ @fileList.header().setLabel( 0, trUtf8("Name") )
79
+ @fileList.header().setLabel( 1, trUtf8("File") )
80
+ @textLabel1.setText( trUtf8("Please select the log file that you want to monitor. In case the file that \n" +
81
+ "you want to monitor is not yet defined, please select \"Cancel\" and then\n" +
82
+ "you can define the log file first.") )
83
+ @otherLogBtn.setText( trUtf8("&Other Log File") )
84
+ @otherLogBtn.setAccel( Qt::KeySequence.new(trUtf8("Alt+O")) )
85
+ @monitorBtn.setText( trUtf8("&Monitor") )
86
+ @monitorBtn.setAccel( Qt::KeySequence.new(trUtf8("Alt+M")) )
87
+ @cancelBtn.setText( trUtf8("&Quit") )
88
+ @cancelBtn.setAccel( Qt::KeySequence.new(trUtf8("Alt+Q")) )
89
+ end
90
+ protected :languageChange
91
+
92
+
93
+ def otherLogBtnClicked(*k)
94
+ print("LogFileSelectorDlg.otherLogBtnClicked(): Not implemented yet.\n")
95
+ end
96
+
97
+ end