1<?php 2 3///////////////////////////////////////////////////////////////////////////// 4// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 5// 6// All Rights Reserved. See copyright.txt for details and a complete list of authors. 7// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 8// 9// PURPOSE: 10// A brief OpenPGP support class for Tiki OpenPGP functionality in 11// - webmail 12// - ZF based mail 13// - newsletters 14// - admin notifications 15// 16// 17// 18// CHANGE HISTORY: 19// v0.10 20// 2012-11-04 hollmeer: Collected all functions into intial version openpgplib.php. 21// Minimal preparation/calling portions remain in caller sources, 22// as it seems so far adequate with current approch to leave 23// such portions e.g. there 24// NOTE: Zend Framework as is wrapped by bringing/changing 25// necessary classes from 26// Zend/Mail/ and 27// Zend/Mail/Transport/ 28// into lib/openpgp/ per now. No patches needed anymore 29// into ZF to enable 100% PGP/MIME encryption. 30// v0.11 31// 2014-11-04 hollmeer: Protected function naming to _xxxx 32// v0.12 33// 2014-12-01 hollmeer: Changed all OpenGPG functionality configuration to use 34// preferences 35// 36// 37// 38///////////////////////////////////////////////////////////////////////////// 39 40 41//this script may only be included - so its better to die if called directly. 42if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) { 43 header("location: index.php"); 44 exit; 45} 46 47class OpenPGPLib 48{ 49 50 //PGP/MIME HEADER CONSTANTS 51 const MULTIPART_PGP_ENCRYPTED = 'multipart/encrypted'; 52 const TYPE_PGP_PROTOCOL = 'application/pgp-encrypted'; 53 const PGP_MIME_NOTE = 'This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)'; 54 const TYPE_PGP_CONTENT_VERSION = 'application/pgp-encrypted'; 55 const DESCRIPTION_PGP_CONTENT_VERSION = 'PGP/MIME version identification'; 56 const PGP_MIME_VERSION_IDENTIFICATION = 'Version: 1'; 57 const TYPE_PGP_CONTENT_ENCRYPTED = 'application/octet-stream; name="encrypted.asc"'; 58 const DESCRIPTION_PGP_CONTENT_ENCRYPTED = 'OpenPGP encrypted message'; 59 const DISPOSITION_PGP_CONTENT_INLINE = 'inline; filename="encrypted.asc"'; 60 61 /** 62 * EOL character string used by transport 63 * @var string 64 * @access public 65 */ 66 private $EOL = "\n"; 67 68 69 /** 70 * Full path to gpg 71 * @var string 72 * @access protected 73 */ 74 private $_gpg_path; 75 76 /** 77 * Full path to keyring directory 78 * @var string 79 * @access protected 80 */ 81 private $_gpg_home; 82 83 /** 84 * gpg signer idfile 85 * @var string 86 * @access protected 87 */ 88 private $_gpg_sgn_id; 89 90 /** 91 * gpg signer passphrase 92 * @var string 93 * @access protected 94 */ 95 private $_gpg_sgn_passphrase; 96 97 /** 98 * gpg signer full passfile path 99 * @var string 100 * @access protected 101 */ 102 private $_gpg_sgn_passfile_path; 103 104 /** 105 * gpg trust 106 * depending on which version of GnuPG we're using there 107 * are two different ways to specify "always trust" 108 * @var string 109 * @access protected 110 */ 111 private $_gpg_trust; 112 113 /** 114 * Constructor function. Set initial defaults. 115 */ 116 function __construct() 117 { 118 global $prefs,$tiki_p_admin; 119 120 $this->_gpg_path = $prefs['openpgp_gpg_path']; 121 $this->_gpg_home = $prefs['openpgp_gpg_home']; 122 $this->_gpg_sgn_id = $prefs['sender_email']; 123 if ($prefs['openpgp_gpg_signer_passphrase_store'] == 'file') { 124 $this->_gpg_sgn_passfile_path = $prefs['openpgp_gpg_signer_passfile']; 125 $this->_gpg_sgn_passphrase = ''; 126 } else { 127 $this->_gpg_sgn_passfile_path = ''; 128 $this->_gpg_sgn_passphrase = $prefs['openpgp_gpg_signer_passphrase']; 129 } 130 $this->_gpg_trust = ''; 131 132 $this->setCrlf(); 133 } 134 135 /** 136 * Accessor to set the CRLF style 137 */ 138 function setCrlf($crlf = "\n") 139 { 140 if (! defined('CRLF')) { 141 define('CRLF', $crlf, true); 142 } 143 144 if (! defined('MAIL_MIMEPART_CRLF')) { 145 define('MAIL_MIMEPART_CRLF', $crlf, true); 146 } 147 } 148 149 /** 150 * Gnupg version check; sets internal variable once 151 * 152 * @access protected 153 * @return void 154 */ 155 protected function _gpg_check_version() 156 { 157 158 ////////////////////////////////////////// 159 // find which version of GnuPG we're using 160 ////////////////////////////////////////// 161 162 /////////////////////////////// 163 // open the GnuPG process and get the reply 164 // we're only concerned with the first line of output, so use "false" as last argument 165 $commandline = $this->_gpg_path 166 . ' --version'; 167 $ret = $this->_gpg_exec_proc($commandline, null, false); 168 169 ///////////////////////////////////////////////////// 170 // get the version (we are only concerned with the first line of output, 171 // which was read from gpg-process-output as single-line-read into $ret[1] 172 $gpg_version_output = $ret[0]; 173 174 /////////////////////////////////////////////// 175 // sanity check - see if we're working with gpg 176 if (preg_match('/^gpg /', $gpg_version_output) == 0) { 177 $error_msg = 'gpg executable is not GnuPG: "' . $this->_gpg_path . '"'; 178 trigger_error($error_msg, E_USER_ERROR); 179 // if an error message directs you to the line above please 180 // double check that your path to gpg is really GnuPG 181 die(); 182 } 183 184 ///////////////////////////////////////////////////////////// 185 // pick the version number out of $gpg_encrypt_version_output 186 // we'll need this so we can determine the correct 187 // way to tell GnuPG how to "always trust" 188 $gpg_gpg_version = preg_replace('/^.* /', '', $gpg_version_output); 189 190 //////////////////////////////////////////////////////// 191 // depending on which version of GnuPG we're using there 192 // are two different ways to specify "always trust" 193 if ("$gpg_gpg_version" < '1.2.3') { 194 $this->_gpg_trust = '--always-trust'; // the old way 195 } else { 196 $this->_gpg_trust = '--trust-model always'; // the new way 197 } 198 199 ///////////////////////////////////////////// 200 // unset variables that we don't need anymore 201 unset( 202 $gpg_version_output, 203 $gpg_gpg_version, 204 $commandline 205 ); 206 207 //////////////////////////////////////// 208 // we're done checking the GnuPG version 209 //////////////////////////////////////// 210 return; 211 } 212 213 /** 214 * Gnupg process call function 215 * 216 * @param string $gpg_proc_call 217 * @param string $gpg_proc_input 218 * @param boolean $read_multilines 219 * @access protected 220 * @return array 221 * 0 => process call output (STDOUT) 222 * 1 => warnings and notices (STDERR) 223 * 2 => exit status 224 */ 225 protected function _gpg_exec_proc($gpg_proc_call = '', $gpg_proc_input = null, $read_multilines = true) 226 { 227 228 if ($gpg_proc_call == '') { 229 die; 230 } 231 232 ////////////////////////////////////////////// 233 // set up pipes for handling I/O to/from GnuPG 234 $gpg_descriptorspec = [ 235 0 => ["pipe", "r"], // STDIN is a pipe that GnuPG will read from 236 1 => ["pipe", "w"], // STDOUT is a pipe that GnuPG will write to 237 2 => ["pipe", "w"] // STDERR is a pipe that GnuPG will write to 238 ]; 239 240 /////////////////////////////// 241 // this opens the GnuPG process 242 $gpg_process = proc_open( 243 $gpg_proc_call, 244 $gpg_descriptorspec, 245 $gpg_pipes 246 ); 247 248 ////////////////////////////////////////////////////////////////// 249 // this writes the "$gpg_encrypt_secret_message" to GnuPG on STDIN 250 if (is_resource($gpg_process)) { 251 if ($gpg_proc_input != null) { 252 fwrite($gpg_pipes[0], $gpg_proc_input); 253 } 254 fclose($gpg_pipes[0]); 255 256 ///////////////////////////////////////////////////////// 257 // this reads the output from GnuPG from STDOUT 258 $gpg_proc_output = ''; 259 if ($read_multilines) { 260 while (! feof($gpg_pipes[1])) { 261 $gpg_proc_output .= fgets($gpg_pipes[1], 1024); 262 } 263 fclose($gpg_pipes[1]); 264 } else { 265 $gpg_proc_output = fgets($gpg_pipes[1], 1024); 266 } 267 268 ///////////////////////////////////////////////////////// 269 // this reads warnings and notices from GnuPG from STDERR 270 $gpg_error_message = ''; 271 while (! feof($gpg_pipes[2])) { 272 $gpg_error_message .= fgets($gpg_pipes[2], 1024); 273 } 274 fclose($gpg_pipes[2]); 275 276 ///////////////////////////////////////// 277 // this collects the exit status of GnuPG 278 $gpg_exit_status = proc_close($gpg_process); 279 280 //////////////////////////////////////////// 281 // unset variables that are no longer needed 282 // and can only cause trouble 283 unset( 284 $gpg_descriptorspec, 285 $gpg_process, 286 $gpg_pipes 287 ); 288 289 //////////////////////////////////// 290 // this returns an array containing: 291 // [0] encrypted output (STDOUT) 292 // [1] warnings and notices (STDERR) 293 // [2] exit status 294 return [$gpg_proc_output, $gpg_error_message, $gpg_exit_status]; 295 } else { 296 //////////////////////////////////////////// 297 // unset variables that are no longer needed 298 // and can only cause trouble 299 unset( 300 $gpg_descriptorspec, 301 $gpg_process, 302 $gpg_pipes 303 ); 304 305 ////////////////////////////// 306 // set output as otherwise nothing 307 $gpg_proc_output = ''; 308 $gpg_error_message = 'Fatal process call error: Process call failed!'; 309 $gpg_exit_status = 99; 310 return [$gpg_proc_output, $gpg_error_message, $gpg_exit_status]; 311 } 312 } 313 314 315 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 316 // 317 // Encryption function; encrypts & signs the message 318 // 319 // usage: 320 // array gpg_encrypt(secret-message, recipients); 321 // 322 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 323 324 /** 325 * Encryption function; encrypts & signs the message 326 * 327 * @param string $secret-message 328 * @param array/string $recipients 329 * @access public 330 * @return array 331 * 0 => encrypted message output (STDOUT) 332 * 1 => warnings and notices (STDERR) 333 * 2 => exit status 334 */ 335 function gpg_encrypt() 336 { 337 338 global $prefs; 339 340 ////////////////////////////////////////////////////////// 341 // sanity check - make sure there are at least 2 arguments 342 // any extra arguments are considered to be additional key IDs 343 if (func_num_args() < 2) { 344 trigger_error("gpg_encrypt() requires at least 2 arguments", E_USER_ERROR); 345 // if an error message directs you to the line above please 346 // double check that you are providing at least 2 arguments 347 die(); 348 } 349 350 //////////////////////////////// 351 // assign arguments to variables 352 $gpg_args = func_get_args(); 353 $gpg_secret_message = array_shift($gpg_args); // 1st argument - secret message; let the gpg process to deal with empty/faulty content 354 355 /////////////////////////////////////////////////////////////////////// 356 // make sure that each recipient has the message encrypted to their key 357 // the 2nd argument, and any subsequent arguments, are key IDs 358 $gpg_recipient_list = ''; 359 foreach ($gpg_args as $gpg_recipient) { 360 if (is_array($gpg_recipient)) { 361 foreach ($gpg_recipient as &$item) { 362 $gpg_recipient_list .= ' -r ' . $item; 363 } 364 } else { 365 $gpg_recipient_list .= " -r ${gpg_recipient}"; 366 } 367 } 368 369 ////////////////////////////////////////// 370 // find which version of GnuPG we're using 371 ////////////////////////////////////////// 372 if ($this->_gpg_trust == '') { 373 $this->_gpg_check_version(); 374 } 375 376 /////////////////////////////// 377 // open the GnuPG process and get the reply 378 $commandline = ''; 379 if ($prefs['openpgp_gpg_signer_passphrase_store'] == 'file') { 380 // get signer-key passphrase from a file 381 $commandline .= $this->_gpg_path 382 . ' --no-random-seed-file' 383 . ' --homedir ' . $this->_gpg_home 384 . ' ' . $this->_gpg_trust 385 . ' --batch' 386 . ' --local-user ' . $this->_gpg_sgn_id 387 . ' --passphrase-file ' . $this->_gpg_sgn_passfile_path 388 . ' -sea ' . $gpg_recipient_list 389 . ' '; 390 } else { 391 // get signer-key passphrase from preferences 392 $commandline .= $this->_gpg_path 393 . ' --no-random-seed-file' 394 . ' --homedir ' . $this->_gpg_home 395 . ' ' . $this->_gpg_trust 396 . ' --batch' 397 . ' --local-user ' . $this->_gpg_sgn_id 398 . ' --passphrase ' . $this->_gpg_sgn_passphrase 399 . ' -sea ' . $gpg_recipient_list 400 . ' '; 401 } 402 $ret = $this->_gpg_exec_proc($commandline, $gpg_secret_message); 403 404 unset( 405 $gpg_args, 406 $gpg_secret_message, 407 $gpg_recipient_list, 408 $commandline 409 ); 410 411 //////////////////////////////////// 412 // this returns an array containing: 413 // [0] encrypted output (STDOUT) 414 // [1] warnings and notices (STDERR) 415 // [2] exit status 416 return $ret; 417 } 418 419 ///////////////////////////////////////////////////////////// 420 // 421 // Get the public-key fingerprint for a key associated with the ID 422 // 423 ///////////////////////////////////////////////////////////// 424 425 /** 426 * Get public-key fingerprint 427 * 428 * @param string $gpg_key_id 429 * @access public 430 * @return array 431 * 0 => public key gingerprint output (STDOUT) 432 * 1 => warnings and notices (STDERR) 433 * 2 => exit status 434 */ 435 function gpg_getFingerprint($gpg_key_id = null) 436 { 437 438 ////////////////////////////////////////////////////////// 439 // sanity check - make sure there is 1 argument 440 if ($gpg_key_id == null) { 441 trigger_error("gpg_getFingerprint() requires 1 argument", E_USER_ERROR); 442 // if an error message directs you to the line above please 443 // double check that you are providing 1 argument 444 die(); 445 } 446 447 /////////////////////////////////////////////////////////////////////// 448 // the argument is key ID; if array, accept only the first 449 $gpg_key_id_to_return = ''; 450 if (is_array($gpg_key_id)) { 451 foreach ($gpg_key_id as &$item) { 452 $gpg_key_id_to_return .= $item; 453 break; 454 } 455 } else { 456 $gpg_key_id_to_return .= $gpg_key_id; 457 } 458 459 ////////////////////////////////////////// 460 // find which version of GnuPG we're using 461 ////////////////////////////////////////// 462 if ($this->_gpg_trust == '') { 463 $this->_gpg_check_version(); 464 } 465 466 /////////////////////////////// 467 // open the GnuPG process and get the reply 468 $commandline = $this->_gpg_path 469 . ' --homedir ' . $this->_gpg_home 470 . ' ' . $this->_gpg_trust 471 . ' --fingerprint' 472 . ' --list-sigs ' . $gpg_key_id_to_return 473 . ' '; 474 $ret = $this->_gpg_exec_proc($commandline); 475 476 unset( 477 $gpg_key_id_to_return, 478 $commandline 479 ); 480 481 //////////////////////////////////// 482 // this returns an array containing: 483 // [0] fingerprint output (STDOUT) 484 // [1] warnings and notices (STDERR) 485 // [2] exit status 486 return $ret; 487 } 488 489 ////////////////////////////////////////////////////////////////////////////// 490 // 491 // Get the public-key ascii-armor-block for a key associated with the ID 492 // 493 ////////////////////////////////////////////////////////////////////////////// 494 495 /** 496 * Get public-key ascii armor block 497 * 498 * @param string $gpg_key_id 499 * @access public 500 * @return array 501 * 0 => public key armor output (STDOUT) 502 * 1 => warnings and notices (STDERR) 503 * 2 => exit status 504 */ 505 function gpg_getPublicKey($gpg_key_id = null) 506 { 507 508 ////////////////////////////////////////////////////////// 509 // sanity check - make sure there is 1 argument 510 if ($gpg_key_id == null) { 511 trigger_error("gpg_getPublicKey() requires 1 argument", E_USER_ERROR); 512 // if an error message directs you to the line above please 513 // double check that you are providing 1 argument 514 die(); 515 } 516 517 /////////////////////////////////////////////////////////////////////// 518 // the argument is key ID; if array, accept only the first 519 $gpg_key_id_to_return = ''; 520 if (is_array($gpg_key_id)) { 521 foreach ($gpg_key_id as &$item) { 522 $gpg_key_id_to_return .= $item; 523 break; 524 } 525 } else { 526 $gpg_key_id_to_return .= $gpg_key_id; 527 } 528 529 ////////////////////////////////////////// 530 // find which version of GnuPG we're using 531 ////////////////////////////////////////// 532 if ($this->_gpg_trust == '') { 533 $this->_gpg_check_version(); 534 } 535 536 /////////////////////////////// 537 // open the GnuPG process and get the reply 538 $commandline = $this->_gpg_path 539 . ' --homedir ' . $this->_gpg_home 540 . ' ' . $this->_gpg_trust 541 . ' --export --armor ' . $gpg_key_id_to_return 542 . ' '; 543 $ret = $this->_gpg_exec_proc($commandline); 544 545 unset( 546 $gpg_key_id_to_return, 547 $commandline 548 ); 549 550 //////////////////////////////////// 551 // this returns an array containing: 552 // [0] public key armor output (STDOUT) 553 // [1] warnings and notices (STDERR) 554 // [2] exit status 555 return $ret; 556 } 557 558 ///////////////////////////////////////////////////////////////// 559 // 560 // MESSAGE COMPOSING 561 // 562 ///////////////////////////////////////////////////////////////// 563 564 /** 565 * ALPHAFIELDS 2012-01-08: added to retrieve admin email public key armor block 566 * Returns the contact users' email or empty 567 * 568 * @access public 569 * @return string (contact users' email or empty) 570 */ 571 function get_admin_email_for_armor_block() 572 { 573 global $user, $prefs, $tikilib; 574 $empty = ''; 575 return isset($prefs['sender_email']) ? $prefs['sender_email'] : $empty; 576 } 577 578 ///////////////////////////////////////////////////////////////////////////// 579 /** 580 * Function to get publickey ascii-armor-block and original headers into body 581 * 582 * @param string $req_priority 583 * @param string $req_to 584 * @param string $req_cc 585 * @access public 586 * @return array 587 * 0 => $prepend_email_body 588 * 1 => $user_armor 589 */ 590 function getPublickeyArmorBlock($req_priority, $req_to, $req_cc) 591 { 592 593 global $user; 594 $userlib = TikiLib::lib('user'); 595 596 // get user email for publickey armor block retrieval 597 $user_email = ''; 598 if ($user != 'admin') { 599 $user_email = $userlib->get_user_email($user); 600 } else { 601 // NOTE: This function is in this lib-class, not in $userlib! 602 $user_email = $this->get_admin_email_for_armor_block(); 603 } 604 $user_armor = ''; 605 if ($user_email) { 606 //retrieve armor block for keyid 607 $gpg = $this->gpg_getPublicKey($user_email); 608 // $gpg is an array containing 609 // $gpg[0] armor output (STDOUT) 610 // $gpg[1] warnings and notices (STDERR) 611 // $gpg[2] exit status from gpg 612 613 // test gpg's exit status 614 if ("$gpg[2]" == '0') { 615 // if the gpg command returned zero 616 $user_armor = "\n\n--original sender public key below--\n\n" . $gpg[0]; 617 } else { 618 // if the gpg command returned non-zero 619 $error_msg = 'OpenPGPLib: _getPublickeyArmorBlock() returned error code: ' . $gpg[2]; 620 trigger_error($error_msg, E_USER_ERROR); 621 // if an error message directs you to the line above please 622 // double check that your gnupg-configuration, process-call commandline input, and other parameters are correct 623 } 624 // TODO: hardcoded addresses into preferences from db 625 $gpg = $this->gpg_getFingerprint($user_email); 626 // $gpg is an array containing 627 // $gpg[0] fingerprint (STDOUT) 628 // $gpg[1] warnings and notices (STDERR) 629 // $gpg[2] exit status from gpg 630 631 // test gpg's exit status 632 if ("$gpg[2]" == '0') { 633 // if the gpg command returned zero 634 $user_armor = $user_armor . "\n-----fingerprint data below-------\n\n" . $gpg[0] 635 . "\n----------------------------------\n\n"; 636 } else { 637 // if the gpg command returned non-zero 638 $error_msg = 'OpenPGPLib: _getPublickeyArmorBlock() returned error code: ' . $gpg[2]; 639 trigger_error($error_msg, E_USER_ERROR); 640 // if an error message directs you to the line above please 641 // double check that your gnupg-configuration, process-call commandline input, and other parameters are correct 642 } 643 } 644 // generate a message has ID to be used as a consistent message referenceID across all recipients 645 // and prepend it into message body 646 $tmpstr = chunk_split(md5(rand() . microtime()), 8, '-'); 647 $tmpstr = substr($tmpstr, 0, strlen($tmpstr) - 1); 648 $prepend_email_body = "ID: " 649 . $tmpstr 650 . " (use this for message reference)\n" 651 . "Prio: " . $req_priority . "\n" 652 . "From: " . $user . " (" . $user_email . ")\n" 653 . "To: " . $req_to . "\n" 654 . "Cc: " . $req_cc . "\n\n"; 655 656 return [$prepend_email_body,$user_armor]; 657 } 658 659 ///////////////////////////////////////////////////////////////// 660 // 661 // WEBMAIL/htmlMimeMail GNUPG-ENCRYPTED PGP/MIME MAIL FUNCTIONS 662 // 663 ///////////////////////////////////////////////////////////////// 664 665 ///////////////////////////////////////////////////////////////// 666 /** 667 * Function to encode a header if necessary 668 * according to RFC2047 669 */ 670 function _encodeHeader($input, $charset = 'ISO-8859-1') 671 { 672 preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches); 673 674 foreach ($matches[1] as $value) { 675 $replacement = preg_replace_callback('/([\\x80-\\xFF])/', function ($match) { 676 return "=" . strtoupper(dechex(ord($match[1]))); 677 }, $value); 678 679 $input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input); 680 } 681 682 return $input; 683 } 684 685 686 ///////////////////////////////////////////////////////////////// 687 /** 688 * Send a message to a user with gpg-armor block etc included 689 * A changed encryption-related version was copied/changed from lib/messu/messulib.pgp 690 * into lib/openpgp/openpgplib.php for prepending/appending content into 691 * message body 692 693 * @param string $user 694 * @param string $from 695 * @param string $to 696 * @param string $cc 697 * @param string $subject 698 * @param string $body 699 * @param string $prepend_email_body 700 * @param string $user_pubkeyarmor 701 * @param string $priority 702 * @param string $replyto_hash 703 * @param string $replyto_email 704 * @param string $bcc_sender 705 * @access public 706 * @return boolean true/false 707 */ 708 function post_message_with_pgparmor_attachment( 709 $user, 710 $from, 711 $to, 712 $cc, 713 $subject, 714 $body, 715 $prepend_email_body, 716 // NOTE this 717 $user_pubkeyarmor, 718 // NOTE this 719 $priority, 720 $replyto_hash = '', 721 $replyto_email = '', 722 $bcc_sender = '' 723 ) { 724 725 global $prefs; 726 $userlib = TikiLib::lib('user'); 727 $tikilib = TikiLib::lib('tiki'); 728 $smarty = TikiLib::lib('smarty'); 729 730 $subject = strip_tags($subject); 731 $body = strip_tags($body, '<a><b><img><i>'); 732 // Prevent duplicates 733 $hash = md5($subject . $body); 734 735 if ($tikilib->getOne("select count(*) from `messu_messages` where `user`=? and `user_from`=? and `hash`=?", [$user,$from,$hash])) { 736 return false; 737 } 738 739 $query = "insert into `messu_messages`(`user`,`user_from`,`user_to`,`user_cc`,`subject`,`body`,`date`,`isRead`,`isReplied`,`isFlagged`,`priority`,`hash`,`replyto_hash`) values(?,?,?,?,?,?,?,?,?,?,?,?,?)"; 740 $tikilib->query($query, [$user,$from,$to,$cc,$subject,$body,(int) $tikilib->now,'n','n','n',(int) $priority,$hash,$replyto_hash]); 741 742 // Now check if the user should be notified by email 743 $foo = parse_url($_SERVER["REQUEST_URI"]); 744 $machine = $tikilib->httpPrefix(true) . $foo["path"]; 745 $machine = str_replace('messu-compose', 'messu-mailbox', $machine); 746 if ($tikilib->get_user_preference($user, 'minPrio', 6) <= $priority) { 747 if (! isset($_SERVER["SERVER_NAME"])) { 748 $_SERVER["SERVER_NAME"] = $_SERVER["HTTP_HOST"]; 749 } 750 $email = $userlib->get_user_email($user); 751 if ($email) { 752 include_once('lib/webmail/tikimaillib.php'); 753 $smarty->assign('mail_site', $_SERVER["SERVER_NAME"]); 754 $smarty->assign('mail_machine', $machine); 755 $smarty->assign('mail_date', $tikilib->now); 756 $smarty->assign('mail_user', stripslashes($user)); 757 $smarty->assign('mail_from', stripslashes($from)); 758 $smarty->assign('mail_subject', stripslashes($subject)); 759 //////////////////////////////////////////////////////////////////////// 760 // // 761 // ALPHAFIELDS 2012-11-03: ADDED PGP/MIME ENCRYPTION PREPARATION // 762 // USING lib/openpgp/opepgplib.php // 763 // // 764 // prepend original headers into email // 765 $aux_body = $prepend_email_body . $body; 766 $body = $aux_body; 767 // // 768 //////////////////////////////////////////////////////////////////////// 769 $smarty->assign('mail_body', stripslashes($body)); 770 $mail = new TikiMail($user); 771 $lg = $tikilib->get_user_preference($user, 'language', $prefs['site_language']); 772 if (empty($subject)) { 773 $s = $smarty->fetchLang($lg, 'mail/messu_message_notification_subject.tpl'); 774 $mail->setSubject(sprintf($s, $_SERVER["SERVER_NAME"])); 775 } else { 776 $mail->setSubject($subject); 777 } 778 $mail_data = $smarty->fetchLang($lg, 'mail/messu_message_notification.tpl'); 779 //////////////////////////////////////////////////////////////////////// 780 // // 781 // ALPHAFIELDS 2012-11-03: ADDED PGP/MIME ENCRYPTION PREPARATION // 782 // USING lib/openpgp/opepgplib.php // 783 // // 784 // append pgparmor block and fingerprint into email // 785 $mail_data .= $user_pubkeyarmor; 786 // // 787 //////////////////////////////////////////////////////////////////////// 788 $mail->setText($mail_data); 789 790 if ($userlib->user_exists($from)) { 791 $from_email = $userlib->get_user_email($from); 792 if ($bcc_sender === 'y' && ! empty($from_email)) { 793 $mail->setBcc($from_email); 794 } 795 if ($replyto_email !== 'y' && $userlib->get_user_preference($from, 'email is public', 'n') == 'n') { 796 $from_email = ''; // empty $from_email if not to be used - saves getting it twice 797 } 798 if (! empty($from_email)) { 799 $mail->setReplyTo($from_email); 800 } 801 } 802 if (! empty($from_email)) { 803 $mail->setFrom($from_email); 804 } 805 806 if (! $mail->send([$email], 'mail')) { 807 return false; //TODO echo $mail->errors; 808 } 809 } 810 } 811 return true; 812 } 813 814 ///////////////////////////////////////////////////////////////// 815 /** 816 * Function to insert original subject into text part body 817 * 818 * @param array $mail_headers / headers array 819 * @param string $text / The text body of the message 820 * @access public 821 * @return string $text / The text body of the message prepended with original subject 822 */ 823 function prependSubjectToText($mail_headers, $text) 824 { 825 826 // AS THE Subject-header is hidden and contains a hash only in a pgp/mime encrypted message subject-header 827 // extract the original subject and prepend it into the text part 828 // TODO: for some reason, newsletter notifications etc 829 // do not set Subject yet at this point so no adjustment is generated for them; 830 // what is the problem and solution? 831 $subject = ''; 832 if (! empty($mail_headers['Subject'])) { 833 $subject = $mail_headers['Subject']; 834 } 835 $ret = "******** PGP/MIME-ENCRYPTED MESSAGE ********\n" 836 . "Subject: " . $subject 837 . "\n\n" 838 . $text; 839 return $ret; 840 } 841 842 /** 843 * Function to insert original subject into html part body 844 * 845 * @param array $mail_headers / headers array 846 * @param string $html / The html body of the message 847 * @param string $text / The text body of the message 848 * @access public 849 * @return array 850 * 0 => $html / The html body of the message prepended with original subject 851 * 1 => $html_text / The html_text body of the message prepended with original subject 852 */ 853 function prependSubjectToHtml($mail_headers, $html, $text) 854 { 855 856 // AS THE Subject-header is hidden and contains a hash only in a pgp/mime encrypted message subject-header 857 // extract the original subject and prepend it into the html part 858 // TODO: for some reason, newsletter notifications etc 859 // do not set Subject yet at this point so no adjustment is generated for them; 860 // what is the problem and solution? 861 $subject = ''; 862 if (! empty($mail_headers['Subject'])) { 863 $subject = $mail_headers['Subject']; 864 } 865 $ret_html = "******** PGP/MIME-ENCRYPTED MESSAGE ********<br>" 866 . "Subject: " . $subject 867 . "<br>" 868 . $html; 869 870 $ret_html_text = "******** PGP/MIME-ENCRYPTED MESSAGE ********<br>" 871 . "Subject: " . $subject 872 . "<br>" 873 . $text; 874 return [$ret_html,$ret_html_text]; 875 } 876 877 ///////////////////////////////////////////////////////////////// 878 /** 879 * Prepate encryption of a mail using gnupg 880 * 881 * @param array $original_mail_headers / headers array 882 * @param string $original_mail_body / The main body of the message after building 883 * @param string $mail_build_params_head_charset 884 * @param array/string $recipients (needs to be not-imploded string or array) 885 * @access public 886 * @return array 887 * 0 => string $gnupg_header 888 * 1 => string $gnupg_subject 889 * 2 => string $pgpmime_encrypted_message_body 890 */ 891 function prepareEncryptWithMailSender($original_mail_headers, $original_mail_body, $mail_build_params_head_charset, $mail_recipients) 892 { 893 894 // Define gnupg/mime header variables; see constants above in this class 895 $gnupg_mpe = OpenPGPLib::MULTIPART_PGP_ENCRYPTED; 896 $gnupg_tpp = OpenPGPLib::TYPE_PGP_PROTOCOL; 897 $gnupg_pmn = OpenPGPLib::PGP_MIME_NOTE; 898 $gnupg_tpcv = OpenPGPLib::TYPE_PGP_CONTENT_VERSION; 899 $gnupg_dpcv = OpenPGPLib::DESCRIPTION_PGP_CONTENT_VERSION; 900 $gnupg_pmvi = OpenPGPLib::PGP_MIME_VERSION_IDENTIFICATION; 901 $gnupg_tpce = OpenPGPLib::TYPE_PGP_CONTENT_ENCRYPTED; 902 $gnupg_dpce = OpenPGPLib::DESCRIPTION_PGP_CONTENT_ENCRYPTED; 903 $gnupg_dpci = OpenPGPLib::DISPOSITION_PGP_CONTENT_INLINE; 904 905 906 // Define gnupg boundary 907 $gnupg_boundary = '------gnupg-' . md5(rand() . microtime()); 908 909 // Get flat representation of headers 910 foreach ($original_mail_headers as $name => $value) { 911 // first process Content-Type and discard original and set pgp/mime-required after loop 912 if ($name == 'Content-Type') { 913 $tmpvalue = $this->_encodeHeader($value, $mail_build_params_head_charset); 914 // check if original message is just text/plain, so we can discard the entire 915 // orig_header from being prepended into encrypted part 916 $pos = strpos($tmpvalue, 'text/plain'); 917 if ($pos !== false) { 918 // so text/plain ...set discard-flag... 919 $discard_orig_header = true; 920 } else { 921 // reach here if not text/plain 922 $orig_headers[] = $name . ': ' . $tmpvalue; 923 } 924 } else { 925 // Get flat representation of original headers 926 $orig_headers[] = $name . ': ' . $this->_encodeHeader($value, $mail_build_params_head_charset); 927 } 928 } 929 930 // save original header to be added into encrypted part 931 if ($discard_orig_header) { 932 // original body is text/plain, so no headers there 933 $orig_header = ''; 934 } else { 935 $orig_header = implode(CRLF, $orig_headers); 936 } 937 938 ////////////////////////////////////////////////////////////////////////// 939 // NOTE: pgpmime_header; this must be returned as header (string here) for the mail() function 940 $pgpmime_header = "Content-Type: {$gnupg_mpe};{$this->EOL} protocol=\"{$gnupg_tpp}\";{$this->EOL} boundary=\"{$gnupg_boundary}\"{$this->EOL}{$this->EOL}"; 941 942 // Instead of original Subject, use this to hide even the subject: 943 // - generate a message hash ID to be used instead of orig subject; 944 // - show the original Subject in the encrypted message body; 945 $tmpstr = chunk_split( 946 md5( 947 $pgpmime_header 948 . rand() 949 . microtime() 950 ), 951 8, 952 '-' 953 ); 954 $tmpstr = substr($tmpstr, 0, strlen($tmpstr) - 1); 955 $replace_subject_with_msgID = '[PGP/MIME] ' . $tmpstr; 956 ////////////////////////////////////////////////////////////////////////// 957 // NOTE: pgpmime subject; this must be returned as subject for the mail() function 958 $pgpmime_subject = $replace_subject_with_msgID; 959 960 // gnupg pgp/mime note 961 $gnupg = "{$gnupg_pmn}{$this->EOL}"; 962 963 // gnupg part 1 header 964 $gnupg .= "--{$gnupg_boundary}{$this->EOL}Content-Type: {$gnupg_tpcv}{$this->EOL}Content-Description: {$gnupg_dpcv}{$this->EOL}{$this->EOL}{$gnupg_pmvi}{$this->EOL}{$this->EOL}"; 965 966 // gnupg part 2 header 967 $gnupg .= "--{$gnupg_boundary}{$this->EOL}Content-Type: {$gnupg_tpce}{$this->EOL}Content-Description: {$gnupg_dpce}{$this->EOL}Content-Disposition: {$gnupg_dpci}{$this->EOL}{$this->EOL}"; 968 969 // gnupg encrypted/signed message body 970 // original header to be added into encrypted part (use here the prepared/imploded orig_header from above) 971 // NOTE: signer and signer passphrase are set ready in this class instantiation, 972 // and used in the following function directly from there 973 $gnupg .= $this->_encryptSignGnuPG($orig_header . "{$this->EOL}{$this->EOL}" . $original_mail_body, $mail_recipients); 974 // gnupg end boundary 975 $gnupg .= "{$this->EOL}--{$gnupg_boundary}--{$this->EOL}"; 976 977 ////////////////////////////////////////////////////////////////////////// 978 // NOTE: gnupg into mail body; this must be returned as encrypted body for the mail() function 979 $pgpmime_encrypted_message_body = $gnupg; 980 981 return [ 982 0 => $pgpmime_header, 983 1 => $pgpmime_subject, 984 2 => $pgpmime_encrypted_message_body]; 985 } 986 987 988 ///////////////////////////////////////////////////////////////// 989 /** 990 * Prepare encryption of a mail using gnupg 991 * 992 * @param array $original_mail_headers / headers array 993 * @param string $original_mail_body / The main body of the message after building 994 * @param string $mail_build_params_head_charset 995 * @param array/string $recipients (needs to be not-imploded string or array) 996 * @access public 997 * @return array 998 * 0 => array $gnupg_header_array 999 * 1 => string $pgpmime_encrypted_message_body 1000 */ 1001 function prepareEncryptWithSmtpSender($original_mail_headers, $original_mail_body, $mail_build_params_head_charset, $mail_recipients) 1002 { 1003 1004 // Define gnupg/mime header variables; see constants above in this class 1005 $gnupg_mpe = OpenPGPLib::MULTIPART_PGP_ENCRYPTED; 1006 $gnupg_tpp = OpenPGPLib::TYPE_PGP_PROTOCOL; 1007 $gnupg_pmn = OpenPGPLib::PGP_MIME_NOTE; 1008 $gnupg_tpcv = OpenPGPLib::TYPE_PGP_CONTENT_VERSION; 1009 $gnupg_dpcv = OpenPGPLib::DESCRIPTION_PGP_CONTENT_VERSION; 1010 $gnupg_pmvi = OpenPGPLib::PGP_MIME_VERSION_IDENTIFICATION; 1011 $gnupg_tpce = OpenPGPLib::TYPE_PGP_CONTENT_ENCRYPTED; 1012 $gnupg_dpce = OpenPGPLib::DESCRIPTION_PGP_CONTENT_ENCRYPTED; 1013 $gnupg_dpci = OpenPGPLib::DISPOSITION_PGP_CONTENT_INLINE; 1014 1015 // Define gnupg boundary 1016 $gnupg_boundary = '------gnupg-' . md5(rand() . microtime()); 1017 1018 // Define a boundary for orig body, if needed 1019 $add_boundary_for_orig = '------orig--' . md5(rand() . microtime()); 1020 1021 // set discard-flag originally false; see below foreach loop and later the origheader implode 1022 $discard_orig_header = true; 1023 1024 // Get flat representation of original headers to be put with the encrypted body 1025 foreach ($original_mail_headers as $name => $value) { 1026 // first process Content-Type and discard original and set pgp/mime-required after loop 1027 if ($name == 'Content-Type') { 1028 $tmpvalue = $this->_encodeHeader($value, $mail_build_params_head_charset); 1029 // check if original message is just text/plain, so we can discard the entire 1030 // orig_header from being prepended into encrypted part 1031 $pos = strpos($tmpvalue, 'text/plain'); 1032 if ($pos !== false) { 1033 // so text/plain ...set discard-flag... 1034 $discard_orig_header = true; 1035 } else { 1036 // reach here if not text/plain 1037 $orig_headers[] = $name . ': ' . $tmpvalue; 1038 } 1039 } else { 1040 // Get flat representation of original headers 1041 $orig_headers[] = $name . ': ' . $this->_encodeHeader($value, $mail_build_params_head_charset); 1042 } 1043 } 1044 1045 // save original header to be added into encrypted part 1046 if ($discard_orig_header) { 1047 // original body is text/plain, so no headers there 1048 $orig_header = ''; 1049 } else { 1050 $orig_header = implode(CRLF, $orig_headers); 1051 } 1052 1053 // gnupg pgp/mime headers; original headers from call-parameters to be added into encrypted part (see above/below) 1054 $pgpmime_header = "Content-Type: {$gnupg_mpe};{$this->EOL} protocol=\"{$gnupg_tpp}\";{$this->EOL} boundary=\"{$gnupg_boundary}\"{$this->EOL}{$this->EOL}"; 1055 1056 ////////////////////////////////////////////////////////////////////////// 1057 // Instead of original Subject, use this to hide even the subject: 1058 // - generate a message hash ID to be used instead of orig subject; 1059 // - show the original Subject in the encrypted message body; 1060 $tmpstr = chunk_split( 1061 md5( 1062 $pgpmime_header 1063 . rand() 1064 . microtime() 1065 ), 1066 8, 1067 '-' 1068 ); 1069 $tmpstr = substr($tmpstr, 0, strlen($tmpstr) - 1); 1070 $replace_subject_with_msgID = '[PGP/MIME] ' . $tmpstr; 1071 ////////////////////////////////////////////////////////////////////////// 1072 // NOTE: pgpmime_header_array; this must be returned as header array (NOTE: array here) for the mail() function 1073 // prepend the opaque Subject before other PGP/MIME headers 1074 $pgpmime_header_array[] = "Subject: " . $replace_subject_with_msgID; 1075 // instead of the original, set this pgp/mime-required header into $gnupg_header_array -return array 1076 $pgpmime_header_array[] = $pgpmime_header; 1077 1078 // Create gnupg pgp/mime parts etc below and set/repalced to message body by caller 1079 // NOTE: here we do not need to create directly the $gpgpmime_header, because the $gnupg_header_array is returned back 1080 // to caller in array format (caller is htmlMimeMail) 1081 1082 // gnupg pgp/mime note 1083 $gnupg = "{$gnupg_pmn}{$this->EOL}"; 1084 1085 // gnupg part 1 header 1086 $gnupg .= "--{$gnupg_boundary}{$this->EOL}Content-Type: {$gnupg_tpcv}{$this->EOL}Content-Description: {$gnupg_dpcv}{$this->EOL}{$this->EOL}{$gnupg_pmvi}{$this->EOL}{$this->EOL}"; 1087 1088 // gnupg part 2 header 1089 $gnupg .= "--{$gnupg_boundary}{$this->EOL}Content-Type: {$gnupg_tpce}{$this->EOL}Content-Description: {$gnupg_dpce}{$this->EOL}Content-Disposition: {$gnupg_dpci}{$this->EOL}{$this->EOL}"; 1090 1091 // gnupg encrypted/signed message body 1092 // original header to be added into encrypted part (use here the prepared/imploded orig_header from above) 1093 // NOTE: signer and signer passphrase are set ready in this class instantiation, 1094 // and used in the following function directly from there 1095 $gnupg .= $this->_encryptSignGnuPG($orig_header . "{$this->EOL}{$this->EOL}" . $original_mail_body, $mail_recipients); 1096 // gnupg end boundary 1097 $gnupg .= "{$this->EOL}--{$gnupg_boundary}--{$this->EOL}"; 1098 1099 ////////////////////////////////////////////////////////////////////////// 1100 // NOTE: gnupg into mail body; this must be returned as encrypted body for the mail() function 1101 $pgpmime_encrypted_message_body = $gnupg; 1102 1103 return [ 1104 0 => $pgpmime_header_array, 1105 1 => $pgpmime_encrypted_message_body]; 1106 } 1107 1108 ////////////////////////////////////////////////////////// 1109 // 1110 // ZEND FRAMEWORK GNUPG-ENCRYPTED PGP/MIME MAIL FUNCTIONS 1111 // 1112 ////////////////////////////////////////////////////////// 1113 1114 ////////////////////////////////////////////////////////// 1115 /** 1116 * Prepend header name to header value; copied here from Zend/Mail/Transport/Abstract 1117 * See usage in the array_walk in function below 1118 * @param string $item 1119 * @param string $key 1120 * @param string $prefix 1121 * @static 1122 * @access protected 1123 * @return void 1124 */ 1125 protected static function _formatHeader(&$item, $key, $prefix) 1126 { 1127 $item = $prefix . ': ' . $item; 1128 } 1129 1130 ////////////////////////////////////////////////////////// 1131 /** 1132 * Prepate encryption of a mail using gnupg 1133 * 1134 * @param string $original_mail_headers 1135 * @param string $original_mail_body 1136 * @param array|string $recipients 1137 * @access public 1138 * @return array 1139 * 0 => string $pgpmime_header 1140 * 1 => string $pgpmime_encrypted_message_body 1141 */ 1142 function prepareEncryptWithZendMail($original_mail_header = '', $original_mail_body = null, $recipients) 1143 { 1144 1145 // Define gnupg/mime header variables; see constants above in this class 1146 $gnupg_mpe = OpenPGPLib::MULTIPART_PGP_ENCRYPTED; 1147 $gnupg_tpp = OpenPGPLib::TYPE_PGP_PROTOCOL; 1148 $gnupg_pmn = OpenPGPLib::PGP_MIME_NOTE; 1149 $gnupg_tpcv = OpenPGPLib::TYPE_PGP_CONTENT_VERSION; 1150 $gnupg_dpcv = OpenPGPLib::DESCRIPTION_PGP_CONTENT_VERSION; 1151 $gnupg_pmvi = OpenPGPLib::PGP_MIME_VERSION_IDENTIFICATION; 1152 $gnupg_tpce = OpenPGPLib::TYPE_PGP_CONTENT_ENCRYPTED; 1153 $gnupg_dpce = OpenPGPLib::DESCRIPTION_PGP_CONTENT_ENCRYPTED; 1154 $gnupg_dpci = OpenPGPLib::DISPOSITION_PGP_CONTENT_INLINE; 1155 1156 // Define gnupg boundary 1157 $gnupg_boundary = '------gnupg-' . md5(rand() . microtime()); 1158 1159 //********************* 1160 // NOTE: in smtp, $mail_recipients includes the Cc and Bcc recipients. 1161 // so the message gets properly encrypted for them also; 1162 // the problem is still with the Sendmail for such cases / see above...? 1163 // What is the case in Zend Abstract, Sendmail and Smtp...? 1164 //********************* 1165 1166 // Create gnupg pgp/mime parts etc below and set to this->output 1167 1168 // gnupg pgp/mime headers; original headers from call-parameters to be added into encrypted part (see below) 1169 $pgpmime_header = "Content-Type: {$gnupg_mpe};{$this->EOL} protocol=\"{$gnupg_tpp}\";{$this->EOL} boundary=\"{$gnupg_boundary}\"{$this->EOL}{$this->EOL}"; 1170 1171 // Instead of original Subject, use this to hide even the subject: 1172 // - generate a message hash ID to be used instead of orig subject; 1173 // - show the original Subject in the encrypted message body; 1174 $tmpstr = chunk_split( 1175 md5( 1176 $pgpmime_header 1177 . rand() 1178 . microtime() 1179 ), 1180 8, 1181 '-' 1182 ); 1183 $tmpstr = substr($tmpstr, 0, strlen($tmpstr) - 1); 1184 $replace_subject_with_msgID = '[PGP/MIME] ' . $tmpstr; 1185 // prepend the opaque Subject before other PGP/MIME headers 1186 $pgpmime_header = "Subject: " . $replace_subject_with_msgID . $this->EOL . $pgpmime_header; 1187 1188 // gnupg pgp/mime note 1189 $gnupg = "{$gnupg_pmn}{$this->EOL}"; 1190 1191 // gnupg part 1 header 1192 $gnupg .= "--{$gnupg_boundary}{$this->EOL}Content-Type: {$gnupg_tpcv}{$this->EOL}Content-Description: {$gnupg_dpcv}{$this->EOL}{$this->EOL}{$gnupg_pmvi}{$this->EOL}{$this->EOL}"; 1193 1194 // gnupg part 2 header 1195 $gnupg .= "--{$gnupg_boundary}{$this->EOL}Content-Type: {$gnupg_tpce}{$this->EOL}Content-Description: {$gnupg_dpce}{$this->EOL}Content-Disposition: {$gnupg_dpci}{$this->EOL}{$this->EOL}"; 1196 1197 // gnupg encrypted/signed message body 1198 // original header to be added into encrypted part 1199 // NOTE: signer and signer passphrase are set ready in this class instantiation, 1200 // and used in the following function directly from there 1201 $gnupg .= $this->_encryptSignGnuPG($original_mail_header . "{$this->EOL}{$this->EOL}" . $original_mail_body, $recipients); 1202 // gnupg end boundary 1203 $gnupg .= "{$this->EOL}--{$gnupg_boundary}--{$this->EOL}"; 1204 1205 // gnupg into mail body 1206 $pgpmime_encrypted_message_body = $gnupg; 1207 1208 return [ 1209 0 => $pgpmime_header, 1210 1 => $pgpmime_encrypted_message_body]; 1211 } 1212 1213 ////////////////////////////////////////////////////////// 1214 /** 1215 * Encrypt and sign a mail using gnupg 1216 * 1217 * @param string $unencrypted_message 1218 * @param array/string $recipients (needs to be not-imploded string or array) 1219 * @access protected 1220 * @return string ($encrypted_message) 1221 */ 1222 protected function _encryptSignGnuPG($unencrypted_message, $recipients) 1223 { 1224 1225 $encrypted_message = ''; 1226 1227 // encrypt $message to recipients 1228 // sign wth signer 1229 $gpg = $this->gpg_encrypt("${unencrypted_message}", $recipients); 1230 1231 // $gpg is an array containing 1232 // $gpg[0] encrypted output (STDOUT) 1233 // $gpg[1] warnings and notices (STDERR) 1234 // $gpg[2] exit status from gpg 1235 1236 // test gpg's exit status 1237 if ("$gpg[2]" == '0') { 1238 // if the gpg command returned zero 1239 $encrypted_message = $gpg[0]; 1240 } else { 1241 // if the gpg command returned non-zero 1242 $error_msg = 'OpenPGPLib: _encryptSignGnuPG() returned error code: ' . $gpg[2]; 1243 trigger_error($error_msg, E_USER_ERROR); 1244 // if an error message directs you to the line above please 1245 // double check that your gnupg-configuration, process-call commandline input, and other parameters are correct 1246 } 1247 1248 return $encrypted_message; 1249 } 1250} 1251$openpgplib = new OpenPGPLib; 1252