rwdschedule 0.99 → 1.00
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme.txt +10 -0
- data/code/superant.com.schedule/downloadrwdschedulefiles.rb +19 -13
- data/code/superant.com.schedule/loadconfigurationrecord.rb +1 -2
- data/code/superant.com.schedule/saveconfigurationrecord.rb +4 -1
- data/code/superant.com.schedule/test_cases.rb +46 -0
- data/configuration/rwdapplicationidentity.dist +1 -1
- data/configuration/rwdschedule.dist +3 -2
- data/configuration/rwdtinker.dist +2 -2
- data/extras/icalendar/base.rb +17 -0
- data/extras/icalendar/calendar.rb +44 -0
- data/extras/icalendar/calendar_parser.rb +237 -0
- data/extras/icalendar/component.rb +91 -0
- data/extras/icalendar/component/alarm.rb +16 -0
- data/extras/icalendar/component/event.rb +25 -0
- data/extras/icalendar/component/freebusy.rb +12 -0
- data/extras/icalendar/component/journal.rb +25 -0
- data/extras/icalendar/component/timezone.rb +26 -0
- data/extras/icalendar/component/todo.rb +21 -0
- data/extras/icalendar/helpers.rb +103 -0
- data/extras/icalendar/parameter.rb +25 -0
- data/extras/zip/ioextras.rb +114 -0
- data/extras/zip/stdrubyext.rb +111 -0
- data/extras/zip/tempfile_bugfixed.rb +195 -0
- data/extras/zip/zip.rb +1377 -0
- data/extras/zip/zipfilesystem.rb +558 -0
- data/extras/zip/ziprequire.rb +61 -0
- data/gui/00coreguibegin/applicationguitop.rwd +1 -1
- data/rwd_files/HowTo_Schedule.txt +4 -0
- data/rwd_files/HowTo_Tinker.txt +3 -0
- data/schedules/200505may02a.sch +4 -0
- data/tests/RubyGauge.rb +179 -0
- data/tests/makedist.rb +1 -0
- metadata +24 -7
- data/schedules/200502february22 test event.sch +0 -5
- data/updates/200507july04a.sch +0 -8
data/Readme.txt
CHANGED
@@ -154,6 +154,16 @@ Steven Gibson
|
|
154
154
|
steven@superant.com
|
155
155
|
|
156
156
|
== Changelog
|
157
|
+
Version 1.00
|
158
|
+
fixed sync download
|
159
|
+
added more unit tests
|
160
|
+
|
161
|
+
Version 0.99
|
162
|
+
updated for rwdtinker version 1.64
|
163
|
+
changed handling of application name returned
|
164
|
+
added jump seletion options
|
165
|
+
added some unit tests
|
166
|
+
|
157
167
|
version 0.98
|
158
168
|
updated for rwdtinker version 1.61
|
159
169
|
add in test harness
|
@@ -9,24 +9,30 @@ def downloadrwdschedulefiles
|
|
9
9
|
ftp.login($rwdschedule_ftplogin, $rwdschedule_ftppassword)
|
10
10
|
ftp.chdir($rwdschedule_ftpdirectory)
|
11
11
|
print "I'm in the directory ", ftp.pwd(), "\n"
|
12
|
-
schfiles = ftp.nlst($rwdschedule_ftpdirectory)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
schfiles = ftp.nlst($rwdschedule_ftpdirectory)
|
13
|
+
#puts schfiles
|
14
|
+
$stderr.print $rwdschedule_updatedirectory
|
15
|
+
|
16
|
+
schfiles.each {|x|
|
17
|
+
#adjust the filters to the files you want to see...
|
18
|
+
|
19
|
+
if x =~ /sch/
|
20
|
+
#lastslash = x.rindex('/')+1
|
21
|
+
#newstring = x.slice!(lastslash..256)
|
22
|
+
newstring = x
|
23
|
+
# $stderr.print newstring.to_s
|
24
|
+
localupdatefile = File.join($rwdschedule_updatedirectory, "#{x}")
|
25
|
+
ftp.getbinaryfile("#{x}" , localupdatefile )
|
21
26
|
@rwdscheduleftpdisplay = @rwdscheduleftpdisplay + newstring + "\n"
|
22
|
-
end
|
23
|
-
end
|
24
27
|
|
25
|
-
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
}
|
26
32
|
ftp.close
|
27
33
|
|
28
34
|
rescue
|
29
|
-
|
35
|
+
@rwdscheduleftpdisplay = "ftp error"
|
30
36
|
if ftp
|
31
37
|
ftp.close
|
32
38
|
end
|
@@ -23,8 +23,7 @@
|
|
23
23
|
@a_schconfigline8 = fd.readline.chomp
|
24
24
|
@a_schconfigline9 = fd.readline.chomp
|
25
25
|
@a_schconfigline10= fd.readline.chomp
|
26
|
-
@
|
27
|
-
@a_schconfigline11= fd.readline.chomp
|
26
|
+
@a_schconfigline11= fd.readline.chomp
|
28
27
|
@a_schconfigline12= fd.readline.chomp
|
29
28
|
@a_schconfigline13= fd.readline.chomp
|
30
29
|
@a_schconfigline14= fd.readline.chomp
|
@@ -3,7 +3,10 @@
|
|
3
3
|
require 'fileutils'
|
4
4
|
|
5
5
|
newname = "rwdschedule.cnf" # grab the filename to create
|
6
|
-
newdata =@a_schconfigline1.to_s + "\n" + @a_schconfigline2.to_s + "\n" + @a_schconfigline3.to_s + "\n" + @a_schconfigline4.to_s + "\n" + @a_schconfigline5.to_s + "\n" +
|
6
|
+
newdata =@a_schconfigline1.to_s + "\n" + @a_schconfigline2.to_s + "\n" + @a_schconfigline3.to_s + "\n" + @a_schconfigline4.to_s + "\n" + @a_schconfigline5.to_s + "\n" +
|
7
|
+
@a_schconfigline6.to_s + "\n" + @a_schconfigline7.to_s + "\n" + @a_schconfigline8.to_s + "\n" + @a_schconfigline9.to_s + "\n"+
|
8
|
+
@a_schconfigline10.to_s + "\n" + @a_schconfigline11.to_s + "\n"+ @a_schconfigline12.to_s +
|
9
|
+
"\n" + @a_schconfigline13.to_s + "\n"+ @a_schconfigline14.to_s + "\n"+ @a_schconfigline15.to_s + "\n"
|
7
10
|
|
8
11
|
begin # exception trapped block
|
9
12
|
fileName = File.join( ConfigurationDir, newname )
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# test harness
|
2
|
+
|
3
|
+
|
4
|
+
require 'test/unit/testcase'
|
5
|
+
require 'test/unit/assertions'
|
6
|
+
include Test::Unit::Assertions
|
7
|
+
include Test::Unit
|
8
|
+
def rwdschedule_all_tests
|
9
|
+
print "in rwdschedule all tests\n"
|
10
|
+
$testrwdscheduletestcase = TestSuite.new
|
11
|
+
test_runrwdschedule
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_runrwdschedule
|
15
|
+
|
16
|
+
|
17
|
+
begin
|
18
|
+
testasserts = 0
|
19
|
+
print "Starting rwdtorrent tests!\n"
|
20
|
+
runselectiontab
|
21
|
+
assert_equal("selectiontab",@rwd_tab) ; testasserts += 1
|
22
|
+
runrwdschedulemenu10
|
23
|
+
assert_equal("viewrwdscheduleconfiguration",@rwd_tab) ; testasserts += 1
|
24
|
+
loadrwdscheduleconfiguration
|
25
|
+
assert_equal("rwdschedule.cnf",@a_schconfigurationfilename) ; testasserts += 1
|
26
|
+
|
27
|
+
$stderr.print "tests completed succesfully!\n"
|
28
|
+
$stderr.print testasserts, " asserts performed\n"
|
29
|
+
|
30
|
+
rescue NotImplementedError, Exception
|
31
|
+
$stderr.print $!
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
def teststobedown
|
40
|
+
runtinkerhelpabout
|
41
|
+
assert_equal("rwdtinkerhelpwindow",@rwd_tab) ; testasserts += 1
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
##VERSION:
|
1
|
+
##VERSION:1.00
|
2
2
|
##NAME:$rwdschedule_directory:0
|
3
3
|
$rwdschedule_directory = "schedules"
|
4
4
|
##NAME:$rwdschedule_ftpsite:0
|
@@ -11,5 +11,6 @@ $rwdschedule_ftppassword = "mypassword"
|
|
11
11
|
$rwdschedule_ftpdirectory = "/incoming/rwdschedules/"
|
12
12
|
##NAME:$rwdschedule_updatedirectory:0
|
13
13
|
$rwdschedule_updatedirectory = "updates"
|
14
|
-
|
14
|
+
$testharnessarray += ["rwdschedule_all_tests"]
|
15
|
+
RwdScheduleVersion = "1.00"
|
15
16
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
##VERSION:1.
|
1
|
+
##VERSION:1.64
|
2
2
|
ConfigurationDir = "configuration" # for use in program - init.rb has this value without using this constant
|
3
3
|
CodeName = "rwdtinker"
|
4
4
|
CodeNameFile = CodeName + ".rb"
|
@@ -12,4 +12,4 @@ LangDir = "lang"
|
|
12
12
|
$rwdcontrolports =["13713","13714","13715","13716","13717","13718"]
|
13
13
|
$port = 7705
|
14
14
|
$rwdjumplink = ["helpscreen","tinkerbackwindow","returntomain","opendocuments","editconfiguration"]
|
15
|
-
RwdTinkerVersion = "1.
|
15
|
+
RwdTinkerVersion = "1.64"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Icalendar #:nodoc:
|
4
|
+
class IcalendarError < StandardError #:nodoc:
|
5
|
+
end
|
6
|
+
|
7
|
+
class InvalidComponentClass < IcalendarError
|
8
|
+
end
|
9
|
+
|
10
|
+
class InvalidPropertyValue < IcalendarError
|
11
|
+
end
|
12
|
+
|
13
|
+
class Base
|
14
|
+
@@logger = Logger.new(STDOUT)
|
15
|
+
@@logger.level = Logger::INFO
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Icalendar
|
2
|
+
class Calendar < Component
|
3
|
+
|
4
|
+
attr_accessor :events, :todos, :journals, :freebusys, :timezones
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
super("VCALENDAR")
|
8
|
+
@properties = {}
|
9
|
+
@property_params = {}
|
10
|
+
|
11
|
+
@events = []
|
12
|
+
@todos = []
|
13
|
+
@journals = []
|
14
|
+
@freebusys = []
|
15
|
+
@timezones = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(component)
|
19
|
+
if component.is_a? Event
|
20
|
+
@events << component
|
21
|
+
elsif component.is_a? Todo
|
22
|
+
@todos << component
|
23
|
+
elsif component.is_a? Journal
|
24
|
+
@journals << component
|
25
|
+
elsif component.is_a? Freebusy
|
26
|
+
@freebusys << component
|
27
|
+
elsif component.is_a? Timezone
|
28
|
+
@timezones << component
|
29
|
+
else
|
30
|
+
raise InvalidComponentClass
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
print_string do |s|
|
36
|
+
@events.each { |event| s << event.to_s }
|
37
|
+
@todos.each { |todo| s << todo.to_s }
|
38
|
+
@journals.each { |journal| s << journal.to_s }
|
39
|
+
@freebusys.each { |freebusy| s << freebusy.to_s }
|
40
|
+
@timezones.each { |timezone| s << timezone.to_s }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
module Icalendar
|
2
|
+
class CalendarParser < Icalendar::Base
|
3
|
+
# 1*(ALPHA / DIGIT / "=")
|
4
|
+
NAME = '[-a-z0-9]+'
|
5
|
+
|
6
|
+
# <"> <Any character except CTLs, DQUOTE> <">
|
7
|
+
QSTR = '"[^"]*"'
|
8
|
+
|
9
|
+
# *<Any character except CTLs, DQUOTE, ";", ":", ",">
|
10
|
+
PTEXT = '[^";:,]*'
|
11
|
+
|
12
|
+
# param-value = ptext / quoted-string
|
13
|
+
PVALUE = "#{PTEXT}|#{QSTR}"
|
14
|
+
|
15
|
+
# Contentline
|
16
|
+
LINE = "(#{NAME})([^:]*)\:(.*)"
|
17
|
+
|
18
|
+
# param = name "=" param-value *("," param-value)
|
19
|
+
# Note: v2.1 allows a type or encoding param-value to appear without the type=
|
20
|
+
# or the encoding=. This is hideous, but we try and support it, if there # is no "=", then $2 will be "", and we will treat it as a v2.1 param.
|
21
|
+
PARAM = ";(#{NAME})(=?)((?:#{PVALUE})(?:,#{PVALUE})*)"
|
22
|
+
|
23
|
+
# date = date-fullyear ["-"] date-month ["-"] date-mday
|
24
|
+
# date-fullyear = 4 DIGIT
|
25
|
+
# date-month = 2 DIGIT
|
26
|
+
# date-mday = 2 DIGIT
|
27
|
+
DATE = '(\d\d\d\d)-?(\d\d)-?(\d\d)'
|
28
|
+
|
29
|
+
# time = time-hour [":"] time-minute [":"] time-second [time-secfrac] [time-zone]
|
30
|
+
# time-hour = 2 DIGIT
|
31
|
+
# time-minute = 2 DIGIT
|
32
|
+
# time-second = 2 DIGIT
|
33
|
+
# time-secfrac = "," 1*DIGIT
|
34
|
+
# time-zone = "Z" / time-numzone
|
35
|
+
# time-numzome = sign time-hour [":"] time-minute
|
36
|
+
TIME = '(\d\d):?(\d\d):?(\d\d)(\.\d+)?(Z|[-+]\d\d:?\d\d)?'
|
37
|
+
|
38
|
+
def initialize(src)
|
39
|
+
@@logger.info("New Calendar Parser")
|
40
|
+
|
41
|
+
# Define the next line method different depending on whether
|
42
|
+
# this is a string or an IO object so we can be efficient about
|
43
|
+
# parsing large files...
|
44
|
+
|
45
|
+
# Just do the unfolding work in one shot if its a whole string
|
46
|
+
if src.respond_to?(:split)
|
47
|
+
unfolded = []
|
48
|
+
|
49
|
+
# Split into an array of lines, then unfold those into a new array
|
50
|
+
src.split(/\r?\n/).each do |line|
|
51
|
+
|
52
|
+
# If it's a continuation line, add it to the last.
|
53
|
+
# If it's an empty line, drop it from the input.
|
54
|
+
if( line =~ /^[ \t]/ )
|
55
|
+
unfolded << unfolded.pop + line[1, line.size-1]
|
56
|
+
elsif( line =~ /^$/ )
|
57
|
+
else
|
58
|
+
unfolded << line
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
@lines = unfolded
|
63
|
+
@index = 0
|
64
|
+
|
65
|
+
# Now that we are unfolded we can just iterate through the array.
|
66
|
+
# Dynamically define next line for a string.
|
67
|
+
def next_line
|
68
|
+
if @index == @lines.size
|
69
|
+
return nil
|
70
|
+
else
|
71
|
+
line = @lines[@index]
|
72
|
+
@index += 1
|
73
|
+
return line
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# If its a file we need to read and unfold on the go to save from reading
|
78
|
+
# large amounts of data into memory.
|
79
|
+
elsif src.respond_to?(:gets)
|
80
|
+
@file = src
|
81
|
+
@prev_line = src.gets
|
82
|
+
if !@prev_line.nil?
|
83
|
+
@prev_line.chomp!
|
84
|
+
end
|
85
|
+
|
86
|
+
# Dynamically define next line for an IO object
|
87
|
+
def next_line
|
88
|
+
line = @prev_line
|
89
|
+
|
90
|
+
if line.nil?
|
91
|
+
return nil
|
92
|
+
end
|
93
|
+
|
94
|
+
# Loop through until we get to a non-continuation line...
|
95
|
+
loop do
|
96
|
+
nextLine = @file.gets
|
97
|
+
if !nextLine.nil?
|
98
|
+
nextLine.chomp!
|
99
|
+
end
|
100
|
+
|
101
|
+
# If it's a continuation line, add it to the last.
|
102
|
+
# If it's an empty line, drop it from the input.
|
103
|
+
if( nextLine =~ /^[ \t]/ )
|
104
|
+
line << nextLine[1, nextLine.size]
|
105
|
+
elsif( nextLine =~ /^$/ )
|
106
|
+
else
|
107
|
+
@prev_line = nextLine
|
108
|
+
break
|
109
|
+
end
|
110
|
+
end
|
111
|
+
line
|
112
|
+
end
|
113
|
+
else
|
114
|
+
raise ArgumentError, "CalendarParser.new cannot be called with a #{src.class} type!"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Parse the calendar into an object representation
|
119
|
+
def parse
|
120
|
+
calendars = []
|
121
|
+
|
122
|
+
# Outer loop for Calendar objects
|
123
|
+
while (line = next_line)
|
124
|
+
fields = parse_line(line)
|
125
|
+
|
126
|
+
# Just iterate through until we find the beginning of a calendar object
|
127
|
+
if fields[:name] == "BEGIN" and fields[:value] == "VCALENDAR"
|
128
|
+
cal = parse_calendar
|
129
|
+
calendars << cal
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
calendars
|
134
|
+
end
|
135
|
+
|
136
|
+
# Parse a single VCALENDAR object
|
137
|
+
# -- This should consist of the PRODID, VERSION, option METHOD & CALSCALE,
|
138
|
+
# and then one or more calendar components: VEVENT, VTODO, VJOURNAL,
|
139
|
+
# VFREEBUSY, VTIMEZONE
|
140
|
+
def parse_calendar(component = Calendar.new)
|
141
|
+
while (line = next_line)
|
142
|
+
fields = parse_line(line)
|
143
|
+
|
144
|
+
name = fields[:name]
|
145
|
+
|
146
|
+
# Although properties are supposed to come before components, we should
|
147
|
+
# be able to handle them in any order...
|
148
|
+
if name == "END"
|
149
|
+
break
|
150
|
+
elsif name == "BEGIN" # New component
|
151
|
+
case(fields[:value])
|
152
|
+
when "VEVENT"
|
153
|
+
component.events << parse_calendar(Event.new)
|
154
|
+
when "VTODO"
|
155
|
+
component.todos << parse_calendar(Todo.new)
|
156
|
+
when "VJOURNAL"
|
157
|
+
component.journals << parse_calendar(Journal.new)
|
158
|
+
when "VFREEBUSY"
|
159
|
+
component.freebusys << parse_calendar(Freebusy.new)
|
160
|
+
when "VTIMEZONE"
|
161
|
+
component.timezones << parse_calendar(Timezone.new)
|
162
|
+
when "VALARM"
|
163
|
+
component.alarms << parse_calendar(Alarm.new)
|
164
|
+
end
|
165
|
+
else # If its not a component then it should be properties...
|
166
|
+
|
167
|
+
# Just set the properties ourselves so that the parser can still
|
168
|
+
# parse invalid files...
|
169
|
+
@@logger.debug("Setting #{name} => #{fields[:value]}")
|
170
|
+
component.properties[name] = fields[:value]
|
171
|
+
if not fields[:params].empty?
|
172
|
+
component.property_params[name] = fields[:params]
|
173
|
+
end
|
174
|
+
|
175
|
+
# This will generate the correctly formed calls to the dynamic method
|
176
|
+
# handler.
|
177
|
+
# component.send("#{name}=", fields[:value])
|
178
|
+
# component.send("#{name}_params=", fields[:params]) unless fields[:params].empty?
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
component
|
183
|
+
end
|
184
|
+
|
185
|
+
def parse_line(line)
|
186
|
+
unless line =~ %r{#{LINE}}i # Case insensitive match for a valid line
|
187
|
+
raise "Invalid line in calendar string!"
|
188
|
+
end
|
189
|
+
|
190
|
+
name = $1.upcase # The case insensitive part is upcased for easier comparison...
|
191
|
+
paramslist = $2
|
192
|
+
value = $3
|
193
|
+
|
194
|
+
params = {}
|
195
|
+
|
196
|
+
# Collect the params, if any.
|
197
|
+
if paramslist.size > 1
|
198
|
+
|
199
|
+
# v3.0 and v2.1 params
|
200
|
+
paramslist.scan( %r{#{PARAM}}i ) do
|
201
|
+
|
202
|
+
# param names are case-insensitive, and multi-valued
|
203
|
+
pname = $1
|
204
|
+
pvals = $3
|
205
|
+
|
206
|
+
# v2.1 pvals have no '=' sign, figure out what kind of param it
|
207
|
+
# is (either its a known encoding, or we treat it as a 'type'
|
208
|
+
# param).
|
209
|
+
if $2 == ""
|
210
|
+
pvals = $1
|
211
|
+
case $1
|
212
|
+
when /quoted-printable/i
|
213
|
+
pname = 'encoding'
|
214
|
+
|
215
|
+
when /base64/i
|
216
|
+
pname = 'encoding'
|
217
|
+
|
218
|
+
else
|
219
|
+
pname = 'type'
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
unless params.key? pname
|
224
|
+
params[pname] = []
|
225
|
+
end
|
226
|
+
pvals.scan( %r{(#{PVALUE})} ) do
|
227
|
+
if $1.size > 0
|
228
|
+
params[pname] << $1
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
{:name => name, :params => params, :value => value}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|