gpgme-ffi 3.0.0

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.
Files changed (65) hide show
  1. data/examples/edit.rb +77 -0
  2. data/examples/genkey.rb +55 -0
  3. data/examples/keylist.rb +7 -0
  4. data/examples/roundtrip.rb +42 -0
  5. data/examples/sign.rb +31 -0
  6. data/examples/verify.rb +8 -0
  7. data/ext/gpgme/Makefile.in +55 -0
  8. data/ext/gpgme/extconf.rb +8 -0
  9. data/ext/gpgme/extract_enums.rb +88 -0
  10. data/ext/gpgme/gpgme-1.3.1.tar.bz2 +0 -0
  11. data/ext/gpgme/libassuan-2.0.2.tar.bz2 +0 -0
  12. data/ext/gpgme/libgpg-error-1.10.tar.bz2 +0 -0
  13. data/ext/gpgme/libgpgme_gem.so +0 -0
  14. data/lib/gpgme/compat.rb +48 -0
  15. data/lib/gpgme/constants.rb +187 -0
  16. data/lib/gpgme/crypto.rb +357 -0
  17. data/lib/gpgme/ctx.rb +462 -0
  18. data/lib/gpgme/data.rb +189 -0
  19. data/lib/gpgme/engine.rb +76 -0
  20. data/lib/gpgme/error.rb +66 -0
  21. data/lib/gpgme/ffi/ctx.rb +36 -0
  22. data/lib/gpgme/ffi/data.rb +24 -0
  23. data/lib/gpgme/ffi/decrypt_result.rb +14 -0
  24. data/lib/gpgme/ffi/encrypt_result.rb +22 -0
  25. data/lib/gpgme/ffi/engine_info.rb +17 -0
  26. data/lib/gpgme/ffi/enums.rb +687 -0
  27. data/lib/gpgme/ffi/functions.rb +364 -0
  28. data/lib/gpgme/ffi/import_result.rb +35 -0
  29. data/lib/gpgme/ffi/import_status.rb +15 -0
  30. data/lib/gpgme/ffi/invalid_key.rb +14 -0
  31. data/lib/gpgme/ffi/key.rb +60 -0
  32. data/lib/gpgme/ffi/key_sig.rb +20 -0
  33. data/lib/gpgme/ffi/library.rb +279 -0
  34. data/lib/gpgme/ffi/meta.rb +57 -0
  35. data/lib/gpgme/ffi/new_signature.rb +18 -0
  36. data/lib/gpgme/ffi/sig_notation.rb +12 -0
  37. data/lib/gpgme/ffi/sign_result.rb +33 -0
  38. data/lib/gpgme/ffi/signature.rb +35 -0
  39. data/lib/gpgme/ffi/sub_key.rb +27 -0
  40. data/lib/gpgme/ffi/trust_item.rb +31 -0
  41. data/lib/gpgme/ffi/user_id.rb +30 -0
  42. data/lib/gpgme/ffi/verify_result.rb +22 -0
  43. data/lib/gpgme/ffi.rb +22 -0
  44. data/lib/gpgme/io_callbacks.rb +21 -0
  45. data/lib/gpgme/key.rb +242 -0
  46. data/lib/gpgme/key_common.rb +43 -0
  47. data/lib/gpgme/key_sig.rb +35 -0
  48. data/lib/gpgme/misc.rb +66 -0
  49. data/lib/gpgme/signature.rb +85 -0
  50. data/lib/gpgme/sub_key.rb +58 -0
  51. data/lib/gpgme/user_id.rb +20 -0
  52. data/lib/gpgme/version.rb +3 -0
  53. data/lib/gpgme.rb +106 -0
  54. data/test/crypto_test.rb +246 -0
  55. data/test/ctx_test.rb +432 -0
  56. data/test/data_test.rb +129 -0
  57. data/test/files/testkey_pub.gpg +52 -0
  58. data/test/files/testkey_sec.gpg +54 -0
  59. data/test/gpgme_test.rb +12 -0
  60. data/test/key_test.rb +209 -0
  61. data/test/signature_test.rb +52 -0
  62. data/test/sub_key_test.rb +48 -0
  63. data/test/support/resources.rb +516 -0
  64. data/test/test_helper.rb +84 -0
  65. metadata +203 -0
data/lib/gpgme/ctx.rb ADDED
@@ -0,0 +1,462 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # A context within which all cryptographic operations are performed.
5
+ #
6
+ # More operations can be done which are not available in the higher level
7
+ # API. Note how to create a new instance of this class in {GPGME::Ctx.new}.
8
+ #
9
+ class Ctx
10
+
11
+ ##
12
+ # Create a new instance from the given +options+. Must be released either
13
+ # executing the operations inside a block, or executing {GPGME::Ctx#release}
14
+ # afterwards.
15
+ #
16
+ # @param [Hash] options
17
+ # The optional parameters are as follows:
18
+ # * +:protocol+ Either +PROTOCOL_OpenPGP+ or +PROTOCOL_CMS+.
19
+ # * +:armor+ will return ASCII armored outputs if specified true.
20
+ # * +:textmode+ if +true+, inform the recipient that the input is text.
21
+ # * +:keylist_mode+ One of: +KEYLIST_MODE_LOCAL+, +KEYLIST_MODE_EXTERN+,
22
+ # +KEYLIST_MODE_SIGS+ or +KEYLIST_MODE_VALIDATE+.
23
+ # * +:password+ password of the passphrased password being used.
24
+ # * +:passphrase_callback+ A callback function. See {#set_passphrase_callback}.
25
+ # * +:passphrase_callback_value+ An object passed to passphrase_callback.
26
+ # * +:progress_callback+ A callback function. See {#set_progress_callback}.
27
+ # * +:progress_callback_value+ An object passed to progress_callback.
28
+ #
29
+ # @example
30
+ # ctx = GPGME::Ctx.new
31
+ # # operate on ctx
32
+ # ctx.release
33
+ #
34
+ # @example
35
+ # GPGME::Ctx.new do |ctx|
36
+ # # operate on ctx
37
+ # end
38
+ #
39
+ def self.new(options = {})
40
+ rctx = []
41
+ err = GPGME::gpgme_new(rctx)
42
+ exc = GPGME::error_to_exception(err)
43
+ raise exc if exc
44
+ ctx = rctx[0]
45
+
46
+ ctx.protocol = options[:protocol] if options[:protocol]
47
+ ctx.armor = options[:armor] if options[:armor]
48
+ ctx.textmode = options[:textmode] if options[:textmode]
49
+ ctx.keylist_mode = options[:keylist_mode] if options[:keylist_mode]
50
+
51
+ if options[:password]
52
+ ctx.set_passphrase_callback GPGME::Ctx.method(:pass_function),
53
+ options[:password]
54
+ else
55
+ if options[:passphrase_callback]
56
+ ctx.set_passphrase_callback options[:passphrase_callback],
57
+ options[:passphrase_callback_value]
58
+ end
59
+ end
60
+ if options[:progress_callback]
61
+ ctx.set_progress_callback options[:progress_callback],
62
+ options[:progress_callback_value]
63
+ end
64
+
65
+ if block_given?
66
+ begin
67
+ yield ctx
68
+ ensure
69
+ GPGME::gpgme_release(ctx)
70
+ end
71
+ else
72
+ ctx
73
+ end
74
+ end
75
+
76
+
77
+ ##
78
+ # Releases the Ctx instance. Must be called if it was initialized without
79
+ # a block.
80
+ #
81
+ # @example
82
+ # ctx = GPGME::Ctx.new
83
+ # # operate on ctx
84
+ # ctx.release
85
+ #
86
+ def release
87
+ GPGME::gpgme_release(self)
88
+ end
89
+
90
+ ##
91
+ # Getters and setters
92
+ ##
93
+
94
+ # Set the +protocol+ used within this context. See {GPGME::Ctx.new} for
95
+ # possible values.
96
+ def protocol=(proto)
97
+ err = GPGME::gpgme_set_protocol(self, proto)
98
+ exc = GPGME::error_to_exception(err)
99
+ raise exc if exc
100
+ proto
101
+ end
102
+
103
+ # Return the +protocol+ used within this context.
104
+ def protocol
105
+ GPGME::gpgme_get_protocol(self)
106
+ end
107
+
108
+ # Tell whether the output should be ASCII armored.
109
+ def armor=(yes)
110
+ GPGME::gpgme_set_armor(self, yes ? 1 : 0)
111
+ yes
112
+ end
113
+
114
+ # Return true if the output is ASCII armored.
115
+ def armor
116
+ GPGME::gpgme_get_armor(self) == 1 ? true : false
117
+ end
118
+
119
+ # Tell whether canonical text mode should be used.
120
+ def textmode=(yes)
121
+ GPGME::gpgme_set_textmode(self, yes ? 1 : 0)
122
+ yes
123
+ end
124
+
125
+ # Return true if canonical text mode is enabled.
126
+ def textmode
127
+ GPGME::gpgme_get_textmode(self) == 1 ? true : false
128
+ end
129
+
130
+ # Change the default behaviour of the key listing functions.
131
+ def keylist_mode=(mode)
132
+ GPGME::gpgme_set_keylist_mode(self, mode)
133
+ mode
134
+ end
135
+
136
+ # Return the current key listing mode.
137
+ def keylist_mode
138
+ GPGME::gpgme_get_keylist_mode(self)
139
+ end
140
+
141
+ ##
142
+ # Passphrase and progress callbacks
143
+ ##
144
+
145
+ # Set the passphrase callback with given hook value.
146
+ # +passfunc+ should respond to +call+ with 5 arguments.
147
+ #
148
+ # * +obj+ the parameter +:passphrase_callback_value+ passed when creating
149
+ # the {GPGME::Ctx} object.
150
+ # * +uid_hint+ hint as to what key are we asking the password for. Ex:
151
+ #
152
+ # +CFB3294A50C2CFD7 Albert Llop <mrsimo@example.com>+
153
+ #
154
+ # * +passphrase_info+
155
+ # * +prev_was_bad+ 0 if it's the first time the password is being asked,
156
+ # 1 otherwise.
157
+ # * +fd+ file descriptor where the password must be written too.
158
+ #
159
+ # Expects a Method object which can be obtained by the +method+ method
160
+ # (really..).
161
+ #
162
+ # ctx.set_passphrase_callback(MyModule.method(:passfunc))
163
+ #
164
+ # @example this method will simply return +maria+ as password.
165
+ # def pass_function(obj, uid_hint, passphrase_info, prev_was_bad, fd)
166
+ # io = ::FFI::IO.for_fd(fd, 'w')
167
+ # io.puts "maria"
168
+ # io.flush
169
+ # end
170
+ #
171
+ # @example this will interactively ask for the password
172
+ # def passfunc(obj, uid_hint, passphrase_info, prev_was_bad, fd)
173
+ # $stderr.write("Passphrase for #{uid_hint}: ")
174
+ # $stderr.flush
175
+ # begin
176
+ # system('stty -echo')
177
+ # io = ::FFI::IO.for_fd(fd, 'w')
178
+ # io.puts(gets)
179
+ # io.flush
180
+ # ensure
181
+ # (0 ... $_.length).each do |i| $_[i] = ?0 end if $_
182
+ # system('stty echo')
183
+ # end
184
+ # $stderr.puts
185
+ # end
186
+ #
187
+ def set_passphrase_callback(passfunc, hook_value = nil)
188
+ GPGME::gpgme_set_passphrase_cb(self, passfunc, hook_value)
189
+ end
190
+ alias set_passphrase_cb set_passphrase_callback
191
+
192
+ # Set the progress callback with given hook value.
193
+ # <i>progfunc</i> should respond to <code>call</code> with 5 arguments.
194
+ #
195
+ # def progfunc(hook, what, type, current, total)
196
+ # $stderr.write("#{what}: #{current}/#{total}\r")
197
+ # $stderr.flush
198
+ # end
199
+ #
200
+ # ctx.set_progress_callback(method(:progfunc))
201
+ #
202
+ def set_progress_callback(progfunc, hook_value = nil)
203
+ GPGME::gpgme_set_progress_cb(self, progfunc, hook_value)
204
+ end
205
+ alias set_progress_cb set_progress_callback
206
+
207
+ ##
208
+ # Searching and iterating through keys. Used by {GPGME::Key.find}
209
+ ##
210
+
211
+ # Initiate a key listing operation for given pattern. If +pattern+ is
212
+ # +nil+, all available keys are returned. If +secret_only<+ is +true+,
213
+ # only secret keys are returned.
214
+ #
215
+ # Used by {GPGME::Ctx#each_key}
216
+ def keylist_start(pattern = nil, secret_only = false)
217
+ err = GPGME::gpgme_op_keylist_start(self, pattern, secret_only ? 1 : 0)
218
+ exc = GPGME::error_to_exception(err)
219
+ raise exc if exc
220
+ end
221
+
222
+ # Advance to the next key in the key listing operation.
223
+ #
224
+ # Used by {GPGME::Ctx#each_key}
225
+ def keylist_next
226
+ rkey = []
227
+ err = GPGME::gpgme_op_keylist_next(self, rkey)
228
+ exc = GPGME::error_to_exception(err)
229
+ raise exc if exc
230
+ rkey[0]
231
+ end
232
+
233
+ # End a pending key list operation.
234
+ #
235
+ # Used by {GPGME::Ctx#each_key}
236
+ def keylist_end
237
+ err = GPGME::gpgme_op_keylist_end(self)
238
+ exc = GPGME::error_to_exception(err)
239
+ raise exc if exc
240
+ end
241
+
242
+ # Convenient method to iterate over keys.
243
+ #
244
+ # If +pattern+ is +nil+, all available keys are returned. If +secret_only+
245
+ # is +true+, only secret keys are returned.
246
+ #
247
+ # See {GPGME::Key.find} for an example of how to use, or for an easier way
248
+ # to use.
249
+ def each_key(pattern = nil, secret_only = false, &block)
250
+ keylist_start(pattern, secret_only)
251
+ begin
252
+ loop { yield keylist_next }
253
+ rescue EOFError
254
+ # The last key in the list has already been returned.
255
+ ensure
256
+ keylist_end
257
+ end
258
+ end
259
+ alias each_keys each_key
260
+
261
+ # Returns the keys that match the +pattern+, or all if +pattern+ is nil.
262
+ # Returns only secret keys if +secret_only+ is true.
263
+ def keys(pattern = nil, secret_only = nil)
264
+ keys = []
265
+ each_key(pattern, secret_only) do |key|
266
+ keys << key
267
+ end
268
+ keys
269
+ end
270
+
271
+ # Get the key with the +fingerprint+.
272
+ # If +secret+ is +true+, secret key is returned.
273
+ def get_key(fingerprint, secret = false)
274
+ rkey = []
275
+ err = GPGME::gpgme_get_key(self, fingerprint, rkey, secret ? 1 : 0)
276
+ exc = GPGME::error_to_exception(err)
277
+ raise exc if exc
278
+ rkey[0]
279
+ end
280
+
281
+ ##
282
+ # Import/export and generation/deletion of keys
283
+ ##
284
+
285
+ # Generate a new key pair.
286
+ # +parms+ is a string which looks like
287
+ #
288
+ # <GnupgKeyParms format="internal">
289
+ # Key-Type: DSA
290
+ # Key-Length: 1024
291
+ # Subkey-Type: ELG-E
292
+ # Subkey-Length: 1024
293
+ # Name-Real: Joe Tester
294
+ # Name-Comment: with stupid passphrase
295
+ # Name-Email: joe@foo.bar
296
+ # Expire-Date: 0
297
+ # Passphrase: abc
298
+ # </GnupgKeyParms>
299
+ #
300
+ # If +pubkey+ and +seckey+ are both set to +nil+, it stores the generated
301
+ # key pair into your key ring.
302
+ def generate_key(parms, pubkey = nil, seckey = nil)
303
+ err = GPGME::gpgme_op_genkey(self, parms, pubkey, seckey)
304
+ exc = GPGME::error_to_exception(err)
305
+ raise exc if exc
306
+ end
307
+ alias genkey generate_key
308
+
309
+ # Extract the public keys that match the +recipients+. Returns a
310
+ # {GPGME::Data} object which is not rewinded (should do +seek(0)+
311
+ # before reading).
312
+ #
313
+ # Private keys cannot be exported due to GPGME restrictions.
314
+ #
315
+ # If passed, the key will be exported to +keydata+, which must be
316
+ # a {GPGME::Data} object.
317
+ def export_keys(recipients, keydata = Data.new)
318
+ err = GPGME::gpgme_op_export(self, recipients, 0, keydata)
319
+ exc = GPGME::error_to_exception(err)
320
+ raise exc if exc
321
+ keydata
322
+ end
323
+ alias export export_keys
324
+
325
+ # Add the keys in the data buffer to the key ring.
326
+ def import_keys(keydata)
327
+ err = GPGME::gpgme_op_import(self, keydata)
328
+ exc = GPGME::error_to_exception(err)
329
+ raise exc if exc
330
+ end
331
+ alias import import_keys
332
+
333
+ def import_result
334
+ GPGME::gpgme_op_import_result(self)
335
+ end
336
+
337
+ # Delete the key from the key ring.
338
+ # If allow_secret is false, only public keys are deleted,
339
+ # otherwise secret keys are deleted as well.
340
+ def delete_key(key, allow_secret = false)
341
+ err = GPGME::gpgme_op_delete(self, key, allow_secret ? 1 : 0)
342
+ exc = GPGME::error_to_exception(err)
343
+ raise exc if exc
344
+ end
345
+ alias delete delete_key
346
+
347
+ # Edit attributes of the key in the local key ring.
348
+ def edit_key(key, editfunc, hook_value = nil, out = Data.new)
349
+ err = GPGME::gpgme_op_edit(self, key, editfunc, hook_value, out)
350
+ exc = GPGME::error_to_exception(err)
351
+ raise exc if exc
352
+ end
353
+ alias edit edit_key
354
+
355
+ # Edit attributes of the key on the card.
356
+ def edit_card_key(key, editfunc, hook_value = nil, out = Data.new)
357
+ err = GPGME::gpgme_op_card_edit(self, key, editfunc, hook_value, out)
358
+ exc = GPGME::error_to_exception(err)
359
+ raise exc if exc
360
+ end
361
+ alias edit_card edit_card_key
362
+ alias card_edit edit_card_key
363
+
364
+ ##
365
+ # Crypto operations
366
+ ##
367
+
368
+ # Decrypt the ciphertext and return the plaintext.
369
+ def decrypt(cipher, plain = Data.new)
370
+ err = GPGME::gpgme_op_decrypt(self, cipher, plain)
371
+ exc = GPGME::error_to_exception(err)
372
+ raise exc if exc
373
+ plain
374
+ end
375
+
376
+ def decrypt_verify(cipher, plain = Data.new)
377
+ err = GPGME::gpgme_op_decrypt_verify(self, cipher, plain)
378
+ exc = GPGME::error_to_exception(err)
379
+ raise exc if exc
380
+ plain
381
+ end
382
+
383
+ def decrypt_result
384
+ GPGME::gpgme_op_decrypt_result(self)
385
+ end
386
+
387
+ # Verify that the signature in the data object is a valid signature.
388
+ def verify(sig, signed_text = nil, plain = Data.new)
389
+ err = GPGME::gpgme_op_verify(self, sig, signed_text, plain)
390
+ exc = GPGME::error_to_exception(err)
391
+ raise exc if exc
392
+ plain
393
+ end
394
+
395
+ def verify_result
396
+ GPGME::gpgme_op_verify_result(self)
397
+ end
398
+
399
+ # Remove the list of signers from this object.
400
+ def clear_signers
401
+ GPGME::gpgme_signers_clear(self)
402
+ end
403
+
404
+ # Add _keys_ to the list of signers.
405
+ def add_signer(*keys)
406
+ keys.each do |key|
407
+ err = GPGME::gpgme_signers_add(self, key)
408
+ exc = GPGME::error_to_exception(err)
409
+ raise exc if exc
410
+ end
411
+ end
412
+
413
+ # Create a signature for the text.
414
+ # +plain+ is a data object which contains the text.
415
+ # +sig+ is a data object where the generated signature is stored.
416
+ def sign(plain, sig = Data.new, mode = GPGME::SIG_MODE_NORMAL)
417
+ err = GPGME::gpgme_op_sign(self, plain, sig, mode)
418
+ exc = GPGME::error_to_exception(err)
419
+ raise exc if exc
420
+ sig
421
+ end
422
+
423
+ def sign_result
424
+ GPGME::gpgme_op_sign_result(self)
425
+ end
426
+
427
+ # Encrypt the plaintext in the data object for the recipients and
428
+ # return the ciphertext.
429
+ def encrypt(recp, plain, cipher = Data.new, flags = 0)
430
+ err = GPGME::gpgme_op_encrypt(self, recp, flags, plain, cipher)
431
+ exc = GPGME::error_to_exception(err)
432
+ raise exc if exc
433
+ cipher
434
+ end
435
+
436
+ def encrypt_result
437
+ GPGME::gpgme_op_encrypt_result(self)
438
+ end
439
+
440
+ def encrypt_sign(recp, plain, cipher = Data.new, flags = 0)
441
+ err = GPGME::gpgme_op_encrypt_sign(self, recp, flags, plain, cipher)
442
+ exc = GPGME::error_to_exception(err)
443
+ raise exc if exc
444
+ cipher
445
+ end
446
+
447
+ def inspect
448
+ "#<#{self.class} protocol=#{PROTOCOL_NAMES[protocol] || protocol}, \
449
+ armor=#{armor}, textmode=#{textmode}, \
450
+ keylist_mode=#{KEYLIST_MODE_NAMES[keylist_mode]}>"
451
+ end
452
+
453
+ private
454
+
455
+ def self.pass_function(pass, uid_hint, passphrase_info, prev_was_bad, fd)
456
+ io = ::FFI::IO.for_fd(fd, 'w')
457
+ io.puts pass
458
+ io.flush
459
+ end
460
+
461
+ end
462
+ end
data/lib/gpgme/data.rb ADDED
@@ -0,0 +1,189 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # A class whose purpose is to unify the way we work with the data (both input
5
+ # and output). Most of the calls expect instances of this class, or will try
6
+ # to create one from your parameters.
7
+ #
8
+ # Read the {#read}, {#write} and {#seek} methods for the most commonly used
9
+ # methods.
10
+ class Data
11
+
12
+ BLOCK_SIZE = 4096
13
+
14
+ class << self
15
+
16
+ ##
17
+ # We implement +self.new+ instead of initialize because objects are actually
18
+ # instantiated through the C API with stuff like +gpgme_data_new+.
19
+ #
20
+ # We try to create a {GPGME::Data} smartly depending on the object passed, and if
21
+ # another {GPGME::Data} object is passed, it just returns it, so when in
22
+ # doubt, you can always pass a {GPGME::Data} object.
23
+ #
24
+ # @example empty
25
+ # data = GPGME::Data.new
26
+ # data.write("stuff")
27
+ #
28
+ # @example from a string
29
+ # data = GPGME::Data.new("From a string")
30
+ #
31
+ # @example from a file
32
+ # data = GPGME::Data.new(File.open("secure.pass"))
33
+ #
34
+ # @example from a file descriptor
35
+ # data = GPGME::Data.new(0) # Standard input
36
+ # data = GPGME::Data.new(1) # Standard output
37
+ #
38
+ # file = File.open("secure.pass")
39
+ # data = GPGME::Data.new(file.fileno) # file descriptor
40
+ #
41
+ def new(object = nil)
42
+ if object.nil?
43
+ empty!
44
+ elsif object.is_a?(Data)
45
+ object
46
+ elsif object.is_a?(Integer)
47
+ from_fd(object)
48
+ elsif object.respond_to? :to_str
49
+ from_str(object.to_str)
50
+ elsif object.respond_to? :to_io
51
+ from_io(object.to_io)
52
+ elsif object.respond_to? :open
53
+ from_io(object.open)
54
+ end
55
+ end
56
+
57
+ # Create a new instance with an empty buffer.
58
+ def empty!
59
+ rdh = []
60
+ err = GPGME::gpgme_data_new(rdh)
61
+ exc = GPGME::error_to_exception(err)
62
+ raise exc if exc
63
+ rdh.first
64
+ end
65
+
66
+ # Create a new instance with internal buffer.
67
+ def from_str(string)
68
+ rdh = []
69
+ err = GPGME::gpgme_data_new_from_mem(rdh, string, string.length)
70
+ exc = GPGME::error_to_exception(err)
71
+ raise exc if exc
72
+ rdh.first
73
+ end
74
+
75
+ # Create a new instance associated with a given IO.
76
+ def from_io(io)
77
+ from_callbacks(IOCallbacks.new(io))
78
+ end
79
+
80
+ # Create a new instance from the specified file descriptor.
81
+ def from_fd(fd)
82
+ rdh = []
83
+ err = GPGME::gpgme_data_new_from_fd(rdh, fd)
84
+ exc = GPGME::error_to_exception(err)
85
+ raise exc if exc
86
+ rdh.first
87
+ end
88
+
89
+ # Create a new instance from the specified callbacks.
90
+ def from_callbacks(callbacks, hook_value = nil)
91
+ rdh = []
92
+ err = GPGME::gpgme_data_new_from_cbs(rdh, callbacks, hook_value)
93
+ exc = GPGME::error_to_exception(err)
94
+ raise exc if exc
95
+ rdh.first
96
+ end
97
+ end # class << self
98
+
99
+ # Read at most +length+ bytes from the data object, or to the end
100
+ # of file if +length+ is omitted or is +nil+.
101
+ #
102
+ # @example
103
+ # data = GPGME::Data.new("From a string")
104
+ # data.read # => "From a string"
105
+ #
106
+ # @example
107
+ # data = GPGME::Data.new("From a string")
108
+ # data.read(4) # => "From"
109
+ #
110
+ def read(length = nil)
111
+ if length
112
+ GPGME::gpgme_data_read(self, length)
113
+ else
114
+ buf = String.new
115
+ loop do
116
+ s = GPGME::gpgme_data_read(self, BLOCK_SIZE)
117
+ break unless s
118
+ buf << s
119
+ end
120
+ buf
121
+ end
122
+ end
123
+
124
+ ##
125
+ # Seek to a given +offset+ in the data object according to the
126
+ # value of +whence+.
127
+ #
128
+ # @example going to the beginning of the buffer after writing something
129
+ # data = GPGME::Data.new("Some data")
130
+ # data.read # => "Some data"
131
+ # data.read # => ""
132
+ # data.seek 0
133
+ # data.read # => "Some data"
134
+ #
135
+ def seek(offset, whence = IO::SEEK_SET)
136
+ GPGME::gpgme_data_seek(self, offset, IO::SEEK_SET)
137
+ end
138
+
139
+ ##
140
+ # Writes +length+ bytes from +buffer+ into the data object.
141
+ # Writes the full buffer if no length passed.
142
+ #
143
+ # @example
144
+ # data = GPGME::Data.new
145
+ # data.write "hola"
146
+ # data.seek 0
147
+ # data.read # => "hola"
148
+ #
149
+ # @example
150
+ # data = GPGME::Data.new
151
+ # data.write "hola", 2
152
+ # data.seek 0
153
+ # data.read # => "ho"
154
+ #
155
+ def write(buffer, length = buffer.length)
156
+ GPGME::gpgme_data_write(self, buffer, length)
157
+ end
158
+
159
+ ##
160
+ # Return the encoding of the underlying data.
161
+ def encoding
162
+ GPGME::gpgme_data_get_encoding(self)
163
+ end
164
+
165
+ ##
166
+ # Sets the encoding for this buffer. Accepts only values in one of the
167
+ # DATA_ENCODING_* constants.
168
+ #
169
+ # @raise [GPGME::Error::InvalidValue] if the value isn't accepted.
170
+ def encoding=(encoding)
171
+ err = GPGME::gpgme_data_set_encoding(self, encoding)
172
+ exc = GPGME::error_to_exception(err)
173
+ raise exc if exc
174
+ encoding
175
+ end
176
+
177
+ ##
178
+ # Return the entire content of the data object as string.
179
+ def to_s
180
+ pos = seek(0, IO::SEEK_CUR)
181
+ begin
182
+ seek(0)
183
+ read
184
+ ensure
185
+ seek(pos)
186
+ end
187
+ end
188
+ end
189
+ end