bigtinker 0.97 → 0.98
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.
- data/code/01rwdcore/01rwdcore.rb +6 -6
- data/code/01rwdcore/02helptexthashbegin.rb +13 -11
- data/code/01rwdcore/jumplinkcommand.rb +14 -4
- data/code/01rwdcore/openhelpwindow.rb +7 -0
- data/code/01rwdcore/runhelpabout.rb +6 -1
- data/code/01rwdcore/runtab.rb +15 -0
- data/code/01rwdcore/selectiontab.rb +2 -0
- data/code/01rwdcore/setuphelpaboutoptions.rb +2 -0
- data/code/01rwdcore/setuptinkerdocuments.rb +1 -0
- data/code/01rwdcore/test_cases.rb +100 -51
- data/code/01rwdcore/test_harness.rb +8 -1
- data/code/01rwdcore/uploadreturns.rb +3 -0
- data/code/dd0viewphoto/dd0viewphoto.rb +2 -0
- data/code/superant.com.rwdcalendar/gh9calendar.rb +40 -0
- data/code/superant.com.rwdcalendar/helptexthashrwdschedule.rb +14 -0
- data/code/superant.com.rwdcalendar/openhelpwindowrwdschedule.rb +17 -0
- data/code/superant.com.rwdtinkerbackwindow/changelocale.rb +84 -0
- data/code/superant.com.rwdtinkerbackwindow/initiateapplets.rb +0 -1
- data/code/superant.com.rwdtinkerbackwindow/installgemapplet.rb +2 -0
- data/code/superant.com.rwdtinkerbackwindow/listgemzips.rb +2 -0
- data/code/superant.com.rwdtinkerbackwindow/listinstalledfiles.rb +3 -1
- data/code/superant.com.rwdtinkerbackwindow/listzips.rb +4 -0
- data/code/superant.com.rwdtinkerbackwindow/loadconfigurationrecord.rb +3 -1
- data/code/superant.com.rwdtinkerbackwindow/openhelpwindowtinkerwin2.rb +3 -1
- data/code/superant.com.rwdtinkerbackwindow/showlocaleoptions.rb +9 -0
- data/code/superant.com.rwdtinkerbackwindow/viewappletcontents.rb +1 -0
- data/code/superant.com.rwdtinkerbackwindow/viewlogfile.rb +8 -5
- data/code/superant.com.schedule/0uninstallapplet.rb +24 -0
- data/code/superant.com.schedule/archiveevent.rb +14 -0
- data/code/superant.com.schedule/archiveicsevent.rb +14 -0
- data/code/superant.com.schedule/cleareventscreendisplay.rb +19 -0
- data/code/superant.com.schedule/deleteeventrecord.rb +19 -0
- data/code/superant.com.schedule/deleteicseventrecord.rb +19 -0
- data/code/superant.com.schedule/deleterwdscheduleupdatefiles.rb +20 -0
- data/code/superant.com.schedule/downloadrwdschedulefiles.rb +37 -0
- data/code/superant.com.schedule/exporticseventrecord.rb +97 -0
- data/code/{superant.com.foldeditor → superant.com.schedule}/helptexthashload.rb +2 -2
- data/code/superant.com.schedule/listeventdates.rb +19 -0
- data/code/superant.com.schedule/listicseventdates.rb +19 -0
- data/code/{superant.com.foldeditor → superant.com.schedule}/loadconfigurationrecord.rb +4 -4
- data/code/superant.com.schedule/loadconfigurationvariables.rb +14 -0
- data/code/superant.com.schedule/loadeventrecord.rb +38 -0
- data/code/superant.com.schedule/loadicseventrecord.rb +30 -0
- data/code/superant.com.schedule/openhelpwindowrwdschedule.rb +43 -0
- data/code/superant.com.schedule/renameeventdata.rb +14 -0
- data/code/superant.com.schedule/renameicseventdata.rb +17 -0
- data/code/{superant.com.foldeditor/runrwdapplet.rb → superant.com.schedule/returntomain.rb} +3 -3
- data/code/superant.com.schedule/runrwdscheduleicsbackwindow.rb +10 -0
- data/code/superant.com.schedule/runrwdschedulemenu1.rb +34 -0
- data/code/superant.com.schedule/runrwdschedulesyncbackwindow.rb +10 -0
- data/code/{superant.com.foldeditor/rwdtinkerversion.rb → superant.com.schedule/rwdversion.rb} +2 -2
- data/code/{superant.com.foldeditor → superant.com.schedule}/saveconfigurationrecord.rb +5 -6
- data/code/superant.com.schedule/saveeventrecord.rb +25 -0
- data/code/superant.com.schedule/saveicseventrecord.rb +98 -0
- data/code/superant.com.schedule/syncrwdschedule.rb +30 -0
- data/code/superant.com.schedule/test_cases.rb +45 -0
- data/code/superant.com.schedule/uploadrwdschedulefiles.rb +30 -0
- data/code/superant.com.schedule/viewevent.rb +20 -0
- data/code/superant.com.schedule/viewicsevent.rb +20 -0
- data/code/superant.com.schedule/viewrwdschedulesconfiguration.rb +21 -0
- data/code/zz0applicationend/zz0end.rb +2 -1
- data/configuration/bigtinker.dist +5 -2
- data/configuration/rwdtinker.dist +3 -3
- data/configuration/rwdwschedule.dist +28 -0
- data/configuration/tinkerwin2variables.dist +1 -1
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/1appname.rwd +5 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/20downloadftp.rwd +45 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/67viewconfiguration.rwd +29 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/70rwddiagnostics.rwd +16 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulebackwindow/m01menubegin.rwd +18 -0
- data/gui/tinkerbackwindows/{superant.com.foldeditor/9end.rwd → superant.com.rwdschedulebackwindow/zvbackend.rwd} +6 -6
- data/gui/tinkerbackwindows/superant.com.rwdschedules/1appname.rwd +5 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedules/gg0viewevent.rwd +27 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedules/gl6editrecord.rwd +56 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedules/gl8contactutilities.rwd +25 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedules/hl9calendar.rwd +27 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedules/m01menubegin.rwd +18 -0
- data/gui/tinkerbackwindows/{superant.com.slideshow/9end.rwd → superant.com.rwdschedules/zvbackend.rwd} +6 -6
- data/gui/tinkerbackwindows/superant.com.rwdschedulesback/1appname.rwd +5 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulesback/30viewevent.rwd +27 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulesback/40editrecord.rwd +49 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulesback/60eventicsutilities.rwd +25 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulesback/m01menubegin.rwd +18 -0
- data/gui/tinkerbackwindows/superant.com.rwdschedulesback/zvbackend.rwd +6 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/70rwddiagnostics.rwd +1 -1
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/80localechanger.rwd +17 -0
- data/init.rb +7 -1
- data/installed/rwdscheduledate2.inf +6 -0
- data/installed/rwdwschedule.inf +20 -0
- data/lang/en/rwdcalendar/en.po +32 -0
- data/lang/en/rwdcore/en.po +31 -0
- data/lang/es/rwdcalendar/es.po +10 -0
- data/lang/es/rwdcore/es.po +27 -15
- data/lang/fr/rwdcalendar/fr.po +11 -0
- data/lang/fr/rwdcore/fr.po +4 -1
- data/lang/hi/rwdcalendar/hi.po +11 -0
- data/lang/hi/rwdcore/hi.po +39 -36
- data/lang/ja/rwdcalendar/ja.po +11 -0
- data/lang/ja/rwdcore/ja.po +3 -0
- data/lang/nl/rwdcalendar/nl.po +12 -0
- data/lang/nl/rwdcore/nl.po +4 -1
- data/lib/cal.rb +158 -0
- data/lib/icalendar.rb +18 -0
- data/lib/icalendar/base.rb +17 -0
- data/lib/icalendar/calendar.rb +44 -0
- data/lib/icalendar/calendar_parser.rb +237 -0
- data/lib/icalendar/component.rb +91 -0
- data/lib/icalendar/component/alarm.rb +16 -0
- data/lib/icalendar/component/event.rb +25 -0
- data/lib/icalendar/component/freebusy.rb +12 -0
- data/lib/icalendar/component/journal.rb +25 -0
- data/lib/icalendar/component/timezone.rb +26 -0
- data/lib/icalendar/component/todo.rb +21 -0
- data/lib/icalendar/helpers.rb +103 -0
- data/lib/icalendar/parameter.rb +25 -0
- data/lib/zip/ioextras.rb +43 -2
- data/lib/zip/stdrubyext.rb +5 -5
- data/lib/zip/tempfile_bugfixed.rb +2 -2
- data/lib/zip/zip.rb +618 -149
- data/lib/zip/zipfilesystem.rb +59 -8
- data/lib/zip/ziprequire.rb +32 -3
- data/rwd_files/HowTo_BigTinker.txt +15 -3
- data/rwd_files/HowTo_Schedule.txt +265 -0
- data/rwd_files/HowTo_Tinker.txt +14 -0
- data/rwd_files/Tinkerhelptexthash.txt +5 -2
- data/rwd_files/rwdapplications.html +23 -1
- data/rwd_files/rwdschedulehelpfiles.txt +19 -0
- data/rwd_files/schedules/20050120T09.ics +9 -0
- data/rwd_files/schedules/200505may02a.sch +4 -0
- data/rwd_files/schedules/Enterprise.ics +411 -0
- data/rwd_files/schedules/US Holidays.ics +575 -0
- data/rwd_files/schedules/archive/sample.archive +1 -0
- data/rwd_files/schedules/testics05.ics +11 -0
- data/rwdconfig.dist +4 -2
- data/{bigtinker.rb → rwdtinker.rb} +0 -0
- data/tests/{makedist-rwdwfoldeditor.rb → makedist-rwdwhypernote.rb} +4 -8
- data/tests/makedist.rb +1 -1
- data/updates/temp.rb +1 -0
- data/zips/rwdwfoldeditor-0.07.zip +0 -0
- data/zips/rwdwhypernote-0.16.zip +0 -0
- data/zips/rwdwschedule-1.07.zip +0 -0
- data/zips/tinkerbellw-0.04.zip +0 -0
- metadata +102 -54
- data/code/superant.com.foldeditor/0uninstallapplet.rb +0 -17
- data/code/superant.com.foldeditor/changehypernotename.rb +0 -21
- data/code/superant.com.foldeditor/chooselinkfile.rb +0 -6
- data/code/superant.com.foldeditor/choosenotefile.rb +0 -6
- data/code/superant.com.foldeditor/clearnotescreen.rb +0 -7
- data/code/superant.com.foldeditor/createnewnotehtml.rb +0 -31
- data/code/superant.com.foldeditor/hyperlinkcreatelinkfile.rb +0 -19
- data/code/superant.com.foldeditor/launchfoldeditorurl.rb +0 -19
- data/code/superant.com.foldeditor/listfoldeditorfiles.rb +0 -7
- data/code/superant.com.foldeditor/loadconfigurationvariables.rb +0 -14
- data/code/superant.com.foldeditor/loadfolddocument.rb +0 -18
- data/code/superant.com.foldeditor/loadnextnote.rb +0 -32
- data/code/superant.com.foldeditor/loadprevnote.rb +0 -32
- data/code/superant.com.foldeditor/loadrwdfoldeditlinkfile.rb +0 -19
- data/code/superant.com.foldeditor/openhelpwindowrwdhyernote.rb +0 -30
- data/code/superant.com.foldeditor/rwddisplayfoldlinks.rb +0 -41
- data/code/superant.com.foldeditor/savefoldlinkfile.rb +0 -20
- data/code/superant.com.foldeditor/savehtmlhypernoterecord.rb +0 -20
- data/configuration/rwdwfoldeditor.dist +0 -16
- data/gui/tinkerbackwindows/superant.com.foldeditor/10appletbegin.rwd +0 -4
- data/gui/tinkerbackwindows/superant.com.foldeditor/10aviewnote.rwd +0 -36
- data/gui/tinkerbackwindows/superant.com.foldeditor/15htmlview.rwd +0 -43
- data/gui/tinkerbackwindows/superant.com.foldeditor/56viewfold.rwd +0 -43
- data/gui/tinkerbackwindows/superant.com.foldeditor/67viewconfiguration.rwd +0 -27
- data/gui/tinkerbackwindows/superant.com.foldeditor/81jumplinkcommands.rwd +0 -17
- data/gui/tinkerbackwindows/superant.com.slideshow/10appletbegin.rwd +0 -4
- data/gui/tinkerbackwindows/superant.com.slideshow/11viewnamedata.rwd +0 -19
- data/gui/tinkerbackwindows/superant.com.slideshow/13listnamerecordfiles.rwd +0 -21
- data/gui/tinkerbackwindows/superant.com.slideshow/16editrecord.rwd +0 -39
- data/gui/tinkerbackwindows/superant.com.slideshow/17viewvcardrecord.rwd +0 -32
- data/gui/tinkerbackwindows/superant.com.slideshow/18contactutilities.rwd +0 -34
- data/gui/tinkerbackwindows/superant.com.slideshow/81jumplinkcommands.rwd +0 -17
- data/installed/rwdwfoldeditor.inf +0 -11
- data/rwd_files/HowTo_FoldEditor.txt +0 -131
- data/rwd_files/default.fld +0 -9
- data/rwd_files/rubylinks.fld +0 -6
- data/rwd_files/rwdfoldeditorhelpfiles.txt +0 -42
- data/rwd_files/rwdhypernote-0.13.fld +0 -202
- data/zips/rwdwfoldeditor-0.06.zip +0 -0
- data/zips/rwdwschedule-1.05.zip +0 -0
- data/zips/tinkerbellw-0.03.zip +0 -0
|
@@ -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
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module Icalendar
|
|
2
|
+
# The body of the iCalendar object consists of a sequence of calendar
|
|
3
|
+
# properties and one or more calendar components. The calendar
|
|
4
|
+
# properties are attributes that apply to the calendar as a whole. The
|
|
5
|
+
# calendar components are collections of properties that express a
|
|
6
|
+
# particular calendar semantic. For example, the calendar component can
|
|
7
|
+
# specify an event, a to-do, a journal entry, time zone information, or
|
|
8
|
+
# free/busy time information, or an alarm.
|
|
9
|
+
class Component < Icalendar::Base
|
|
10
|
+
|
|
11
|
+
attr_reader :name
|
|
12
|
+
attr_accessor :properties, :property_params
|
|
13
|
+
|
|
14
|
+
def initialize(name)
|
|
15
|
+
@name = name
|
|
16
|
+
@properties = {}
|
|
17
|
+
@property_params = {}
|
|
18
|
+
|
|
19
|
+
@@logger.info("New #{@name[1,@name.size].capitalize}...")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def print_string
|
|
23
|
+
s = ""
|
|
24
|
+
|
|
25
|
+
# Begin a new component
|
|
26
|
+
s << "BEGIN:#{@name.upcase}\r\n"
|
|
27
|
+
|
|
28
|
+
# Then print the properties, possible parameters and potentially
|
|
29
|
+
# multiple parameter values for each parameter.
|
|
30
|
+
@properties.each do |key,value|
|
|
31
|
+
# Property name
|
|
32
|
+
s << "#{key.upcase}"
|
|
33
|
+
|
|
34
|
+
# Possible parameters
|
|
35
|
+
if @property_params.has_key?(key)
|
|
36
|
+
params = @property_params[key]
|
|
37
|
+
params.each do |key,val|
|
|
38
|
+
s << ";#{key}"
|
|
39
|
+
unless val.respond_to?(:to_ary)
|
|
40
|
+
val = [ val ]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Possible parameter values
|
|
44
|
+
unless val.empty?
|
|
45
|
+
s << "="
|
|
46
|
+
sep = "" # First entry comes after = sign, but then we need commas
|
|
47
|
+
val.each do |pval|
|
|
48
|
+
s << sep << pval
|
|
49
|
+
sep = ","
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Property value
|
|
56
|
+
s << ":#{value}\r\n"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Any custom body of the derived component
|
|
60
|
+
yield(s)
|
|
61
|
+
|
|
62
|
+
# End of this component
|
|
63
|
+
s << "END:#{@name.upcase}\r\n"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Dynamically execute getters and setters for properties and
|
|
67
|
+
# property parameters. This lets us handle all the general text properties
|
|
68
|
+
# as well as custom app related properties in a natural way, but we don't
|
|
69
|
+
# have to write a million getters and setters for every possible thing we
|
|
70
|
+
# want to support.
|
|
71
|
+
def method_missing(method_id, *args)
|
|
72
|
+
method_name = method_id.id2name.upcase
|
|
73
|
+
|
|
74
|
+
if method_name =~ /\w+_PARAMS/ # Its a parameter request
|
|
75
|
+
hash = @property_params
|
|
76
|
+
val = args
|
|
77
|
+
else # Or its a property request
|
|
78
|
+
hash = @properties
|
|
79
|
+
val = args.first unless args.empty?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
if method_name =~ /(.*)(=)/ # Its a setter
|
|
83
|
+
hash[$1] = val
|
|
84
|
+
@@logger.debug("Setting #{$1} => #{val}")
|
|
85
|
+
else # Or its a getter
|
|
86
|
+
@@logger.debug("Getting #{method_name} => #{hash[method_name]}")
|
|
87
|
+
return hash[method_name]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Icalendar
|
|
2
|
+
# An Alarm calendar component is a grouping of component
|
|
3
|
+
# properties that is a reminder or alarm for an event or a
|
|
4
|
+
# to-do. For example, it may be used to define a reminder for a
|
|
5
|
+
# pending Event or an overdue Todo.
|
|
6
|
+
class Alarm < Component
|
|
7
|
+
def initialize()
|
|
8
|
+
super("VALARM")
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
print_string {}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Icalendar
|
|
2
|
+
# A Event calendar component is a grouping of component
|
|
3
|
+
# properties, and possibly including Alarm calendar components, that
|
|
4
|
+
# represents a scheduled amount of time on a calendar. For example, it
|
|
5
|
+
# can be an activity; such as a one-hour long, department meeting from
|
|
6
|
+
# 8:00 AM to 9:00 AM, tomorrow. Generally, an event will take up time
|
|
7
|
+
# on an individual calendar.
|
|
8
|
+
class Event < Component
|
|
9
|
+
include Dtstart
|
|
10
|
+
|
|
11
|
+
attr_accessor :alarms
|
|
12
|
+
|
|
13
|
+
def initialize()
|
|
14
|
+
super("VEVENT")
|
|
15
|
+
|
|
16
|
+
@alarms = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
print_string do |s|
|
|
21
|
+
@alarms.each { |alarm| s << alarm.to_s }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Icalendar
|
|
2
|
+
# A Freebusy calendar component is a grouping of
|
|
3
|
+
# component properties that represents either a request for, a reply to
|
|
4
|
+
# a request for free or busy time information or a published set of
|
|
5
|
+
# busy time information.
|
|
6
|
+
class Freebusy < Component
|
|
7
|
+
|
|
8
|
+
def initialize()
|
|
9
|
+
super("VFREEBUSY")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Icalendar
|
|
2
|
+
# A Journal calendar component is a grouping of
|
|
3
|
+
# component properties that represent one or more descriptive text
|
|
4
|
+
# notes associated with a particular calendar date. The "DTSTART"
|
|
5
|
+
# property is used to specify the calendar date that the journal entry
|
|
6
|
+
# is associated with. Generally, it will have a DATE value data type,
|
|
7
|
+
# but it can also be used to specify a DATE-TIME value data type.
|
|
8
|
+
# Examples of a journal entry include a daily record of a legislative
|
|
9
|
+
# body or a journal entry of individual telephone contacts for the day
|
|
10
|
+
# or an ordered list of accomplishments for the day. The Journal
|
|
11
|
+
# calendar component can also be used to associate a document with a
|
|
12
|
+
# calendar date.
|
|
13
|
+
class Journal < Component
|
|
14
|
+
|
|
15
|
+
def initialize()
|
|
16
|
+
super("VJOURNAL")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
print_string { }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|