mumboe-vpim 0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGES +510 -0
  2. data/COPYING +58 -0
  3. data/README +185 -0
  4. data/lib/vpim/address.rb +219 -0
  5. data/lib/vpim/agent/atomize.rb +104 -0
  6. data/lib/vpim/agent/base.rb +73 -0
  7. data/lib/vpim/agent/calendars.rb +173 -0
  8. data/lib/vpim/agent/handler.rb +26 -0
  9. data/lib/vpim/agent/ics.rb +161 -0
  10. data/lib/vpim/attachment.rb +102 -0
  11. data/lib/vpim/date.rb +222 -0
  12. data/lib/vpim/dirinfo.rb +277 -0
  13. data/lib/vpim/duration.rb +119 -0
  14. data/lib/vpim/enumerator.rb +32 -0
  15. data/lib/vpim/field.rb +614 -0
  16. data/lib/vpim/icalendar.rb +384 -0
  17. data/lib/vpim/maker/vcard.rb +16 -0
  18. data/lib/vpim/property/base.rb +193 -0
  19. data/lib/vpim/property/common.rb +315 -0
  20. data/lib/vpim/property/location.rb +38 -0
  21. data/lib/vpim/property/priority.rb +43 -0
  22. data/lib/vpim/property/recurrence.rb +69 -0
  23. data/lib/vpim/property/resources.rb +24 -0
  24. data/lib/vpim/repo.rb +261 -0
  25. data/lib/vpim/rfc2425.rb +367 -0
  26. data/lib/vpim/rrule.rb +591 -0
  27. data/lib/vpim/time.rb +40 -0
  28. data/lib/vpim/vcard.rb +1456 -0
  29. data/lib/vpim/version.rb +18 -0
  30. data/lib/vpim/vevent.rb +187 -0
  31. data/lib/vpim/view.rb +90 -0
  32. data/lib/vpim/vjournal.rb +58 -0
  33. data/lib/vpim/vpim.rb +65 -0
  34. data/lib/vpim/vtodo.rb +103 -0
  35. data/lib/vpim.rb +13 -0
  36. data/samples/README.mutt +93 -0
  37. data/samples/ab-query.rb +57 -0
  38. data/samples/agent.ru +10 -0
  39. data/samples/cmd-itip.rb +156 -0
  40. data/samples/ex_cpvcard.rb +55 -0
  41. data/samples/ex_get_vcard_photo.rb +22 -0
  42. data/samples/ex_mkv21vcard.rb +34 -0
  43. data/samples/ex_mkvcard.rb +64 -0
  44. data/samples/ex_mkyourown.rb +29 -0
  45. data/samples/ics-dump.rb +210 -0
  46. data/samples/ics-to-rss.rb +84 -0
  47. data/samples/mutt-aliases-to-vcf.rb +45 -0
  48. data/samples/osx-wrappers.rb +86 -0
  49. data/samples/reminder.rb +209 -0
  50. data/samples/rrule.rb +71 -0
  51. data/samples/tabbed-file-to-vcf.rb +390 -0
  52. data/samples/vcf-dump.rb +86 -0
  53. data/samples/vcf-lines.rb +61 -0
  54. data/samples/vcf-to-ics.rb +22 -0
  55. data/samples/vcf-to-mutt.rb +121 -0
  56. data/test/test_agent_atomize.rb +84 -0
  57. data/test/test_agent_calendars.rb +128 -0
  58. data/test/test_agent_ics.rb +96 -0
  59. data/test/test_all.rb +17 -0
  60. data/test/test_date.rb +120 -0
  61. data/test/test_dur.rb +41 -0
  62. data/test/test_field.rb +156 -0
  63. data/test/test_ical.rb +437 -0
  64. data/test/test_misc.rb +13 -0
  65. data/test/test_repo.rb +129 -0
  66. data/test/test_rrule.rb +1030 -0
  67. data/test/test_vcard.rb +973 -0
  68. data/test/test_view.rb +79 -0
  69. metadata +140 -0
data/README ADDED
@@ -0,0 +1,185 @@
1
+ Author:: Sam Roberts <vieuxtech@gmail.com>
2
+ Copyright:: Copyright (C) 2008 Sam Roberts
3
+ License:: May be distributed under the same terms as Ruby
4
+ Homepage:: http://vpim.rubyforge.org
5
+ Download:: http://rubyforge.org/projects/vpim
6
+ Install:: sudo gem install vpim
7
+
8
+ vPim provides calendaring, scheduling, and contact support for Ruby through the
9
+ standard iCalendar and vCard data formats for "personal information" exchange.
10
+
11
+ = Mumboe
12
+ This code has been modified by Mumboe, Inc. for purposes of Ruby 1.9 compatibility and adding some useful methods for vCard 3.0 specs
13
+
14
+ = Thanks
15
+
16
+ - http://ZipDX.com: for sponsoring development of FREQ=weekly and BYSETPOS in
17
+ recurrence rules.
18
+ - http://RubyForge.org: for their generous hosting of this project.
19
+
20
+ = Installation
21
+
22
+ There is a vPim package installable using ruby-gems:
23
+
24
+ # sudo gem install vpim (may require root privilege)
25
+
26
+ It is also installable in the standard way. Untar the package, and do:
27
+
28
+ $ ruby setup.rb --help
29
+
30
+ or do:
31
+
32
+ $ ruby setup.rb config
33
+ $ ruby setup.rb setup
34
+ # ruby setup.rb install (may require root privilege)
35
+
36
+ = Overview
37
+
38
+ vCard (RFC 2426) is a format for personal information, see Vpim::Vcard and
39
+ Vpim::Maker::Vcard.
40
+
41
+ iCalendar (RFC 2445) is a format for calendar related information, see
42
+ Vpim::Icalendar.
43
+
44
+ vCard and iCalendar support is built on top of an implementation of the MIME
45
+ Content-Type for Directory Information (RFC 2425). The basic RFC 2425 format is
46
+ implemented by Vpim::DirectoryInfo and Vpim::DirectoryInfo::Field.
47
+
48
+ The libary is quite useful, but improvements are ongoing. If you find
49
+ something missing or have suggestions, please contact me. I can't promise
50
+ instantaneous turnaround, but I might be able to suggest another approach, and
51
+ features requested by users of vPim go to the top of the todo list. If you need
52
+ a feature for a commercial project, consider sponsoring development.
53
+
54
+ = Examples
55
+
56
+ Here's an example to give a sense for how iCalendars are encoded and decoded:
57
+
58
+ require 'vpim/icalendar'
59
+
60
+ cal = Vpim::Icalendar.create2
61
+
62
+ cal.add_event do |e|
63
+ e.dtstart Date.new(2005, 04, 28)
64
+ e.dtend Date.new(2005, 04, 29)
65
+ e.summary "Monthly meet-the-CEO day"
66
+ e.description <<'---'
67
+ Unlike last one, this meeting will change your life because
68
+ we are going to discuss your likely demotion if your work isn't
69
+ done soon.
70
+ ---
71
+ e.categories [ 'APPOINTMENT' ]
72
+ e.categories do |c| c.push 'EDUCATION' end
73
+ e.url 'http://www.example.com'
74
+ e.sequence 0
75
+ e.access_class "PRIVATE"
76
+ e.transparency 'OPAQUE'
77
+
78
+ now = Time.now
79
+ e.created now
80
+ e.lastmod now
81
+
82
+
83
+ e.organizer do |o|
84
+ o.cn = "Example Organizer, Mr."
85
+ o.uri = "mailto:organizer@example.com"
86
+ end
87
+
88
+ attendee = Vpim::Icalendar::Address.create("mailto:attendee@example.com")
89
+ attendee.rsvp = true
90
+ e.add_attendee attendee
91
+ end
92
+
93
+ icsfile = cal.encode
94
+
95
+ puts '--- Encode:'
96
+
97
+ puts icsfile
98
+
99
+ puts '--- Decode:'
100
+
101
+ cal = Vpim::Icalendar.decode(icsfile).first
102
+
103
+ cal.components do |e|
104
+ puts e.summary
105
+ puts e.description
106
+ puts e.dtstart.to_s
107
+ puts e.dtend.to_s
108
+ end
109
+
110
+ This produces:
111
+
112
+ --- Encode:
113
+ BEGIN:VCALENDAR
114
+ VERSION:2.0
115
+ PRODID:-//Ensemble Independent//vPim 0.357//EN
116
+ CALSCALE:Gregorian
117
+ BEGIN:VEVENT
118
+ DTSTART;VALUE=DATE:20050428
119
+ DTEND;VALUE=DATE:20050429
120
+ SUMMARY:Monthly meet-the-CEO day
121
+ DESCRIPTION:Unlike last one, this meeting will change your life because\nwe
122
+ are going to discuss your likely demotion if your work isn't\ndone soon.\n
123
+ CATEGORIES:APPOINTMENT,EDUCATION
124
+ URL:http://www.example.com
125
+ SEQUENCE:0
126
+ CLASS:PRIVATE
127
+ CREATED:20060402T231755
128
+ LAST-MODIFIED:20060402T231755
129
+ ORGANIZER;CN="Example Organizer, Mr.":mailto:organizer@example.com
130
+ ATTENDEE;RSVP=true:mailto:attendee@example.com
131
+ END:VEVENT
132
+ END:VCALENDAR
133
+ --- Decode:
134
+ Monthly meet-the-CEO day
135
+ Unlike last one, this meeting will change your life because
136
+ we are going to discuss your likely demotion if your work isn't
137
+ done soon.
138
+ Thu Apr 28 00:00:00 UTC 2005
139
+ Fri Apr 29 00:00:00 UTC 2005
140
+
141
+
142
+ More examples of using vPim are provided in samples/.
143
+
144
+ vCard examples are:
145
+ - link:ex_mkvcard.txt: example of creating a vCard
146
+ - link:ex_cpvcard.txt: example of copying and them modifying a vCard
147
+ - link:ex_mkv21vcard.txt: example of creating version 2.1 vCard
148
+ - link:mutt-aliases-to-vcf.txt: convert a mutt aliases file to vCards
149
+ - link:ex_get_vcard_photo.txt: pull photo data from a vCard
150
+ - link:ab-query.txt: query the OS X Address Book to find vCards
151
+ - link:vcf-to-mutt.txt: query vCards for matches, output in formats useful
152
+ with Mutt (see link:README.mutt for details)
153
+ - link:tabbed-file-to-vcf.txt: convert a tab-delimited file to vCards, a
154
+ (small but) complete application contributed by Dane G. Avilla, thanks!
155
+ - link:vcf-to-ics.txt: example of how to create calendars of birthdays from vCards
156
+ - link:vcf-dump.txt: utility for dumping contents of .vcf files
157
+
158
+ iCalendar examples are:
159
+ - link:ics-to-rss.txt: prints todos as RSS, or starts a WEBrick servlet
160
+ that publishes todos as a RSS feed. Thanks to Dave Thomas for this idea,
161
+ from http://pragprog.com/pragdave/Tech/Blog/ToDos.rdoc.
162
+ - link:cmd-itip.txt: prints emailed iCalendar invitations in human-readable
163
+ form, and see link:README.mutt for instruction on mutt integration. I get
164
+ a lot of meeting invitations from Lotus Notes/Domino users at work, and
165
+ this is pretty useful in figuring out where and when I am supposed to be.
166
+ - link:reminder.txt: prints upcoming events and todos, by default from
167
+ Apple's iCal calendars
168
+ - link:rrule.txt: utility for printing recurrence rules
169
+ - link:ics-dump.txt: utility for dumping contents of .ics files
170
+
171
+ = Project Information
172
+
173
+ vPim can be downloaded from the Ruby Forge project page:
174
+
175
+ - http://rubyforge.org/projects/vpim
176
+
177
+ or installed as a gem:
178
+
179
+ - sudo gem install vpim
180
+
181
+ For notifications about new releases, or to ask questions about vPim, please
182
+ subscribe to "vpim-talk":
183
+
184
+ - http://rubyforge.org/mailman/listinfo/vpim-talk
185
+
@@ -0,0 +1,219 @@
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
+ =begin
10
+
11
+ Notes on a CAL-ADDRESS
12
+
13
+ When used with ATTENDEE, the parameters are:
14
+ CN
15
+ CUTYPE
16
+ DELEGATED-FROM
17
+ DELEGATED-TO
18
+ DIR
19
+ LANGUAGE
20
+ MEMBER
21
+ PARTSTAT
22
+ ROLE
23
+ RSVP
24
+ SENT-BY
25
+
26
+ When used with ORGANIZER, the parameters are:
27
+ CN
28
+ DIR
29
+ LANGUAGE
30
+ SENT-BY
31
+
32
+
33
+ What I've seen in Notes invitations, and iCal responses:
34
+ ROLE
35
+ PARTSTAT
36
+ RSVP
37
+ CN
38
+
39
+ Support these last 4, for now.
40
+
41
+ =end
42
+
43
+ module Vpim
44
+ class Icalendar
45
+ # Used to represent calendar fields containing CAL-ADDRESS values.
46
+ # The organizer or the attendees of a calendar event are examples of such
47
+ # a field.
48
+ #
49
+ # Example:
50
+ #
51
+ # ORGANIZER;CN="A. Person":mailto:a_person@example.com
52
+ #
53
+ # ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION
54
+ # ;CN="Sam Roberts";RSVP=TRUE:mailto:SRoberts@example.com
55
+ #
56
+ class Address
57
+
58
+ # Create a copy of Address. If the original Address was frozen, this one
59
+ # won't be.
60
+ def copy
61
+ #Marshal.load(Marshal.dump(self))
62
+ self.dup.dirty
63
+ end
64
+
65
+ def dirty #:nodoc:
66
+ @field = nil
67
+ self
68
+ end
69
+
70
+ # Addresses in a CAL-ADDRESS are represented as a URI, usually a mailto URI.
71
+ attr_accessor :uri
72
+ # The common or displayable name associated with the calendar address, or
73
+ # nil if there is none.
74
+ attr_accessor :cn
75
+ # The participation role for the calendar user specified by the address.
76
+ #
77
+ # The standard roles are:
78
+ # - CHAIR Indicates chair of the calendar entity
79
+ # - REQ-PARTICIPANT Indicates a participant whose participation is required
80
+ # - OPT-PARTICIPANT Indicates a participant whose participation is optional
81
+ # - NON-PARTICIPANT Indicates a participant who is copied for information purposes only
82
+ #
83
+ # The default role is REQ-PARTICIPANT, returned if no ROLE parameter was
84
+ # specified.
85
+ attr_accessor :role
86
+ # The participation status for the calendar user specified by the
87
+ # property PARTSTAT, a String.
88
+ #
89
+ # These are the participation statuses for an Event:
90
+ # - NEEDS-ACTION Event needs action
91
+ # - ACCEPTED Event accepted
92
+ # - DECLINED Event declined
93
+ # - TENTATIVE Event tentatively accepted
94
+ # - DELEGATED Event delegated
95
+ #
96
+ # Default is NEEDS-ACTION.
97
+ #
98
+ # FIXME - make the default depend on the component type.
99
+ attr_accessor :partstat
100
+ # The value of the RSVP field, either +true+ or +false+. It is used to
101
+ # specify whether there is an expectation of a reply from the calendar
102
+ # user specified by the property value.
103
+ attr_accessor :rsvp
104
+
105
+ def initialize(field=nil) #:nodoc:
106
+ @field = field
107
+ @uri = ''
108
+ @cn = ''
109
+ @role = "REQ-PARTICIPANT"
110
+ @partstat = "NEEDS-ACTION"
111
+ @rsvp = false
112
+ end
113
+
114
+ # Create a new Address. It will encode as a +name+ property.
115
+ def self.create(uri='')
116
+ adr = new
117
+ adr.uri = uri.to_str
118
+ adr
119
+ end
120
+
121
+ def self.decode(field)
122
+ adr = new(field)
123
+ adr.uri = field.value
124
+
125
+ cn = field.param('CN')
126
+
127
+ if cn
128
+ adr.cn = cn.first
129
+ end
130
+
131
+ role = field.param('ROLE')
132
+
133
+ if role
134
+ adr.role = role.first.strip.upcase
135
+ end
136
+
137
+ partstat = field.param('PARTSTAT')
138
+
139
+ if partstat
140
+ adr.partstat = partstat.first.strip.upcase
141
+ end
142
+
143
+ rsvp = field.param('RSVP')
144
+
145
+ if rsvp
146
+ adr.rsvp = case rsvp.first
147
+ when /TRUE/i then true
148
+ when /FALSE/i then false
149
+ else raise InvalidEncodingError, "RSVP param value not TRUE/FALSE: #{rsvp}"
150
+ end
151
+ end
152
+
153
+ adr.freeze
154
+ end
155
+
156
+ # Return a representation of this Address as a DirectoryInfo::Field.
157
+ def encode(name) #:nodoc:
158
+ if @field
159
+ # FIXME - set the field name, it could be different from cached
160
+ return @field
161
+ end
162
+
163
+ value = uri.to_str.strip
164
+
165
+ if value.empty?
166
+ raise Uencodeable, "Address#uri is zero-length"
167
+ end
168
+
169
+ params = {}
170
+
171
+ if cn.length > 0
172
+ params['CN'] = Vpim::encode_paramvalue(cn)
173
+ end
174
+
175
+ # FIXME - default value is different for non-vEvent
176
+ if role.length > 0 && role != 'REQ-PARTICIPANT'
177
+ params['ROLE'] = Vpim::encode_paramtext(role)
178
+ end
179
+
180
+ # FIXME - default value is different for non-vEvent
181
+ if partstat.length > 0 && partstat != 'NEEDS-ACTION'
182
+ params['PARTSTAT'] = Vpim::encode_paramtext(partstat)
183
+ end
184
+
185
+ if rsvp
186
+ params['RSVP'] = 'true'
187
+ end
188
+
189
+ Vpim::DirectoryInfo::Field.create(name, value, params)
190
+ end
191
+
192
+ # Return true if the +uri+ is == to this address' URI. The comparison
193
+ # is case-insensitive (because email addresses and domain names are).
194
+ def ==(uri)
195
+ # TODO - could I use a URI library?
196
+ Vpim::Methods.casecmp?(self.uri.to_str, uri.to_str)
197
+ end
198
+
199
+ # A string representation of an address, using the common name, and the
200
+ # URI. The URI protocol is stripped if it's "mailto:".
201
+ def to_s
202
+ u = uri
203
+ u = u.gsub(/^mailto: */i, '')
204
+
205
+ if cn.length > 0
206
+ "#{cn.inspect} <#{uri}>"
207
+ else
208
+ uri
209
+ end
210
+ end
211
+
212
+ def inspect #:nodoc:
213
+ "#<Vpim::Icalendar::Address:cn=#{cn.inspect} status=#{partstat} rsvp=#{rsvp} #{uri.inspect}>"
214
+ end
215
+
216
+ end
217
+ end
218
+ end
219
+
@@ -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
+