rwdaddresses 1.01 → 1.02

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/Readme.txt +5 -0
  2. data/code/01rwdcore/01rwdcore.rb +15 -13
  3. data/code/01rwdcore/openhelpwindow.rb +26 -26
  4. data/code/01rwdcore/returntomain.rb +8 -8
  5. data/code/01rwdcore/rwdtinkerversion.rb +12 -13
  6. data/code/01rwdcore/rwdwindowreturn.rb +3 -5
  7. data/code/01rwdcore/test_cases.rb +115 -0
  8. data/code/01rwdcore/test_harness.rb +12 -0
  9. data/code/01rwdcore/uploadreturns.rb +60 -59
  10. data/code/superant.com.rwdaddresses/attachtmpcontactphoto.rb +23 -23
  11. data/code/superant.com.rwdaddresses/clearscreendisplay.rb +14 -15
  12. data/code/superant.com.rwdaddresses/createnewnamerecord.rb +19 -18
  13. data/code/superant.com.rwdaddresses/deletecontactrecord.rb +22 -21
  14. data/code/superant.com.rwdaddresses/deleterwdaddressesupdatefiles.rb +15 -16
  15. data/code/superant.com.rwdaddresses/downloadrwdaddressfiles.rb +34 -32
  16. data/code/superant.com.rwdaddresses/listnamerecord.rb +14 -14
  17. data/code/superant.com.rwdaddresses/listvcardrecord.rb +15 -0
  18. data/code/superant.com.rwdaddresses/loadconfigurationrecord.rb +45 -44
  19. data/code/superant.com.rwdaddresses/loadconfigurationvariables.rb +14 -13
  20. data/code/superant.com.rwdaddresses/loadnamerecord.rb +29 -29
  21. data/code/superant.com.rwdaddresses/openhelpwindowrwdaddresses.rb +25 -25
  22. data/code/superant.com.rwdaddresses/renamecontact.rb +14 -15
  23. data/code/superant.com.rwdaddresses/returntomain.rb +8 -8
  24. data/code/superant.com.rwdaddresses/runaddresseswindow.rb +8 -8
  25. data/code/superant.com.rwdaddresses/runrwdaddressesmenu1.rb +31 -31
  26. data/code/superant.com.rwdaddresses/runrwdaddresssyncbackwindow.rb +8 -8
  27. data/code/superant.com.rwdaddresses/rwdaddressesbackwindow.rb +8 -8
  28. data/code/superant.com.rwdaddresses/rwdaddresseshelpabout.rb +10 -11
  29. data/code/superant.com.rwdaddresses/saveconfigurationrecord.rb +20 -20
  30. data/code/superant.com.rwdaddresses/savevcardrecord.rb +76 -0
  31. data/code/superant.com.rwdaddresses/syncrwdaddress.rb +24 -26
  32. data/code/superant.com.rwdaddresses/uploadrwdaddressfiles.rb +28 -28
  33. data/code/superant.com.rwdaddresses/viewaddressconfiguration.rb +21 -21
  34. data/code/superant.com.rwdaddresses/viewnamedata.rb +27 -26
  35. data/code/superant.com.rwdaddresses/viewphoto.rb +4 -4
  36. data/code/superant.com.rwdaddresses/viewrwdaddressesconfiguration.rb +23 -21
  37. data/code/superant.com.rwdaddresses/viewtmpcontactphoto.rb +6 -6
  38. data/code/superant.com.rwdaddresses/viewvcarddata.rb +22 -0
  39. data/code/superant.com.rwdtinkerbackwindow/controlclient.rb +89 -92
  40. data/code/superant.com.rwdtinkerbackwindow/diagnostictab.rb +15 -20
  41. data/code/superant.com.rwdtinkerbackwindow/installapplet.rb +19 -18
  42. data/code/superant.com.rwdtinkerbackwindow/installgemapplet.rb +20 -19
  43. data/code/superant.com.rwdtinkerbackwindow/installremotegem.rb +19 -18
  44. data/code/superant.com.rwdtinkerbackwindow/listgemdirs.rb +7 -7
  45. data/code/superant.com.rwdtinkerbackwindow/listgemzips.rb +48 -49
  46. data/code/superant.com.rwdtinkerbackwindow/listinstalledfiles.rb +8 -7
  47. data/code/superant.com.rwdtinkerbackwindow/listzips.rb +22 -26
  48. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationrecord.rb +32 -31
  49. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationvariables.rb +14 -13
  50. data/code/superant.com.rwdtinkerbackwindow/network.rb +82 -82
  51. data/code/superant.com.rwdtinkerbackwindow/openappletname.rb +18 -17
  52. data/code/superant.com.rwdtinkerbackwindow/openhelpwindowtinkerwin2.rb +37 -37
  53. data/code/superant.com.rwdtinkerbackwindow/remotegemlist.rb +20 -20
  54. data/code/superant.com.rwdtinkerbackwindow/removeapplet.rb +33 -32
  55. data/code/superant.com.rwdtinkerbackwindow/runrwdtinkerbackwindow.rb +8 -9
  56. data/code/superant.com.rwdtinkerbackwindow/rwdtinkerwin2version.rb +10 -11
  57. data/code/superant.com.rwdtinkerbackwindow/saveconfigurationrecord.rb +19 -18
  58. data/code/superant.com.rwdtinkerbackwindow/viewappletcontents.rb +21 -20
  59. data/code/superant.com.rwdtinkerbackwindow/viewgemappletcontents.rb +23 -20
  60. data/configuration/language.dist +1 -1
  61. data/configuration/rwdaddresses.dist +2 -2
  62. data/configuration/rwdtinker.dist +2 -2
  63. data/configuration/tinkerwin2variables.dist +1 -1
  64. data/extras/vpim/date.rb +198 -0
  65. data/extras/vpim/dirinfo.rb +229 -0
  66. data/extras/vpim/enumerator.rb +29 -0
  67. data/extras/vpim/field.rb +497 -0
  68. data/extras/vpim/maker/vcard.rb +312 -0
  69. data/extras/vpim/rfc2425.rb +244 -0
  70. data/extras/vpim/rrule.rb +482 -0
  71. data/extras/vpim/time.rb +42 -0
  72. data/extras/vpim/vcard.rb +151 -0
  73. data/extras/vpim/vpim.rb +94 -0
  74. data/gui/frontwindow0/superant.com.rwdaddresses/16editrecord.rwd +5 -0
  75. data/gui/frontwindow0/superant.com.rwdaddresses/17viewvcardrecord.rwd +32 -0
  76. data/gui/helpaboutinstalled/superant.com.tinkerhelpabout/3copyright.rwd +1 -1
  77. data/gui/tinkerbackwindows/superant.com.rwdaddressessyncbackwindow/70rwddiagnostics.rwd +1 -11
  78. data/init.rb +231 -228
  79. data/names/Angelina Jolie.vcf +8 -0
  80. data/rwd_files/HowTo_Addresses.txt +5 -0
  81. data/rwd_files/HowTo_Tinker.txt +14 -0
  82. data/rwdconfig.dist +6 -2
  83. data/tests/makedist.rb +36 -7
  84. metadata +23 -21
  85. data/extras/cmdline_parse +0 -47
  86. data/extras/config_file +0 -69
  87. data/extras/errorMsg +0 -19
  88. data/extras/makePlaylist +0 -34
  89. data/extras/mp3controld +0 -289
  90. data/extras/playlist +0 -186
  91. data/extras/plugins/Network +0 -237
  92. data/extras/showHelp +0 -18
  93. data/gui/frontwindowselections/superant.com.rwdaddressesselectiontab/rwdaddressessyncselectiontab.rwd +0 -12
  94. data/gui/helpaboutinstalled/superant.com.rwdwin2helpabout/1appname.rwd +0 -4
  95. data/gui/helpaboutinstalled/superant.com.rwdwin2helpabout/3copyright.rwd +0 -3
  96. data/gui/helpaboutinstalled/superant.com.rwdwin2helpabout/5version.rwd +0 -10
  97. data/installed/rwdaddressesdata2.inf +0 -8
  98. data/rwd_files/tinker.png +0 -0
@@ -0,0 +1,312 @@
1
+ =begin
2
+ $Id: vcard.rb,v 1.6 2005/01/02 17:18:08 sam Exp $
3
+
4
+ Copyright (C) 2005 Sam Roberts
5
+
6
+ This library is free software; you can redistribute it and/or modify it
7
+ under the same terms as the ruby language itself, see the file COPYING for
8
+ details.
9
+ =end
10
+
11
+ require 'extras/vpim/vcard'
12
+
13
+ module Vpim
14
+ module Maker
15
+ # A helper class to assist in building a vCard.
16
+ #
17
+ # This idea is modelled after ruby 1.8's rss/maker classes. Perhaps all these methods
18
+ # should be added to Vpim::Vcard?
19
+ #
20
+ # = Example
21
+ #
22
+ # - link:ex_mkvcard.txt.
23
+ #
24
+ # Also, see Vpim::Vcard for other examples, some of them use the Vcard::Maker.
25
+ class Vcard
26
+ # Make a vCard for +full_name+.
27
+ #
28
+ # Yields +card+, a Vpim::Maker::Vcard to which fields can be added, and returns a Vpim::Vcard.
29
+ #
30
+ # Note that calling #add_name is required, all other fields are optional.
31
+ def Vcard.make(full_name, &block) # :yields: +card+
32
+ new(full_name).make(&block)
33
+ end
34
+
35
+ def make # :nodoc:
36
+ yield self
37
+ if !@initialized_N
38
+ raise Vpim::InvalidEncodingError, 'It is mandatory to have a N field, see #add_name.'
39
+ end
40
+ @card
41
+ end
42
+
43
+ private
44
+
45
+ def initialize(full_name) # :nodoc:
46
+ @card = Vpim::Vcard::create
47
+ @card << Vpim::DirectoryInfo::Field.create('FN', full_name )
48
+ @initialized_N = false
49
+ # pp @card
50
+ end
51
+
52
+ public
53
+
54
+ # Add an arbitrary field, +field+.
55
+ def add_field(field)
56
+ @card << field
57
+ end
58
+
59
+ # Add a name field, N.
60
+ #
61
+ # Warning: This is the only mandatory field, besides the full name, which
62
+ # is added from Vcard.make's +full_name+.
63
+ #
64
+ # Attributes of N are:
65
+ # - family: family name
66
+ # - given: given name
67
+ # - additional: additional names
68
+ # - prefix: such as "Ms." or "Dr."
69
+ # - suffix: such as "BFA", or "Sensei"
70
+ #
71
+ # All attributes are optional.
72
+ #
73
+ # FIXME: Each attribute can currently only have a single String value.
74
+ #
75
+ # FIXME: Need to escape specials in the String.
76
+ def add_name # :yield: n
77
+ x = Struct.new(:family, :given, :additional, :prefix, :suffix).new
78
+ yield x
79
+ @card << Vpim::DirectoryInfo::Field.create(
80
+ 'N',
81
+ x.map { |s| s ? s.to_str : '' }
82
+ )
83
+ @initialized_N = true
84
+ self
85
+ end
86
+
87
+ # Add a address field, ADR.
88
+ #
89
+ # Attributes of ADR that describe the address are:
90
+ # - pobox: post office box
91
+ # - extended: seldom used, its not clear what it is for
92
+ # - street: street address, multiple components should be separated by a comma, ','
93
+ # - locality: usually the city
94
+ # - region: usually the province or state
95
+ # - postalcode: postal code
96
+ # - country: country name, no standard for country naming is specified
97
+ #
98
+ # Attributes that describe how the address is used, and customary values, are:
99
+ # - location: home, work - often used, can be set to other values
100
+ # - preferred: true - often used, set if this is the preferred address
101
+ # - delivery: postal, parcel, dom (domestic), intl (international) - rarely used
102
+ #
103
+ # All attributes are optional. #location and #home can be set to arrays of
104
+ # strings.
105
+ #
106
+ # TODO: Add #label to support LABEL.
107
+ #
108
+ # FIXME: Need to escape specials in the String.
109
+ def add_addr # :yield: adr
110
+ x = Struct.new(
111
+ :location, :preferred, :delivery,
112
+ :pobox, :extended, :street, :locality, :region, :postalcode, :country
113
+ ).new
114
+ yield x
115
+
116
+ values = x.to_a[3, 7].map { |s| s ? s.to_str : '' }
117
+
118
+ # All these attributes go into the TYPE parameter.
119
+ params = [ x[:location], x[:delivery] ]
120
+ params << 'pref' if x[:preferred]
121
+ params = params.flatten.uniq.compact.map { |s| s.to_str }
122
+
123
+ paramshash = {}
124
+
125
+ paramshash['type'] = params if params.first
126
+
127
+ @card << Vpim::DirectoryInfo::Field.create( 'ADR', values, paramshash)
128
+ self
129
+ end
130
+
131
+ # Add a telephone number field, TEL.
132
+ #
133
+ # +number+ is supposed to be a "X.500 Telephone Number" according to RFC 2426, if you happen
134
+ # to be familiar with that. Otherwise, anything that looks like a phone number should be OK.
135
+ #
136
+ # Attributes of TEL are:
137
+ # - location: home, work, msg, cell, car, pager - often used, can be set to other values
138
+ # - preferred: true - often used, set if this is the preferred telephone number
139
+ # - capability: voice,fax,video,bbs,modem,isdn,pcs - fax is useful, the others are rarely used
140
+ #
141
+ # All attributes are optional, and so is the block.
142
+ def add_tel(number) # :yield: tel
143
+ params = {}
144
+ if block_given?
145
+ x = Struct.new( :location, :preferred, :capability ).new
146
+
147
+ yield x
148
+
149
+ x[:preferred] = 'pref' if x[:preferred]
150
+
151
+ types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
152
+
153
+ params['type'] = types if types.first
154
+ end
155
+
156
+ @card << Vpim::DirectoryInfo::Field.create( 'TEL', number, params)
157
+ self
158
+ end
159
+
160
+ # Add a email address field, EMAIL.
161
+ #
162
+ # Attributes of EMAIL are:
163
+ # - location: home, work - often used, can be set to other values
164
+ # - preferred: true - often used, set if this is the preferred email address
165
+ # - protocol: internet,x400 - internet is the default, set this for other kinds
166
+ #
167
+ # All attributes are optional, and so is the block.
168
+ def add_email(email) # :yield: email
169
+ params = {}
170
+ if block_given?
171
+ x = Struct.new( :location, :preferred, :protocol ).new
172
+
173
+ yield x
174
+
175
+ x[:preferred] = 'pref' if x[:preferred]
176
+
177
+ types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
178
+
179
+ params['type'] = types if types.first
180
+ end
181
+
182
+ @card << Vpim::DirectoryInfo::Field.create( 'EMAIL', email, params)
183
+ self
184
+ end
185
+
186
+ # Add a nickname field, NICKNAME.
187
+ def nickname=(nickname)
188
+ @card << Vpim::DirectoryInfo::Field.create( 'NICKNAME', nickname );
189
+ end
190
+
191
+ # Add a birthday field, BDAY.
192
+ #
193
+ # +birthday+ must be a time or date object.
194
+ #
195
+ # Warning: It may confuse both humans and software if you add multiple
196
+ # birthdays.
197
+ def birthday=(birthday)
198
+ if !birthday.respond_to? :month
199
+ raise Vpim::InvalidEncodingError, 'birthday doesn\'t have #month, so it is not a date or time object.'
200
+ end
201
+ @card << Vpim::DirectoryInfo::Field.create( 'BDAY', birthday );
202
+ end
203
+ =begin
204
+ TODO - need text=() implemented in Field
205
+
206
+ # Add a note field, NOTE. It can contain newlines, they will be escaped.
207
+ def note=(note)
208
+ @card << Vpim::DirectoryInfo::Field.create( 'NOTE', note );
209
+ end
210
+ =end
211
+
212
+ # TODO: IMPP, see draft-jennings...
213
+
214
+ # Add an instant-messaging/point of presence address field, IMPP. The address
215
+ # is a URL, with the syntax depending on the protocol.
216
+ #
217
+ # Attributes of IMPP are:
218
+ # - preferred: true - set if this is the preferred address
219
+ # - location: home, work, mobile - location of address
220
+ # - purpose: personal,business - purpose of communications
221
+ #
222
+ # All attributes are optional, and so is the block.
223
+ #
224
+ # The URL syntaxes for the messaging schemes is fairly complicated, so I
225
+ # don't try and build the URLs here, maybe in the future. This forces
226
+ # the user to know the URL for their own address, hopefully not too much
227
+ # of a burden.
228
+ #
229
+ # IMPP is defined in draft-jennings-impp-vcard-04.txt. It refers to the
230
+ # URI scheme of a number of messaging protocols, but doesn't give
231
+ # references to all of them:
232
+ # - "xmpp" indicates to use XMPP, draft-saintandre-xmpp-uri-06.txt
233
+ # - "irc" or "ircs" indicates to use IRC, draft-butcher-irc-url-04.txt
234
+ # - "sip" indicates to use SIP/SIMPLE, RFC 3261
235
+ # - "im" or "pres" indicates to use a CPIM or CPP gateway, RFC 3860 and RFC 3859
236
+ # - "ymsgr" indicates to use yahoo
237
+ # - "msn" might indicate to use Microsoft messenger
238
+ # - "aim" indicates to use AOL
239
+ #
240
+ def add_impp(url) # :yield: impp
241
+ params = {}
242
+
243
+ if block_given?
244
+ x = Struct.new( :location, :preferred, :purpose ).new
245
+
246
+ yield x
247
+
248
+ x[:preferred] = 'pref' if x[:preferred]
249
+
250
+ types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
251
+
252
+ params['type'] = types if types.first
253
+ end
254
+
255
+ @card << Vpim::DirectoryInfo::Field.create( 'IMPP', url, params)
256
+ self
257
+ end
258
+
259
+ # Add a photo field, PHOTO.
260
+ #
261
+ # Attributes of PHOTO are:
262
+ # - image: set to image data to inclue inline
263
+ # - link: set to the URL of the image data
264
+ # - type: string identifying the image type, supposed to be an "IANA registered image format",
265
+ # or a non-registered image format (usually these start with an x-)
266
+ #
267
+ # An error will be raised if neither image or link is set, or if both image
268
+ # and link is set.
269
+ #
270
+ # Setting type is optional for a link image, because either the URL, the
271
+ # image file extension, or a HTTP Content-Type may specify the type. If
272
+ # it's not a link, setting type is mandatory, though it can be set to an
273
+ # empty string, <code>''</code>, if the type is unknown.
274
+ #
275
+ # TODO - I'm not sure about this API. I'm thinking maybe it should be
276
+ # #add_photo(image, type), and that I should detect when the image is a
277
+ # URL, and make type mandatory if it wasn't a URL.
278
+ def add_photo # :yield: photo
279
+ x = Struct.new(:image, :link, :type).new
280
+ yield x
281
+ if x[:image] && x[:link]
282
+ raise Vpim::InvalidEncodingError, 'Image is not allowed to be both inline and a link.'
283
+ end
284
+
285
+ value = x[:image] || x[:link]
286
+
287
+ if !value
288
+ raise Vpim::InvalidEncodingError, 'A image link or inline data must be provided.'
289
+ end
290
+
291
+ params = {}
292
+
293
+ # Don't set type to the empty string.
294
+ params['type'] = x[:type] if( x[:type] && x[:type].length > 0 )
295
+
296
+ if x[:link]
297
+ params['value'] = 'uri'
298
+ else # it's inline, base-64 encode it
299
+ params['encoding'] = :b64
300
+ if !x[:type]
301
+ raise Vpim::InvalidEncodingError, 'Inline image data must have it\'s type set.'
302
+ end
303
+ end
304
+
305
+ @card << Vpim::DirectoryInfo::Field.create( 'PHOTO', value, params )
306
+ self
307
+ end
308
+
309
+ end
310
+ end
311
+ end
312
+
@@ -0,0 +1,244 @@
1
+ =begin
2
+ $Id: rfc2425.rb,v 1.10 2005/01/01 17:17:01 sam Exp $
3
+
4
+ Copyright (C) 2005 Sam Roberts
5
+
6
+ This library is free software; you can redistribute it and/or modify it
7
+ under the same terms as the ruby language itself, see the file COPYING for
8
+ details.
9
+ =end
10
+
11
+ #require 'vpim/vpim'
12
+
13
+ module Vpim
14
+ # Contains regular expression strings for the EBNF of RFC 2425.
15
+ module Bnf #:nodoc:
16
+
17
+ # 1*(ALPHA / DIGIT / "=")
18
+ NAME = '[-a-z0-9]+'
19
+
20
+ # <"> <Any character except CTLs, DQUOTE> <">
21
+ QSTR = '"[^"]*"'
22
+
23
+ # *<Any character except CTLs, DQUOTE, ";", ":", ",">
24
+ PTEXT = '[^";:,]*'
25
+
26
+ # param-value = ptext / quoted-string
27
+ PVALUE = "#{PTEXT}|#{QSTR}"
28
+
29
+ # V3.0: contentline = [group "."] name *(";" param) ":" value
30
+ # V2.1: contentline = *( group "." ) name *(";" param) ":" value
31
+ #
32
+ # We accept the V2.1 syntax for backwards compatibility.
33
+ LINE = "((?:#{NAME}\\.)*)?(#{NAME})([^:]*)\:(.*)"
34
+
35
+ # param = name "=" param-value *("," param-value)
36
+ # Note: v2.1 allows a type or encoding param-value to appear without the type=
37
+ # or the encoding=. This is hideous, but we try and support it, if there
38
+ # is no "=", then $2 will be "", and we will treat it as a v2.1 param.
39
+ PARAM = ";(#{NAME})(=?)((?:#{PVALUE})(?:,#{PVALUE})*)"
40
+
41
+ # date = date-fullyear ["-"] date-month ["-"] date-mday
42
+ # date-fullyear = 4 DIGIT
43
+ # date-month = 2 DIGIT
44
+ # date-mday = 2 DIGIT
45
+ DATE = '(\d\d\d\d)-?(\d\d)-?(\d\d)'
46
+
47
+ # time = time-hour [":"] time-minute [":"] time-second [time-secfrac] [time-zone]
48
+ # time-hour = 2 DIGIT
49
+ # time-minute = 2 DIGIT
50
+ # time-second = 2 DIGIT
51
+ # time-secfrac = "," 1*DIGIT
52
+ # time-zone = "Z" / time-numzone
53
+ # time-numzome = sign time-hour [":"] time-minute
54
+ TIME = '(\d\d):?(\d\d):?(\d\d)(\.\d+)?(Z|[-+]\d\d:?\d\d)?'
55
+ end
56
+ end
57
+
58
+ module Vpim
59
+ # Split on \r\n or \n to get the lines, unfold continued lines (they
60
+ # start with ' ' or \t), and return the array of unfolded lines.
61
+ #
62
+ # This also implements the (invalid) encoding convention of allowing empty
63
+ # lines to be inserted for readability - it does this by dropping
64
+ # zero-length lines.
65
+ def Vpim.unfold(card) #:nodoc:
66
+ unfolded = []
67
+
68
+ card.split(/\r?\n/).each do
69
+ |line|
70
+
71
+ # If it's a continuation line, add it to the last.
72
+ # If it's an empty line, drop it from the input.
73
+ if( line =~ /^[ \t]/ )
74
+ unfolded << unfolded.pop + line[1, line.size-1]
75
+ elsif( line =~ /^$/ )
76
+ else
77
+ unfolded << line
78
+ end
79
+ end
80
+
81
+ unfolded
82
+ end
83
+
84
+ # Convert a +sep+-seperated list of values into an array of values.
85
+ def Vpim.decode_list(value, sep = ',') # :nodoc:
86
+ list = []
87
+
88
+ value.each(sep) {
89
+ |item|
90
+ list << yield(item) unless item =~ %r{^\s*#{sep}?$}
91
+ }
92
+ list
93
+ end
94
+
95
+ # Convert a RFC 2425 date into an array of [year, month, day].
96
+ def Vpim.decode_date(v) # :nodoc:
97
+ unless v =~ %r{\s*#{Bnf::DATE}\s*}
98
+ raise Vpim::InvalidEncodingError, "date not valid (#{v})"
99
+ end
100
+ [$1.to_i, $2.to_i, $3.to_i]
101
+ end
102
+
103
+ # Note in the following the RFC2425 allows yyyy-mm-ddThh:mm:ss, but RFC2445
104
+ # does not. I choose to encode to the subset that is valid for both.
105
+
106
+ # Encode a Date object as "yyyymmdd".
107
+ def Vpim.encode_date(d) # :nodoc:
108
+ "%0.4d%0.2d%0.2d" % [ d.year, d.mon, d.day ]
109
+ end
110
+
111
+ # Encode a Date object as "yyyymmdd".
112
+ def Vpim.encode_time(d) # :nodoc:
113
+ "%0.4d%0.2d%0.2d" % [ d.year, d.mon, d.day ]
114
+ end
115
+
116
+ # Encode a Time or DateTime object as "yyyymmddThhmmss"
117
+ def Vpim.encode_date_time(d) # :nodoc:
118
+ "%0.4d%0.2d%0.2dT%0.2d%0.2d%0.2d" % [ d.year, d.mon, d.day, d.hour, d.min, d.sec ]
119
+ end
120
+
121
+ # Convert a RFC 2425 time into an array of [hour,min,sec,secfrac,timezone]
122
+ def Vpim.decode_time(v) # :nodoc:
123
+ unless match = %r{\s*#{Bnf::TIME}\s*}.match(v)
124
+ raise Vpim::InvalidEncodingError, "time not valid (#{v})"
125
+ end
126
+ hour, min, sec, secfrac, tz = match.to_a[1..5]
127
+
128
+ [hour.to_i, min.to_i, sec.to_i, secfrac ? secfrac.to_f : 0, tz]
129
+ end
130
+
131
+ # Convert a RFC 2425 date-time into an array of [hour,min,sec,secfrac,timezone]
132
+ def Vpim.decode_date_time(v) # :nodoc:
133
+ unless match = %r{\s*#{Bnf::DATE}T#{Bnf::TIME}\s*}.match(v)
134
+ raise Vpim::InvalidEncodingError, "date-time '#{v}' not valid"
135
+ end
136
+ year, month, day, hour, min, sec, secfrac, tz = match.to_a[1..8]
137
+
138
+ [
139
+ # date
140
+ year.to_i, month.to_i, day.to_i,
141
+ # time
142
+ hour.to_i, min.to_i, sec.to_i, secfrac ? secfrac.to_f : 0, tz
143
+ ]
144
+ end
145
+
146
+ # Vpim.decode_boolean
147
+ #
148
+ # float
149
+ #
150
+ # float_list
151
+ #
152
+ # integer
153
+ #
154
+ # integer_list
155
+ #
156
+ # text_list
157
+
158
+ # Convert a RFC 2425 date-list into an array of dates.
159
+ def Vpim.decode_date_list(v) # :nodoc:
160
+ dates = Vpim.decode_list(v) { |date| Vpim.decode_date(date) }
161
+ end
162
+
163
+ # Convert a RFC 2425 time-list into an array of times.
164
+ def Vpim.decode_time_list(v) # :nodoc:
165
+ times = Vpim.decode_list(v) { |time| Vpim.decode_time(time) }
166
+ end
167
+
168
+ # Convert a RFC 2425 date-time-list into an array of date-times.
169
+ def Vpim.decode_date_time_list(v) # :nodoc:
170
+ datetimes = Vpim.decode_list(v) { |datetime| Vpim.decode_date_time(datetime) }
171
+ end
172
+
173
+ # Convert RFC 2425 text into a String.
174
+ # \\ -> \
175
+ # \n -> NL
176
+ # \N -> NL
177
+ # \, -> ,
178
+ def Vpim.decode_text(v) # :nodoc:
179
+ v.gsub(/\\[nN]/, "\n").gsub(/\\,/, ",").gsub(/\\\\/) { |m| "\\" }
180
+ end
181
+
182
+
183
+ # Unfold the lines in +card+, then return an array of one Field object per
184
+ # line.
185
+ def Vpim.decode(card) #:nodoc:
186
+ content = Vpim.unfold(card).collect { |line| DirectoryInfo::Field.decode(line) }
187
+ end
188
+
189
+
190
+ # Expand an array of fields into its syntactic entities. Each entity is a sequence
191
+ # of fields where the sequences is delimited by a BEGIN/END field. Since
192
+ # BEGIN/END delimited entities can be nested, we build a tree. Each entry in
193
+ # the array is either a Field or an array of entries (where each entry is
194
+ # either a Field, or an array of entries...).
195
+ def Vpim.expand(src) #:nodoc:
196
+ # output array to expand the src to
197
+ dst = []
198
+ # stack used to track our nesting level, as we see begin/end we start a
199
+ # new/finish the current entity, and push/pop that entity from the stack
200
+ current = [ dst ]
201
+
202
+ for f in src
203
+ if f.name? 'begin'
204
+ e = [ f ]
205
+
206
+ current.last.push(e)
207
+ current.push(e)
208
+
209
+ elsif f.name? 'end'
210
+ current.last.push(f)
211
+
212
+ unless current.last.first.value? current.last.last.value
213
+ raise "BEGIN/END mismatch (#{current.last.first.value} != #{current.last.last.value})"
214
+ end
215
+
216
+ current.pop
217
+
218
+ else
219
+ current.last.push(f)
220
+ end
221
+ end
222
+
223
+ dst
224
+ end
225
+
226
+ # Split an array into an array of all the fields at the outer level, and
227
+ # an array of all the inner arrays of fields. Return the array [outer,
228
+ # inner].
229
+ def Vpim.outer_inner(fields) #:nodoc:
230
+ # seperate into the outer-level fields, and the arrays of component
231
+ # fields
232
+ outer = []
233
+ inner = []
234
+ fields.each do |line|
235
+ case line
236
+ when Array; inner << line
237
+ else; outer << line
238
+ end
239
+ end
240
+ return outer, inner
241
+ end
242
+
243
+ end
244
+