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