bigtinker 0.97 → 0.98
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|