added a function which tries to load the pub key
[edward.git] / edward
CommitLineData
0bec96d6 1#! /usr/bin/env python3
ff4136c7 2# -*- coding: utf-8 -*-
0bec96d6
AE
3"""*********************************************************************
4* Edward is free software: you can redistribute it and/or modify *
5* it under the terms of the GNU Affero Public License as published by *
6* the Free Software Foundation, either version 3 of the License, or *
7* (at your option) any later version. *
8* *
9* Edward is distributed in the hope that it will be useful, *
10* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12* GNU Affero Public License for more details. *
13* *
14* You should have received a copy of the GNU Affero Public License *
15* along with Edward. If not, see <http://www.gnu.org/licenses/>. *
16* *
17* Copyright (C) 2014-2015 Andrew Engelbrecht (AGPLv3+) *
18* Copyright (C) 2014 Josh Drake (AGPLv3+) *
19* Copyright (C) 2014 Lisa Marie Maginnis (AGPLv3+) *
8bdfb6d4
AE
20* Copyright (C) 2009-2015 Tails developers <tails@boum.org> ( GPLv3+) *
21* Copyright (C) 2009 W. Trevor King <wking@drexel.edu> ( GPLv2+) *
0bec96d6
AE
22* *
23* Special thanks to Josh Drake for writing the original edward bot! :) *
24* *
25************************************************************************
26
a5385c04 27Code sourced from these projects:
0bec96d6 28
8bdfb6d4
AE
29 * http://agpl.fsf.org/emailselfdefense.fsf.org/edward/CURRENT/edward.tar.gz
30 * https://git-tails.immerda.ch/whisperback/tree/whisperBack/encryption.py?h=feature/python3
31 * http://www.physics.drexel.edu/~wking/code/python/send_pgp_mime
0bec96d6
AE
32"""
33
34import sys
0bec96d6
AE
35import gpgme
36import re
37import io
40c37ab3 38import os
adcef2f7 39import importlib
0bec96d6 40
8bdfb6d4
AE
41import email.parser
42import email.message
43import email.encoders
44
45from email.mime.multipart import MIMEMultipart
46from email.mime.application import MIMEApplication
47from email.mime.nonmultipart import MIMENonMultipart
48
40c37ab3 49import edward_config
c96f3837 50
adcef2f7
AE
51langs = ["an", "de", "el", "en", "fr", "ja", "pt-br", "ro", "ru", "tr"]
52
38738401
AE
53match_types = [('clearsign',
54 '-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----'),
55 ('message',
56578eaf
AE
56 '-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----'),
57 ('pubkey',
58 '-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----'),
59 ('detachedsig',
38738401 60 '-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----')]
56578eaf
AE
61
62
63class EddyMsg (object):
64 def __init__(self):
65 self.multipart = False
66 self.subparts = []
67
68 self.charset = None
69 self.payload_bytes = None
70 self.payload_pieces = []
71
72 self.filename = None
73 self.content_type = None
74 self.description_list = None
75
76
77class PayloadPiece (object):
78 def __init__(self):
79 self.piece_type = None
80 self.string = None
81 self.gpg_data = None
82
83
38738401
AE
84class GPGData (object):
85 def __init__(self):
86 self.decrypted = False
87
88 self.plainobj = None
89 self.sigs = []
90 self.keys = []
91
d873ff48
AE
92class ReplyInfo (object):
93 def __init__(self):
94 self.replies = None
6906d46d
AE
95
96 self.target_key = None
97 self.fallback_target_key = None
d873ff48
AE
98 self.msg_to_quote = ""
99
100 self.success_decrypt = False
101 self.failed_decrypt = False
102 self.public_key_received = False
103 self.no_public_key = False
104 self.sig_success = False
105 self.sig_failure = False
106
38738401 107
0bec96d6
AE
108def main ():
109
20f6e7c5 110 handle_args()
0bec96d6 111
0a064403
AE
112 gpgme_ctx = get_gpg_context(edward_config.gnupghome,
113 edward_config.sign_with_key)
114
c96f3837 115 email_text = sys.stdin.read()
adcef2f7
AE
116 email_struct = parse_pgp_mime(email_text, gpgme_ctx)
117
118 email_to, email_from, email_subject = email_to_from_subject(email_text)
119 lang = import_lang(email_to)
fafa21c3 120
d873ff48
AE
121 replyinfo_obj = ReplyInfo()
122 replyinfo_obj.replies = lang.replies
123
124 prepare_for_reply(email_struct, replyinfo_obj)
013f7cb8 125 encrypt_to_key = get_key_from_fp(replyinfo_obj, gpgme_ctx)
d873ff48 126 reply_plaintext = write_reply(replyinfo_obj)
adcef2f7 127
adcef2f7 128 print(reply_plaintext)
6906d46d
AE
129 debug(replyinfo_obj.target_key)
130 debug(replyinfo_obj.fallback_target_key)
1fccb295 131
bf79a93e
AE
132# reply_mime = generate_encrypted_mime(plaintext, email_from, \
133# email_subject, encrypt_to_key,
134# gpgme_ctx)
c96f3837 135
0bec96d6 136
0a064403
AE
137def get_gpg_context (gnupghome, sign_with_key_fp):
138
139 os.environ['GNUPGHOME'] = gnupghome
140
141 gpgme_ctx = gpgme.Context()
142 gpgme_ctx.armor = True
143
144 try:
145 sign_with_key = gpgme_ctx.get_key(sign_with_key_fp)
146 except:
147 error("unable to load signing key. is the gnupghome "
148 + "and signing key properly set in the edward_config.py?")
149 exit(1)
150
151 gpgme_ctx.signers = [sign_with_key]
152
153 return gpgme_ctx
154
155
38738401 156def parse_pgp_mime (email_text, gpgme_ctx):
394a1476
AE
157
158 email_struct = email.parser.Parser().parsestr(email_text)
159
928e3819
AE
160 eddymsg_obj = parse_mime(email_struct)
161 split_payloads(eddymsg_obj)
162 gpg_on_payloads(eddymsg_obj, gpgme_ctx)
8bb4b0d5 163
928e3819 164 return eddymsg_obj
0bec96d6 165
0bec96d6 166
56578eaf 167def parse_mime(msg_struct):
0bec96d6 168
928e3819 169 eddymsg_obj = EddyMsg()
8bb4b0d5 170
56578eaf
AE
171 if msg_struct.is_multipart() == True:
172 payloads = msg_struct.get_payload()
0bec96d6 173
928e3819
AE
174 eddymsg_obj.multipart = True
175 eddymsg_obj.subparts = list(map(parse_mime, payloads))
dd11a483 176
56578eaf 177 else:
928e3819 178 eddymsg_obj = get_subpart_data(msg_struct)
394a1476 179
928e3819 180 return eddymsg_obj
c267c233 181
80119cab 182
56578eaf 183def scan_and_split (payload_piece, match_type, pattern):
cf75de65 184
a5d37d44
AE
185 # don't try to re-split pieces containing gpg data
186 if payload_piece.piece_type != "text":
187 return [payload_piece]
188
56578eaf
AE
189 flags = re.DOTALL | re.MULTILINE
190 matches = re.search("(?P<beginning>.*?)(?P<match>" + pattern +
191 ")(?P<rest>.*)", payload_piece.string, flags=flags)
86663388 192
56578eaf
AE
193 if matches == None:
194 pieces = [payload_piece]
c96f3837 195
56578eaf 196 else:
d437f8b2 197
56578eaf
AE
198 beginning = PayloadPiece()
199 beginning.string = matches.group('beginning')
200 beginning.piece_type = payload_piece.piece_type
d437f8b2 201
56578eaf
AE
202 match = PayloadPiece()
203 match.string = matches.group('match')
204 match.piece_type = match_type
d437f8b2 205
56578eaf
AE
206 rest = PayloadPiece()
207 rest.string = matches.group('rest')
208 rest.piece_type = payload_piece.piece_type
d437f8b2 209
56578eaf 210 more_pieces = scan_and_split(rest, match_type, pattern)
4615b156 211 pieces = [beginning, match ] + more_pieces
d437f8b2 212
56578eaf 213 return pieces
d437f8b2 214
d437f8b2 215
56578eaf 216def get_subpart_data (part):
0bec96d6 217
56578eaf 218 obj = EddyMsg()
0bec96d6 219
56578eaf
AE
220 obj.charset = part.get_content_charset()
221 obj.payload_bytes = part.get_payload(decode=True)
222
223 obj.filename = part.get_filename()
224 obj.content_type = part.get_content_type()
225 obj.description_list = part['content-description']
226
227 # your guess is as good as a-myy-ee-ine...
228 if obj.charset == None:
229 obj.charset = 'utf-8'
230
231 if obj.payload_bytes != None:
0eb75d9c
AE
232 try:
233 payload = PayloadPiece()
234 payload.string = obj.payload_bytes.decode(obj.charset)
235 payload.piece_type = 'text'
236
237 obj.payload_pieces = [payload]
238 except UnicodeDecodeError:
239 pass
56578eaf
AE
240
241 return obj
242
243
928e3819 244def do_to_eddys_pieces (function_to_do, eddymsg_obj, data):
56578eaf 245
928e3819
AE
246 if eddymsg_obj.multipart == True:
247 for sub in eddymsg_obj.subparts:
d873ff48 248 do_to_eddys_pieces(function_to_do, sub, data)
394a1476 249 else:
928e3819 250 function_to_do(eddymsg_obj, data)
dd11a483
AE
251
252
928e3819 253def split_payloads (eddymsg_obj):
a5d37d44
AE
254
255 for match_type in match_types:
928e3819 256 do_to_eddys_pieces(split_payload_pieces, eddymsg_obj, match_type)
a5d37d44 257
a5d37d44 258
928e3819 259def split_payload_pieces (eddymsg_obj, match_type):
a5d37d44
AE
260
261 (match_name, pattern) = match_type
262
263 new_pieces_list = []
928e3819 264 for piece in eddymsg_obj.payload_pieces:
a5d37d44
AE
265 new_pieces_list += scan_and_split(piece, match_name, pattern)
266
928e3819 267 eddymsg_obj.payload_pieces = new_pieces_list
a5d37d44
AE
268
269
928e3819 270def gpg_on_payloads (eddymsg_obj, gpgme_ctx, prev_parts=[]):
38738401 271
928e3819 272 if eddymsg_obj.multipart == True:
101d54a8 273 prev_parts=[]
928e3819 274 for sub in eddymsg_obj.subparts:
101d54a8
AE
275 gpg_on_payloads (sub, gpgme_ctx, prev_parts)
276 prev_parts += [sub]
38738401 277
d873ff48 278 return
38738401 279
928e3819 280 for piece in eddymsg_obj.payload_pieces:
38738401
AE
281
282 if piece.piece_type == "text":
283 # don't transform the plaintext.
284 pass
285
286 elif piece.piece_type == "message":
7e18f14d 287 (plaintext, sigs) = decrypt_block(piece.string, gpgme_ctx)
38738401
AE
288
289 if plaintext:
290 piece.gpg_data = GPGData()
b23e171d 291 piece.gpg_data.decrypted = True
38738401
AE
292 piece.gpg_data.sigs = sigs
293 # recurse!
294 piece.gpg_data.plainobj = parse_pgp_mime(plaintext, gpgme_ctx)
129543c3 295
8f61c66a 296 elif piece.piece_type == "pubkey":
f8ee6bd3 297 key_fps = add_gpg_key(piece.string, gpgme_ctx)
8f61c66a 298
f8ee6bd3 299 if key_fps != []:
8f61c66a 300 piece.gpg_data = GPGData()
f8ee6bd3 301 piece.gpg_data.keys = key_fps
129543c3
AE
302
303 elif piece.piece_type == "clearsign":
f8ee6bd3 304 (plaintext, sig_fps) = verify_clear_signature(piece.string, gpgme_ctx)
129543c3 305
f8ee6bd3 306 if sig_fps != []:
129543c3 307 piece.gpg_data = GPGData()
f8ee6bd3 308 piece.gpg_data.sigs = sig_fps
129543c3
AE
309 piece.gpg_data.plainobj = parse_pgp_mime(plaintext, gpgme_ctx)
310
101d54a8
AE
311 elif piece.piece_type == "detachedsig":
312 for prev in prev_parts:
313 payload_bytes = prev.payload_bytes
6d240f68 314 sig_fps = verify_detached_signature(piece.string, payload_bytes, gpgme_ctx)
101d54a8 315
6d240f68
AE
316 if sig_fps != []:
317 piece.gpg_data = GPGData()
318 piece.gpg_data.sigs = sig_fps
319 piece.gpg_data.plainobj = prev
320 break
7e18f14d 321
38738401
AE
322 else:
323 pass
324
325
928e3819 326def prepare_for_reply (eddymsg_obj, replyinfo_obj):
dd11a483 327
928e3819 328 do_to_eddys_pieces(prepare_for_reply_pieces, eddymsg_obj, replyinfo_obj)
56578eaf 329
013f7cb8
AE
330 if replyinfo_obj.target_key == None:
331 replyinfo_obj.target_key = replyinfo_obj.fallback_target_key
332
333 if replyinfo_obj.target_key == None:
334 replyinfo_obj.no_public_key = True
335
56578eaf 336
928e3819 337def prepare_for_reply_pieces (eddymsg_obj, replyinfo_obj):
56578eaf 338
928e3819 339 for piece in eddymsg_obj.payload_pieces:
38738401 340 if piece.piece_type == "text":
d873ff48
AE
341 # don't quote the plaintext part.
342 pass
343
38738401 344 elif piece.piece_type == "message":
d873ff48
AE
345 if piece.gpg_data == None:
346 replyinfo_obj.failed_decrypt = True
347 else:
348 replyinfo_obj.success_decrypt = True
d873ff48 349
6906d46d
AE
350 if replyinfo_obj.target_key != None:
351 continue
352 if piece.gpg_data.sigs != []:
353 replyinfo_obj.target_key = piece.gpg_data.sigs[0]
354 replyinfo_obj.msg_to_quote = flatten_payloads(piece.gpg_data.plainobj)
355
356 # to catch public keys in encrypted blocks
d873ff48
AE
357 prepare_for_reply(piece.gpg_data.plainobj, replyinfo_obj)
358
8f61c66a 359 elif piece.piece_type == "pubkey":
d873ff48
AE
360 if piece.gpg_data == None:
361 replyinfo_obj.no_public_key = True
362 else:
363 replyinfo_obj.public_key_received = True
364
365 elif (piece.piece_type == "clearsign") \
366 or (piece.piece_type == "detachedsig"):
367 if piece.gpg_data == None:
368 replyinfo_obj.sig_failure = True
369 else:
370 replyinfo_obj.sig_success = True
371
6906d46d
AE
372 if replyinfo_obj.target_key == None:
373 replyinfo_obj.fallback_target_key = piece.gpg_data.sigs[0]
374
375
d873ff48 376
928e3819 377def flatten_payloads (eddymsg_obj):
d873ff48
AE
378
379 flat_string = ""
380
0aa88c27
AE
381 if eddymsg_obj == None:
382 return ""
383
928e3819
AE
384 if eddymsg_obj.multipart == True:
385 for sub in eddymsg_obj.subparts:
d873ff48
AE
386 flat_string += flatten_payloads (sub)
387
388 return flat_string
389
6906d46d 390 # todo: don't include nested decrypted messages.
928e3819 391 for piece in eddymsg_obj.payload_pieces:
d873ff48
AE
392 if piece.piece_type == "text":
393 flat_string += piece.string
0aa88c27
AE
394 elif piece.piece_type == "message":
395 flat_string += flatten_payloads(piece.plainobj)
396 elif ((piece.piece_type == "clearsign") \
397 or (piece.piece_type == "detachedsig")) \
398 and (piece.gpg_data != None):
399 flat_string += flatten_payloads (piece.gpg_data.plainobj)
400
d873ff48
AE
401
402 return flat_string
403
404
013f7cb8
AE
405def get_key_from_fp (replyinfo_obj, gpgme_ctx):
406
407 if replyinfo_obj.target_key != None:
408 try:
409 encrypt_to_key = gpgme_ctx.get_key(replyinfo_obj.target_key)
410 return encrypt_to_key
411
412 except:
413 pass
414
415 # no available key to use
416 replyinfo_obj.target_key = None
417 replyinfo_obj.fallback_target_key = None
418
419 replyinfo_obj.no_public_key = True
420 replyinfo_obj.public_key_received = False
421
422 return None
423
424
d873ff48
AE
425def write_reply (replyinfo_obj):
426
427 reply_plain = ""
428
429 if replyinfo_obj.success_decrypt == True:
430 quoted_text = email_quote_text(replyinfo_obj.msg_to_quote)
431 reply_plain += replyinfo_obj.replies['success_decrypt']
432 reply_plain += quoted_text
433
434 elif replyinfo_obj.failed_decrypt == True:
435 reply_plain += replyinfo_obj.replies['failed_decrypt']
436
437
438 if replyinfo_obj.sig_success == True:
439 reply_plain += "\n\n"
440 reply_plain += replyinfo_obj.replies['sig_success']
441
442 elif replyinfo_obj.sig_failure == True:
443 reply_plain += "\n\n"
444 reply_plain += replyinfo_obj.replies['sig_failure']
445
446
447 if replyinfo_obj.public_key_received == True:
448 reply_plain += "\n\n"
449 reply_plain += replyinfo_obj.replies['public_key_received']
450
451 elif replyinfo_obj.no_public_key == True:
452 reply_plain += "\n\n"
453 reply_plain += replyinfo_obj.replies['no_public_key']
454
455
456 reply_plain += "\n\n"
457 reply_plain += replyinfo_obj.replies['signature']
56578eaf 458
d873ff48 459 return reply_plain
56578eaf
AE
460
461
8f61c66a 462def add_gpg_key (key_block, gpgme_ctx):
c267c233 463
8f61c66a 464 fp = io.BytesIO(key_block.encode('ascii'))
c267c233 465
8f61c66a
AE
466 result = gpgme_ctx.import_(fp)
467 imports = result.imports
c267c233 468
f8ee6bd3 469 key_fingerprints = []
c267c233 470
8f61c66a
AE
471 if imports != []:
472 for import_ in imports:
473 fingerprint = import_[0]
f8ee6bd3 474 key_fingerprints += [fingerprint]
c267c233 475
e49673aa 476 debug("added gpg key: " + fingerprint)
ec1e779a 477
f8ee6bd3 478 return key_fingerprints
ec1e779a
AE
479
480
129543c3 481def verify_clear_signature (sig_block, gpgme_ctx):
cf75de65 482
129543c3
AE
483 # FIXME: this might require the un-decoded bytes
484 # or the correct re-encoding with the carset of the mime part.
485 msg_fp = io.BytesIO(sig_block.encode('utf-8'))
486 ptxt_fp = io.BytesIO()
cf75de65 487
129543c3 488 result = gpgme_ctx.verify(msg_fp, None, ptxt_fp)
cf75de65 489
129543c3
AE
490 # FIXME: this might require using the charset of the mime part.
491 plaintext = ptxt_fp.getvalue().decode('utf-8')
cf75de65 492
f8ee6bd3 493 sig_fingerprints = []
129543c3 494 for res_ in result:
f8ee6bd3 495 sig_fingerprints += [res_.fpr]
cf75de65 496
f8ee6bd3 497 return plaintext, sig_fingerprints
cf75de65
AE
498
499
101d54a8
AE
500def verify_detached_signature (detached_sig, plaintext_bytes, gpgme_ctx):
501
502 detached_sig_fp = io.BytesIO(detached_sig.encode('ascii'))
503 plaintext_fp = io.BytesIO(plaintext_bytes)
504 ptxt_fp = io.BytesIO()
505
506 result = gpgme_ctx.verify(detached_sig_fp, plaintext_fp, None)
507
508 sig_fingerprints = []
509 for res_ in result:
510 sig_fingerprints += [res_.fpr]
511
512 return sig_fingerprints
513
514
5b3053c1 515def decrypt_block (msg_block, gpgme_ctx):
0bec96d6 516
5b3053c1 517 block_b = io.BytesIO(msg_block.encode('ascii'))
0bec96d6
AE
518 plain_b = io.BytesIO()
519
afc1f64c
AE
520 try:
521 sigs = gpgme_ctx.decrypt_verify(block_b, plain_b)
522 except:
523 return ("",[])
0bec96d6 524
6aa41372 525 plaintext = plain_b.getvalue().decode('utf-8')
cbdf22c1
AE
526
527 fingerprints = []
528 for sig in sigs:
529 fingerprints += [sig.fpr]
530 return (plaintext, fingerprints)
0bec96d6
AE
531
532
d0489345 533def choose_reply_encryption_key (gpgme_ctx, fingerprints):
fafa21c3
AE
534
535 reply_key = None
d0489345
AE
536 for fp in fingerprints:
537 try:
538 key = gpgme_ctx.get_key(fp)
539
540 if (key.can_encrypt == True):
541 reply_key = key
542 break
543 except:
544 continue
545
fafa21c3 546
216708e9 547 return reply_key
fafa21c3
AE
548
549
d65993b8
AE
550def email_to_from_subject (email_text):
551
552 email_struct = email.parser.Parser().parsestr(email_text)
553
554 email_to = email_struct['To']
555 email_from = email_struct['From']
556 email_subject = email_struct['Subject']
557
558 return email_to, email_from, email_subject
559
560
adcef2f7
AE
561def import_lang(email_to):
562
5250b3b8
AE
563 if email_to != None:
564 for lang in langs:
565 if "edward-" + lang in email_to:
566 lang = "lang." + re.sub('-', '_', lang)
567 language = importlib.import_module(lang)
adcef2f7 568
5250b3b8 569 return language
adcef2f7
AE
570
571 return importlib.import_module("lang.en")
572
573
bf79a93e 574def generate_encrypted_mime (plaintext, email_from, email_subject, encrypt_to_key,
0a064403 575 gpgme_ctx):
1da9b527 576
8bdfb6d4 577
1da9b527
AE
578 reply = "To: " + email_from + "\n"
579 reply += "Subject: " + email_subject + "\n"
216708e9
AE
580
581 if (encrypt_to_key != None):
582 plaintext_reply = "thanks for the message!\n\n\n"
583 plaintext_reply += email_quote_text(plaintext)
584
8bdfb6d4
AE
585 # quoted printable encoding lets most ascii characters look normal
586 # before the decrypted mime message is decoded.
587 char_set = email.charset.Charset("utf-8")
588 char_set.body_encoding = email.charset.QP
589
590 # MIMEText doesn't allow setting the text encoding
591 # so we use MIMENonMultipart.
592 plaintext_mime = MIMENonMultipart('text', 'plain')
593 plaintext_mime.set_payload(plaintext_reply, charset=char_set)
594
595 encrypted_text = encrypt_sign_message(plaintext_mime.as_string(),
596 encrypt_to_key,
40c37ab3 597 gpgme_ctx)
8bdfb6d4
AE
598
599 control_mime = MIMEApplication("Version: 1",
600 _subtype='pgp-encrypted',
601 _encoder=email.encoders.encode_7or8bit)
602 control_mime['Content-Description'] = 'PGP/MIME version identification'
603 control_mime.set_charset('us-ascii')
604
605 encoded_mime = MIMEApplication(encrypted_text,
606 _subtype='octet-stream; name="encrypted.asc"',
607 _encoder=email.encoders.encode_7or8bit)
608 encoded_mime['Content-Description'] = 'OpenPGP encrypted message'
609 encoded_mime['Content-Disposition'] = 'inline; filename="encrypted.asc"'
610 encoded_mime.set_charset('us-ascii')
611
612 message_mime = MIMEMultipart(_subtype="encrypted", protocol="application/pgp-encrypted")
613 message_mime.attach(control_mime)
614 message_mime.attach(encoded_mime)
615 message_mime['Content-Disposition'] = 'inline'
216708e9 616
8bdfb6d4 617 reply += message_mime.as_string()
216708e9
AE
618
619 else:
8bdfb6d4 620 reply += "\n"
216708e9
AE
621 reply += "Sorry, i couldn't find your key.\n"
622 reply += "I'll need that to encrypt a message to you."
1da9b527
AE
623
624 return reply
625
626
f87041f8
AE
627def email_quote_text (text):
628
629 quoted_message = re.sub(r'^', r'> ', text, flags=re.MULTILINE)
630
631 return quoted_message
632
633
0a064403 634def encrypt_sign_message (plaintext, encrypt_to_key, gpgme_ctx):
897cbaf6 635
6aa41372 636 plaintext_bytes = io.BytesIO(plaintext.encode('ascii'))
1da9b527
AE
637 encrypted_bytes = io.BytesIO()
638
897cbaf6 639 gpgme_ctx.encrypt_sign([encrypt_to_key], gpgme.ENCRYPT_ALWAYS_TRUST,
1da9b527
AE
640 plaintext_bytes, encrypted_bytes)
641
6aa41372 642 encrypted_txt = encrypted_bytes.getvalue().decode('ascii')
1da9b527
AE
643 return encrypted_txt
644
645
0a064403
AE
646def error (error_msg):
647
e4fb2ab2 648 sys.stderr.write(progname + ": " + str(error_msg) + "\n")
0a064403
AE
649
650
5e8f9094
AE
651def debug (debug_msg):
652
653 if edward_config.debug == True:
0a064403 654 error(debug_msg)
5e8f9094
AE
655
656
20f6e7c5
AE
657def handle_args ():
658 if __name__ == "__main__":
659
660 global progname
661 progname = sys.argv[0]
662
663 if len(sys.argv) > 1:
664 print(progname + ": error, this program doesn't " \
665 "need any arguments.", file=sys.stderr)
666 exit(1)
667
668
0bec96d6
AE
669main()
670