fairtilizer-vpim 0.695
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/CHANGES +510 -0
- data/COPYING +58 -0
- data/README +182 -0
- data/lib/vpim.rb +13 -0
- data/lib/vpim/address.rb +219 -0
- data/lib/vpim/agent/atomize.rb +104 -0
- data/lib/vpim/agent/base.rb +73 -0
- data/lib/vpim/agent/calendars.rb +173 -0
- data/lib/vpim/agent/handler.rb +26 -0
- data/lib/vpim/agent/ics.rb +161 -0
- data/lib/vpim/attachment.rb +102 -0
- data/lib/vpim/date.rb +222 -0
- data/lib/vpim/dirinfo.rb +277 -0
- data/lib/vpim/duration.rb +119 -0
- data/lib/vpim/enumerator.rb +32 -0
- data/lib/vpim/field.rb +614 -0
- data/lib/vpim/icalendar.rb +384 -0
- data/lib/vpim/maker/vcard.rb +16 -0
- data/lib/vpim/property/base.rb +193 -0
- data/lib/vpim/property/common.rb +315 -0
- data/lib/vpim/property/location.rb +38 -0
- data/lib/vpim/property/priority.rb +43 -0
- data/lib/vpim/property/recurrence.rb +69 -0
- data/lib/vpim/property/resources.rb +24 -0
- data/lib/vpim/repo.rb +261 -0
- data/lib/vpim/rfc2425.rb +367 -0
- data/lib/vpim/rrule.rb +591 -0
- data/lib/vpim/time.rb +40 -0
- data/lib/vpim/vcard.rb +1426 -0
- data/lib/vpim/version.rb +18 -0
- data/lib/vpim/vevent.rb +187 -0
- data/lib/vpim/view.rb +90 -0
- data/lib/vpim/vjournal.rb +58 -0
- data/lib/vpim/vpim.rb +65 -0
- data/lib/vpim/vtodo.rb +103 -0
- data/samples/README.mutt +93 -0
- data/samples/ab-query.rb +57 -0
- data/samples/agent.ru +10 -0
- data/samples/cmd-itip.rb +156 -0
- data/samples/ex_cpvcard.rb +55 -0
- data/samples/ex_get_vcard_photo.rb +22 -0
- data/samples/ex_mkv21vcard.rb +34 -0
- data/samples/ex_mkvcard.rb +64 -0
- data/samples/ex_mkyourown.rb +29 -0
- data/samples/ics-dump.rb +210 -0
- data/samples/ics-to-rss.rb +84 -0
- data/samples/mutt-aliases-to-vcf.rb +45 -0
- data/samples/osx-wrappers.rb +86 -0
- data/samples/reminder.rb +209 -0
- data/samples/rrule.rb +71 -0
- data/samples/tabbed-file-to-vcf.rb +390 -0
- data/samples/vcf-dump.rb +86 -0
- data/samples/vcf-lines.rb +61 -0
- data/samples/vcf-to-ics.rb +22 -0
- data/samples/vcf-to-mutt.rb +121 -0
- data/test/test_agent_atomize.rb +84 -0
- data/test/test_agent_calendars.rb +128 -0
- data/test/test_agent_ics.rb +96 -0
- data/test/test_all.rb +17 -0
- data/test/test_date.rb +120 -0
- data/test/test_dur.rb +41 -0
- data/test/test_field.rb +156 -0
- data/test/test_ical.rb +437 -0
- data/test/test_misc.rb +13 -0
- data/test/test_repo.rb +129 -0
- data/test/test_rrule.rb +1030 -0
- data/test/test_vcard.rb +973 -0
- data/test/test_view.rb +79 -0
- metadata +140 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2009 Sam Roberts
|
|
3
|
+
|
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
|
6
|
+
details.
|
|
7
|
+
=end
|
|
8
|
+
|
|
9
|
+
require "atom"
|
|
10
|
+
|
|
11
|
+
module Vpim
|
|
12
|
+
module Agent
|
|
13
|
+
|
|
14
|
+
module Atomize
|
|
15
|
+
MIME = "application/atom+xml"
|
|
16
|
+
|
|
17
|
+
# +ical+, an icalendar, or at least a Repo calendar's subset of an Icalendar
|
|
18
|
+
# +feeduri+, the atom xml should know the URI of where the feed is available from.
|
|
19
|
+
# +caluri+, optionally, the URI of the calendar its converted from.
|
|
20
|
+
#
|
|
21
|
+
# TODO - and the URI of an alternative/html representation of this feed?
|
|
22
|
+
def self.calendar(ical, feeduri, caluri = nil, calname = nil)
|
|
23
|
+
mime = MIME
|
|
24
|
+
|
|
25
|
+
feeduri = feeduri.to_str
|
|
26
|
+
caluri = caluri
|
|
27
|
+
calname = (calname or caluri or "Unknown").to_str
|
|
28
|
+
|
|
29
|
+
f = Atom::Feed.new
|
|
30
|
+
# Mandatory attributes:
|
|
31
|
+
# For ID, we should use http://.../ics/atom?....., or just the URL of the ics?
|
|
32
|
+
# I think it can be a full URI... or maybe a sha-1 of our full URI?
|
|
33
|
+
# or like gmail, no id for feed,
|
|
34
|
+
# <id>tag:gmail.google.com,2004:1295062805013769502</id>
|
|
35
|
+
#
|
|
36
|
+
f.id = feeduri
|
|
37
|
+
f.title = calname
|
|
38
|
+
f.updated = Time.now
|
|
39
|
+
f.authors << Atom::Person.new(:name => (caluri or calname))
|
|
40
|
+
f.generator = Atom::Generator.new do |g|
|
|
41
|
+
g.name = Vpim::PRODID
|
|
42
|
+
g.uri = "http://vpim.rubyforge.org"
|
|
43
|
+
g.version = Vpim::VERSION
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
f.links << Atom::Link.new do |l|
|
|
47
|
+
l.href = feeduri
|
|
48
|
+
l.type = mime
|
|
49
|
+
l.rel = :self
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if caluri
|
|
53
|
+
# This is maybe better described as :via, but with :alternate being
|
|
54
|
+
# an html view of this feed.
|
|
55
|
+
#
|
|
56
|
+
# TODO should I change the scheme to be webcal?
|
|
57
|
+
# TODO should I extend URI to support webcal?
|
|
58
|
+
f.links << Atom::Link.new do |l|
|
|
59
|
+
l.href = caluri
|
|
60
|
+
l.type = "text/calendar"
|
|
61
|
+
l.rel = :alternate
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# .icon = uri to the vAgent icon
|
|
66
|
+
entry_id = 0
|
|
67
|
+
ical.events do |ve|
|
|
68
|
+
# TODO - infinite?
|
|
69
|
+
ve.occurrences do |t|
|
|
70
|
+
f.entries << Atom::Entry.new do |e|
|
|
71
|
+
# iCalendar -> atom
|
|
72
|
+
# -----------------
|
|
73
|
+
# summary -> title
|
|
74
|
+
# description -> text/content
|
|
75
|
+
# uid -> id
|
|
76
|
+
# created -> published?
|
|
77
|
+
# organizer -> author?
|
|
78
|
+
# contact -> author?
|
|
79
|
+
# last-mod -> semantically, this is updated, but atom doesn't
|
|
80
|
+
# have the notion that an entry has a relationship to a time,
|
|
81
|
+
# other than the time the entry itself was published, and when
|
|
82
|
+
# the entry gets updated. We'll abuse updated for the event's time.
|
|
83
|
+
# categories -> where do "tags" go in atom, if anywhere?
|
|
84
|
+
# attachment -> into a link?
|
|
85
|
+
e.title = ve.summary if ve.summary
|
|
86
|
+
e.content = Atom::Content::Text.new(ve.description) if ve.description
|
|
87
|
+
e.updated = t
|
|
88
|
+
|
|
89
|
+
# Use "tag:", as defined by RFC4151, and use event UID if possible. Otherwise,
|
|
90
|
+
# construct something. Maybe I should mix something in to make it unique for
|
|
91
|
+
# each time a feed is generated for the calendar?
|
|
92
|
+
entry_id += 1
|
|
93
|
+
tag = ve.uid || "#{entry_id}@#{feeduri}"
|
|
94
|
+
e.id = "tag:vpim.rubyforge.org,2009:#{tag}"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
return f
|
|
99
|
+
end
|
|
100
|
+
end # Atomize
|
|
101
|
+
|
|
102
|
+
end # Agent
|
|
103
|
+
end # Vpim
|
|
104
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2009 Sam Roberts
|
|
3
|
+
|
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
|
6
|
+
details.
|
|
7
|
+
=end
|
|
8
|
+
|
|
9
|
+
require 'cgi'
|
|
10
|
+
|
|
11
|
+
require 'sinatra/base'
|
|
12
|
+
|
|
13
|
+
# TODO Pasting of webcal links, conversion to webcal links?
|
|
14
|
+
|
|
15
|
+
module Vpim
|
|
16
|
+
module Agent
|
|
17
|
+
|
|
18
|
+
class Base < Sinatra::Base
|
|
19
|
+
# Ensure that this happens...
|
|
20
|
+
set :haml, :format=>:html4 # Appears to do nothing, but maybe it will some day...
|
|
21
|
+
|
|
22
|
+
def css(template)
|
|
23
|
+
render :css, template, {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def render_css(template, data, options) # :nodoc:
|
|
27
|
+
data
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Complete path, as requested by the client. Take care about CGI path rewriting.
|
|
31
|
+
def request_path
|
|
32
|
+
# Using .to_s because rack/request.rb does, though I think the Rack
|
|
33
|
+
# spec requires these to be strings already.
|
|
34
|
+
begin
|
|
35
|
+
URI.parse(env["SCRIPT_URI"].to_s).path
|
|
36
|
+
rescue
|
|
37
|
+
env["SCRIPT_NAME"].to_s + env["PATH_INFO"].to_s
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Complete path, as requested by the client, without the env's PATH_INFO.
|
|
42
|
+
# This is the path to whatever is "handling" the request.
|
|
43
|
+
#
|
|
44
|
+
# Recent discussions on how PATH_INFO must be decoded leads me to think
|
|
45
|
+
# this might not work if the path had any URL encoded characters in it.
|
|
46
|
+
def script_path
|
|
47
|
+
request_path.sub(/#{env["PATH_INFO"]}$/, "")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# URL-ready form of the host and port, where the port isn't specified if
|
|
51
|
+
# it is the default for the URL scheme.
|
|
52
|
+
def host_port
|
|
53
|
+
r = request
|
|
54
|
+
host_port = r.host
|
|
55
|
+
|
|
56
|
+
if r.scheme == "https" && r.port != 443 ||
|
|
57
|
+
r.scheme == "http" && r.port != 80
|
|
58
|
+
host_port << ":#{r.port}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
host_port
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# URL to the script
|
|
65
|
+
def script_url
|
|
66
|
+
request.scheme + "://" + host_port + script_path
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end # Base
|
|
70
|
+
|
|
71
|
+
end # Agent
|
|
72
|
+
end # Vpim
|
|
73
|
+
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2008 Sam Roberts
|
|
3
|
+
|
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
|
6
|
+
details.
|
|
7
|
+
=end
|
|
8
|
+
|
|
9
|
+
require "cgi"
|
|
10
|
+
require "uri"
|
|
11
|
+
|
|
12
|
+
require "vpim/repo"
|
|
13
|
+
require "vpim/agent/atomize"
|
|
14
|
+
|
|
15
|
+
module Vpim
|
|
16
|
+
module Agent
|
|
17
|
+
# On failure, raise this with an error message. text/plain for now,
|
|
18
|
+
# text/html later. Will convert to a 404 and a message.
|
|
19
|
+
class NotFound < Exception
|
|
20
|
+
def initialize(name, path)
|
|
21
|
+
super %{Resource "#{name}" under "#{path.prefix}" was not found!}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Path
|
|
26
|
+
def self.split_path(path)
|
|
27
|
+
begin
|
|
28
|
+
path = path.to_ary
|
|
29
|
+
rescue NameError
|
|
30
|
+
path = path.split("/")
|
|
31
|
+
end
|
|
32
|
+
path.map{|w| CGI.unescape(w)}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# URI is the uri being queried, base is where this path is mounted under?
|
|
36
|
+
def initialize(uri, base = "")
|
|
37
|
+
@uri = URI.parse(uri.to_s)
|
|
38
|
+
#pp [uri, base, @uri]
|
|
39
|
+
if @uri.path.size == 0
|
|
40
|
+
@uri.path = "/"
|
|
41
|
+
end
|
|
42
|
+
@path = Path.split_path(@uri.path)
|
|
43
|
+
@base = base.to_str
|
|
44
|
+
@mark = 0
|
|
45
|
+
|
|
46
|
+
@base.split.size.times{ shift }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def uri
|
|
50
|
+
@uri.to_s
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_path
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# TODO - call this #next
|
|
58
|
+
def shift
|
|
59
|
+
if @path[@mark]
|
|
60
|
+
@path[@mark += 1]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def append(name, scheme = nil)
|
|
65
|
+
uri = @uri.dup
|
|
66
|
+
uri.path += "/" + CGI.escape(name)
|
|
67
|
+
if scheme
|
|
68
|
+
uri.scheme = scheme
|
|
69
|
+
end
|
|
70
|
+
uri
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def prefix(len = nil)
|
|
74
|
+
len ||= @mark
|
|
75
|
+
@path[0, len].map{|p| CGI.escape(p)}.join("/") + "/"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
module Form
|
|
81
|
+
ATOM = Atomize::MIME
|
|
82
|
+
HTML = "text/html"
|
|
83
|
+
ICS = "text/calendar"
|
|
84
|
+
PLAIN = "text/plain"
|
|
85
|
+
VCF = "text/directory"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Return an HTML description of a list of resources accessible under this
|
|
89
|
+
# path.
|
|
90
|
+
class ResourceList
|
|
91
|
+
def initialize(description, items)
|
|
92
|
+
@description = description
|
|
93
|
+
@items = items
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def get(path)
|
|
97
|
+
return <<__, Form::HTML
|
|
98
|
+
<html><body>
|
|
99
|
+
#{@description}
|
|
100
|
+
<ul>
|
|
101
|
+
#{
|
|
102
|
+
@items.map do |name,description,scheme|
|
|
103
|
+
"<li><a href=\"#{path.append(name,scheme)}\">#{description || name}</a></li>\n"
|
|
104
|
+
end
|
|
105
|
+
}
|
|
106
|
+
</ul>
|
|
107
|
+
</body></html>
|
|
108
|
+
__
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Return calendar information based on RESTful (lovein' the jargon...)
|
|
113
|
+
# paths. Input is a Vpim::Repo.
|
|
114
|
+
#
|
|
115
|
+
# .../coding/month/atom
|
|
116
|
+
# .../coding/events/month/ics <- next month?
|
|
117
|
+
# .../coding/events/month/2008-04/ics <- a specified month?
|
|
118
|
+
# .../coding/week/atom
|
|
119
|
+
# .../year/atom
|
|
120
|
+
class Calendars
|
|
121
|
+
def initialize(repo)
|
|
122
|
+
@repo = repo
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
class Calendar
|
|
126
|
+
def initialize(cal)
|
|
127
|
+
@cal = cal
|
|
128
|
+
@list = ResourceList.new(
|
|
129
|
+
"Calendar #{@cal.name.inspect}:",
|
|
130
|
+
[
|
|
131
|
+
["calendar", "download"],
|
|
132
|
+
["calendar", "subscription", "webcal"],
|
|
133
|
+
["atom", "syndication"],
|
|
134
|
+
]
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def get(path)
|
|
139
|
+
form = path.shift
|
|
140
|
+
|
|
141
|
+
# TODO should redirect to an object, so that extra paths can be
|
|
142
|
+
# handled more gracefully.
|
|
143
|
+
case form
|
|
144
|
+
when nil
|
|
145
|
+
return @list.get(path)
|
|
146
|
+
when "calendar"
|
|
147
|
+
return @cal.encode, Form::ICS
|
|
148
|
+
when "atom"
|
|
149
|
+
return Atomize.calendar(@cal, path.uri, nil, @cal.name).to_xml, Form::ATOM
|
|
150
|
+
else
|
|
151
|
+
raise NotFound.new(form, path)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Get object at this path. Return value is a tuple of data and mime content type.
|
|
157
|
+
def get(path)
|
|
158
|
+
case name = path.to_path.shift
|
|
159
|
+
when nil
|
|
160
|
+
list = ResourceList.new("Calendars:", @repo.map{|c| c.name})
|
|
161
|
+
return list.get(path)
|
|
162
|
+
else
|
|
163
|
+
if cal = @repo.find{|c| c.name == name}
|
|
164
|
+
return Calendar.new(cal).get(path)
|
|
165
|
+
else
|
|
166
|
+
raise NotFound.new(name, path)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2009 Sam Roberts
|
|
3
|
+
|
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
|
6
|
+
details.
|
|
7
|
+
=end
|
|
8
|
+
|
|
9
|
+
require 'sinatra/base'
|
|
10
|
+
|
|
11
|
+
# Auto-choose our handler based on the environment.
|
|
12
|
+
# TODO Code should be in Sinatra, and should handle Thin, Mongrel, etc.
|
|
13
|
+
Sinatra::Base.configure do
|
|
14
|
+
server = Sinatra::Base.server
|
|
15
|
+
Sinatra::Base.set :server, Proc.new {
|
|
16
|
+
if ENV.include?("PHP_FCGI_CHILDREN")
|
|
17
|
+
break "fastcgi" # Must NOT be the correct class name!
|
|
18
|
+
elsif ENV.include?("REQUEST_METHOD")
|
|
19
|
+
break "cgi" # Must NOT be the correct class name!
|
|
20
|
+
else
|
|
21
|
+
# Fall back on whatever it was going to be.
|
|
22
|
+
server
|
|
23
|
+
end
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
Copyright (C) 2009 Sam Roberts
|
|
3
|
+
|
|
4
|
+
This library is free software; you can redistribute it and/or modify it
|
|
5
|
+
under the same terms as the ruby language itself, see the file COPYING for
|
|
6
|
+
details.
|
|
7
|
+
=end
|
|
8
|
+
|
|
9
|
+
require 'cgi'
|
|
10
|
+
|
|
11
|
+
require 'vpim/agent/base'
|
|
12
|
+
require 'vpim/agent/atomize'
|
|
13
|
+
require 'vpim/repo'
|
|
14
|
+
require 'vpim/view'
|
|
15
|
+
|
|
16
|
+
require 'sinatra/base'
|
|
17
|
+
|
|
18
|
+
module Vpim
|
|
19
|
+
module Agent
|
|
20
|
+
|
|
21
|
+
class Ics < Base
|
|
22
|
+
use_in_file_templates!
|
|
23
|
+
|
|
24
|
+
def atomize(caluri, feeduri)
|
|
25
|
+
repo = Vpim::Repo::Uri.new(caluri)
|
|
26
|
+
cal = repo.find{true}
|
|
27
|
+
cal = View.week(cal)
|
|
28
|
+
feed = Agent::Atomize.calendar(cal, feeduri, caluri, cal.name)
|
|
29
|
+
return feed.to_xml, Agent::Atomize::MIME
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
## Route handlers:
|
|
33
|
+
def get_base(from)
|
|
34
|
+
@url_base = script_url # agent mount point
|
|
35
|
+
@url_ics = from # ics from here
|
|
36
|
+
@url_atom = nil # atom feed from here, if ics is accessible
|
|
37
|
+
@url_error= nil # error message, if is is not accessible
|
|
38
|
+
|
|
39
|
+
if not from.empty?
|
|
40
|
+
begin
|
|
41
|
+
atomize(from, "http://example.com")
|
|
42
|
+
@url_atom = @url_base + "/atom" + "?" + from
|
|
43
|
+
rescue
|
|
44
|
+
@url_error = CGI.escapeHTML($!.to_s)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
haml :"vpim/agent/ics/view"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# When we support other forms..
|
|
52
|
+
#get '/ics/:form' do
|
|
53
|
+
# form = params[:form]
|
|
54
|
+
def get_atom(caluri)
|
|
55
|
+
if caluri.empty?
|
|
56
|
+
redirect script_url
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
feeduri = script_url + "/atom?" + caluri
|
|
60
|
+
|
|
61
|
+
begin
|
|
62
|
+
xml, xmltype = atomize(caluri, feeduri)
|
|
63
|
+
content_type xmltype
|
|
64
|
+
body xml
|
|
65
|
+
rescue
|
|
66
|
+
redirect script_url + "?" + caluri
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def get_style
|
|
71
|
+
content_type 'text/css'
|
|
72
|
+
css :"vpim/agent/ics/style"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
## Sinatra routing:
|
|
76
|
+
get '/?' do
|
|
77
|
+
get_base(env['QUERY_STRING'])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
post "/?" do
|
|
81
|
+
redirect script_url + "?" + (params[:url] || "")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
get "/atom" do
|
|
85
|
+
get_atom(env['QUERY_STRING'])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
get '/style.css' do
|
|
89
|
+
get_style
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end # Ics
|
|
93
|
+
|
|
94
|
+
end # Agent
|
|
95
|
+
end # Vpim
|
|
96
|
+
|
|
97
|
+
__END__
|
|
98
|
+
@@vpim/agent/ics/style
|
|
99
|
+
body {
|
|
100
|
+
background-color: gray;
|
|
101
|
+
}
|
|
102
|
+
h1 {
|
|
103
|
+
border-bottom: 3px solid #8B0000;
|
|
104
|
+
font-size: large;
|
|
105
|
+
}
|
|
106
|
+
form {
|
|
107
|
+
margin-left: 10%;
|
|
108
|
+
}
|
|
109
|
+
input.text {
|
|
110
|
+
width: 80%;
|
|
111
|
+
}
|
|
112
|
+
a {
|
|
113
|
+
color: black;
|
|
114
|
+
}
|
|
115
|
+
a:hover {
|
|
116
|
+
color: #8B0000;
|
|
117
|
+
}
|
|
118
|
+
tt {
|
|
119
|
+
margin-left: 10%;
|
|
120
|
+
}
|
|
121
|
+
.footer {
|
|
122
|
+
border-top: 3px solid #8B0000;
|
|
123
|
+
}
|
|
124
|
+
@@vpim/agent/ics/view
|
|
125
|
+
!!! strict
|
|
126
|
+
%html
|
|
127
|
+
%head
|
|
128
|
+
%title Subscribe to calendar feeds as atom feeds
|
|
129
|
+
%link{:href => script_url + "/style.css", :media => "screen", :type => "text/css"}
|
|
130
|
+
%meta{:"http-equiv" => "Content-Type", :content => "text/html;charset=utf-8"}
|
|
131
|
+
%body
|
|
132
|
+
%h1 Subscribe to calendar feeds as atom feeds
|
|
133
|
+
%p
|
|
134
|
+
Calendar feeds are great, but when you want a reminder of what's coming up
|
|
135
|
+
in the next week, you might want those events as an atom feed.
|
|
136
|
+
%p
|
|
137
|
+
Paste the URL of the calendar below, submit it, and subscribe.
|
|
138
|
+
%form{:method => 'POST', :action => script_url}
|
|
139
|
+
%p
|
|
140
|
+
%input.text{:type => 'text', :name => 'url', :value => @url_ics}
|
|
141
|
+
%input{:type => 'submit', :value => 'Submit'}
|
|
142
|
+
- if @url_atom
|
|
143
|
+
%p
|
|
144
|
+
Subscribe to
|
|
145
|
+
%a{:href => @url_ics}= @url_ics
|
|
146
|
+
as:
|
|
147
|
+
%ul.feed
|
|
148
|
+
%li
|
|
149
|
+
%a{:href => @url_atom}= @url_atom
|
|
150
|
+
(atom feed)
|
|
151
|
+
- if @url_error
|
|
152
|
+
%p
|
|
153
|
+
Sorry, trying to access
|
|
154
|
+
%tt=@url_ics
|
|
155
|
+
resulted in:
|
|
156
|
+
%p
|
|
157
|
+
%tt= @url_error
|
|
158
|
+
.footer
|
|
159
|
+
:textile
|
|
160
|
+
Brought from the "Octet Cloud":http://octetcloud.com/ using "vPim":http://vpim.rubyforge.org/, by cloud monkey "Sam Roberts":mailto:vieuxtech@gmail.com.
|
|
161
|
+
|