gpgme-ffi 3.0.0

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