1<?php
2/*
3 * e107 website system
4 *
5 * Copyright (C) 2008-2014 e107 Inc (e107.org)
6 * Released under the terms and conditions of the
7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
8 *
9 *	PM plugin - base class API
10 *
11 */
12
13
14
15if (!defined('e107_INIT')) { exit; }
16
17class private_message
18{
19	protected 	$e107;
20	protected	$pmPrefs;
21
22
23	public function prefs()
24	{
25		return $this->pmPrefs;
26	}
27
28
29	/**
30	 *	Constructor
31	 *
32	 *	@param array $prefs - pref settings for PM plugin
33	 *	@return none
34	 */
35	public	function __construct($prefs=null)
36	{
37		$this->e107 = e107::getInstance();
38		$this->pmPrefs = e107::pref('pm');
39	}
40
41
42	/**
43	 *	Mark a PM as read
44	 *	If flag set, send read receipt to sender
45	 *
46	 *	@param	int $pm_id - ID of PM
47	 *	@param	array $pm_info - PM details
48	 *
49	 *	@return	none
50	 *
51	 *	@todo - 'read_delete' pref doesn't exist - remove code? Or support?
52	 */
53	function pm_mark_read($pm_id, $pm_info)
54	{
55		$now = time();
56		if($this->pmPrefs['read_delete'])
57		{
58			$this->del($pm_id);
59		}
60		else
61		{
62			e107::getDb()->gen("UPDATE `#private_msg` SET `pm_read` = {$now} WHERE `pm_id`=".intval($pm_id)); // TODO does this work properly?
63			if(strpos($pm_info['pm_option'], '+rr') !== FALSE)
64			{
65				$this->pm_send_receipt($pm_info);
66			}
67		  	e107::getEvent()->trigger('user_pm_read', $pm_id);
68		}
69	}
70
71
72	/*
73	 *	Get an existing PM
74	 *
75	 *	@param	int $pmid - ID of PM in DB
76	 *
77	 *	@return	boolean|array - FALSE on error, array of PM info on success
78	 */
79	function pm_get($pmid)
80	{
81		$qry = "
82		SELECT pm.*, ut.user_image AS sent_image, ut.user_name AS sent_name, uf.user_image AS from_image, uf.user_name AS from_name, uf.user_email as from_email, ut.user_email as to_email  FROM #private_msg AS pm
83		LEFT JOIN #user AS ut ON ut.user_id = pm.pm_to
84		LEFT JOIN #user AS uf ON uf.user_id = pm.pm_from
85		WHERE pm.pm_id='".intval($pmid)."'
86		";
87		if (e107::getDb()->gen($qry))
88		{
89			$row = e107::getDb()->fetch();
90			return $row;
91		}
92		return FALSE;
93	}
94
95
96	/*
97	 *	Send a PM
98	 *
99	 *	@param	array $vars	- PM information
100	 *		['receipt'] - set TRUE if read receipt required
101	 *		['uploaded'] - list of attachments (if any) - each is an array('size', 'name')
102	 *		['to_userclass'] - set TRUE if sending to a user class
103	 *		['to_array'] = array of recipients
104	 *		['pm_userclass'] = target user class
105	 *		['to_info'] = recipients array of array('user_id', 'user_class')
106	 *
107	 *		May also be an array as received from the generic table, if sending via a cron job
108	 *			identified by the existence of $vars['pm_from']
109	 *
110	 *	@return	string - text detailing result
111	 */
112	function add($vars)
113	{
114		$tp = e107::getParser();
115		$sql = e107::getDb();
116		$pmsize = 0;
117		$attachlist = '';
118		$pm_options = '';
119		$ret = '';
120		$addOutbox = TRUE;
121		$timestamp = time();
122
123		$maxSendNow = varset($this->pmPrefs['pm_max_send'],100);	// Maximum number of PMs to send without queueing them
124		if (isset($vars['pm_from']))
125		{	// Doing bulk send off cron task
126			$info = array();
127			foreach ($vars as $k => $v)
128			{
129				if (strpos($k, 'pm_') === 0)
130				{
131					$info[$k] = $v;
132					unset($vars[$k]);
133				}
134			}
135			$addOutbox = FALSE;			// Don't add to outbox - was done earlier
136		}
137		else
138		{	// Send triggered by user - may be immediate or bulk dependent on number of recipients
139			$vars['options'] = '';
140			if(isset($vars['receipt']) && $vars['receipt']) {$pm_options .= '+rr+';	}
141
142			if(isset($vars['uploaded']))
143			{
144				foreach($vars['uploaded'] as $u)
145				{
146					if (!isset($u['error']) || !$u['error'])
147					{
148						$pmsize += $u['size'];
149						$a_list[] = $u['name'];
150					}
151				}
152				$attachlist = implode(chr(0), $a_list);
153			}
154			$pmsize += strlen($vars['pm_message']);
155
156			$pm_subject = trim($tp->toDB($vars['pm_subject']));
157			$pm_message = trim($tp->toDB($vars['pm_message']));
158
159			if (!$pm_subject && !$pm_message && !$attachlist)
160			{  // Error - no subject, no message body and no uploaded files
161				return LAN_PM_65;
162			}
163
164			// Most of the pm info is fixed - just need to set the 'to' user on each send
165			$info = array(
166				'pm_from' => $vars['from_id'],
167				'pm_sent' => $timestamp,					/* Date sent */
168				'pm_read' => 0,							/* Date read */
169				'pm_subject' => $pm_subject,
170				'pm_text' => $pm_message,
171				'pm_sent_del' => 0,						/* Set when can delete */
172				'pm_read_del' => 0,						/* set when can delete */
173				'pm_attachments' => $attachlist,
174				'pm_option' => $pm_options,				/* Options associated with PM - '+rr' for read receipt */
175				'pm_size' => $pmsize
176				);
177
178		//	print_a($info);
179		//	print_a($vars);
180		}
181
182		if(!empty($vars['pm_userclass']) || isset($vars['to_array']))
183		{
184			if(!empty($vars['pm_userclass']))
185			{
186				$toclass = e107::getUserClass()->uc_get_classname($vars['pm_userclass']);
187				$tolist = $this->get_users_inclass($vars['pm_userclass']);
188				$ret .= LAN_PM_38.": {$toclass}<br />";
189				$class = TRUE;
190				$info['pm_sent_del'] = 1; // keep the outbox clean and limited to 1 entry when sending to an entire class.
191			}
192			else
193			{
194				$tolist = $vars['to_array'];
195				$class = FALSE;
196			}
197			// Sending multiple PMs here. If more than some number ($maxSendNow), need to split into blocks.
198			if (count($tolist) > $maxSendNow)
199			{
200				$totalSend = count($tolist);
201				$targets = array_chunk($tolist, $maxSendNow);		// Split into a number of lists, each with the maximum number of elements (apart from the last block, of course)
202				unset($tolist);
203				$array = new ArrayData;
204				$pmInfo = $info;
205				$genInfo = array(
206					'gen_type' => 'pm_bulk',
207					'gen_datestamp' => time(),
208					'gen_user_id' => USERID,
209					'gen_ip' => ''
210					);
211				for ($i = 0; $i < count($targets) - 1; $i++)
212				{	// Save the list in the 'generic' table
213					$pmInfo['to_array'] = $targets[$i];			// Should be in exactly the right format
214					$genInfo['gen_intdata'] = count($targets[$i]);
215					$genInfo['gen_chardata'] = $array->WriteArray($pmInfo,TRUE);
216					$sql->insert('generic', array('data' => $genInfo, '_FIELD_TYPES' => array('gen_chardata' => 'string')));	// Don't want any of the clever sanitising now
217				}
218				$toclass .= ' ['.$totalSend.']';
219				$tolist = $targets[count($targets) - 1];		// Send the residue now (means user probably isn't kept hanging around too long if sending lots)
220				unset($targets);
221			}
222			foreach($tolist as $u)
223			{
224				set_time_limit(30);
225				$info['pm_to'] = intval($u['user_id']);		// Sending to a single user now
226
227				if($pmid = $sql->insert('private_msg', $info))
228				{
229					$info['pm_id'] = $pmid;
230					e107::getEvent()->trigger('user_pm_sent', $info);
231
232					unset($info['pm_id']); // prevent it from being used on the next record.
233
234					if($class == FALSE)
235					{
236						$toclass .= $u['user_name'].', ';
237					}
238					if(check_class($this->pmPrefs['notify_class'], null, $u['user_id']))
239					{
240						$vars['to_info'] = $u;
241						$vars['pm_sent'] = $timestamp;
242						$this->pm_send_notify($u['user_id'], $vars, $pmid, count($a_list));
243					}
244				}
245				else
246				{
247					$ret .= LAN_PM_39.": {$u['user_name']} <br />";
248					e107::getMessage()->addDebug($sql->getLastErrorText());
249				}
250			}
251			if ($addOutbox)
252			{
253				$info['pm_to'] = $toclass;		// Class info to put into outbox
254				$info['pm_sent_del'] = 0;
255				$info['pm_read_del'] = 1;
256				if(!$pmid = $sql->insert('private_msg', $info))
257				{
258					$ret .= LAN_PM_41.'<br />';
259				}
260			}
261
262		}
263		else
264		{	// Sending to a single person
265			$info['pm_to'] = intval($vars['to_info']['user_id']);		// Sending to a single user now
266
267
268
269
270			if($pmid = $sql->insert('private_msg', $info))
271			{
272				$info['pm_id'] = $pmid;
273				$info['pm_sent'] = $timestamp;
274				e107::getEvent()->trigger('user_pm_sent', $info);
275
276
277				if(check_class($this->pmPrefs['notify_class'], null, $vars['to_info']['user_id']))
278				{
279					set_time_limit(20);
280					$vars['pm_sent'] = $timestamp;
281					$this->pm_send_notify($vars['to_info']['user_id'], $vars, $pmid, count($a_list));
282				}
283				$ret .= LAN_PM_40.": {$vars['to_info']['user_name']}<br />";
284			}
285		}
286		return $ret;
287	}
288
289
290
291	/**
292	 *	Delete a PM from a user's inbox/outbox.
293	 *	PM is only actually deleted from DB once both sender and recipient have marked it as deleted
294	 *	When physically deleted, any attachments are deleted as well
295	 *
296	 *	@param integer $pmid - ID of the PM
297	 *	@param boolean $force - set to TRUE to force deletion of unread PMs
298	 *	@return boolean|string - FALSE if PM not found, or other DB error. String if successful
299	 */
300	function del($pmid, $force = FALSE)
301	{
302		$sql = e107::getDb();
303		$pmid = (int)$pmid;
304		$ret = '';
305		$newvals = '';
306		if($sql->select('private_msg', '*', 'pm_id = '.$pmid.' AND (pm_from = '.USERID.' OR pm_to = '.USERID.')'))
307		{
308			$row = $sql->fetch();
309
310			// if user is the receiver of the PM
311			if (!$force && ($row['pm_to'] == USERID))
312			{
313				$newvals = 'pm_read_del = 1';
314				$ret .= LAN_PM_42.'<br />';
315				if($row['pm_sent_del'] == 1) { $force = TRUE; } // sender has deleted as well, set force to true so the DB record can be deleted
316			}
317
318			// if user is the sender of the PM
319			if (!$force && ($row['pm_from'] == USERID))
320			{
321				if($newvals != '') { $force = TRUE; }
322				$newvals = 'pm_sent_del = 1';
323				$ret .= LAN_PM_43."<br />";
324				if($row['pm_read_del'] == 1) { $force = TRUE; } // receiver has deleted as well, set force to true so the DB record can be deleted
325			}
326
327			if($force == TRUE)
328			{
329				// Delete any attachments and remove PM from db
330				$attachments = explode(chr(0), $row['pm_attachments']);
331				$aCount = array(0,0);
332				foreach($attachments as $a)
333				{
334					$a = trim($a);
335					if ($a)
336					{
337						$filename = e_PLUGIN.'pm/attachments/'.$a;
338						if (unlink($filename)) $aCount[0]++; else $aCount[1]++;
339					}
340				}
341				if ($aCount[0] || $aCount[1])
342				{
343
344				//	$ret .= str_replace(array('--GOOD--', '--FAIL--'), $aCount, LAN_PM_71).'<br />';
345					$ret .= e107::getParser()->lanVars(LAN_PM_71, $aCount);
346				}
347				$sql->delete('private_msg', 'pm_id = '.$pmid);
348			}
349			else
350			{
351				$sql->update('private_msg', $newvals.' WHERE pm_id = '.$pmid);
352			}
353			return $ret;
354		}
355		return FALSE;
356	}
357
358	/**
359	 * Convinient url assembling shortcut
360	 *//*
361	public function url($action, $params = array(), $options = array())
362	{
363		if(strpos($action, '/') === false) $action = 'view/'.$action;
364		e107::getUrl()->create('pm/'.$action, $params, $options);
365	}*/
366
367	/**
368	 *	Send an email to notify of a PM
369	 *
370	 *	@param int $uid - not used
371	 *	@param array $pmInfo - PM details
372	 *	@param int $pmid - ID of PM in database
373	 *	@param int $attach_count - number of attachments
374	 *
375	 *	@return none
376	 */
377	function pm_send_notify($uid, $pmInfo, $pmid, $attach_count = 0)
378	{
379	//	require_once(e_HANDLER.'mail.php');
380/*
381		$tpl_file = THEME.'pm_template.php';
382
383		$PM_NOTIFY = null; // loaded in template below.
384
385		include(is_readable($tpl_file) ? $tpl_file : e_PLUGIN.'pm/pm_template.php');
386
387		$template = $PM_NOTIFY;
388*/
389	if(THEME_LEGACY){include_once(THEME.'pm_template.php');}
390	if (!$PM_NOTIFY){$PM_NOTIFY = e107::getTemplate('pm', 'pm', 'notify');}
391
392		if(empty($PM_NOTIFY)) // BC Fallback.
393		{
394
395			$PM_NOTIFY =
396			"<div>
397			<h4>".LAN_PM_101."{SITENAME}</h4>
398			<table class='table table-striped'>
399			<tr><td>".LAN_PM_102."</td><td>{USERNAME}</td></tr>
400			<tr><td>".LAN_PM_103."</td><td>{PM_SUBJECT}</td></tr>
401			<tr><td>".LAN_PM_108."</td><td>{PM_DATE}</td></tr>
402			<tr><td>".LAN_PM_104."</td><td>{PM_ATTACHMENTS}</td></tr>
403
404			</table><br />
405			<div>".LAN_PM_105.": {PM_URL}</div>
406			</div>
407			";
408
409		}
410
411		$url = e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmid;
412
413		$data = array();
414		$data['PM_SUBJECT']     = $pmInfo['pm_subject'];
415		$data['PM_ATTACHMENTS'] = intval($attach_count);
416		$data['PM_DATE']        = e107::getParser()->toDate($pmInfo['pm_sent'], 'long');
417		$data['SITENAME']       = SITENAME;
418		$data['USERNAME']       = USERNAME;
419		$data['PM_URL']         = $url;// e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmid;
420		$data['PM_BUTTON']      = "<a class='btn btn-primary' href='".$url."'>".LAN_PM_113."</a>";// e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmid;
421
422		$text = e107::getParser()->simpleParse($PM_NOTIFY, $data);
423
424		$eml = array();
425		$eml['email_subject']		= LAN_PM_100.USERNAME;
426		$eml['send_html']			= true;
427		$eml['email_body']			= $text;
428		$eml['template']			= 'default';
429		$eml['e107_header']			= $pmInfo['to_info']['user_id'];
430
431		if(e107::getEmail()->sendEmail($pmInfo['to_info']['user_email'], $pmInfo['to_info']['user_name'], $eml))
432		{
433			return true;
434		}
435		else
436		{
437			return false;
438		}
439
440	}
441
442
443	/**
444	 *	Send PM read receipt
445	 *
446	 *	@param array $pmInfo - PM details
447	 * 	@return boolean
448	 */
449	function pm_send_receipt($pmInfo) //TODO Add Template and combine with method above..
450	{
451		require_once(e_HANDLER.'mail.php');
452		$subject = LAN_PM_106.$pmInfo['sent_name'];
453
454		$pmlink = e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmInfo['pm_id'];
455
456		$txt = str_replace("{UNAME}", $pmInfo['sent_name'], LAN_PM_107).date('l F dS Y h:i:s A')."\n\n";
457		$txt .= LAN_PM_108.date('l F dS Y h:i:s A', $pmInfo['pm_sent'])."\n";
458		$txt .= LAN_PM_103.$pmInfo['pm_subject']."\n";
459		$txt .= LAN_PM_105."\n".$pmlink."\n";
460
461		if(sendemail($pmInfo['from_email'], $subject, $txt, $pmInfo['from_name']))
462		{
463			return true;
464		}
465
466		return false;
467	}
468
469
470	/**
471	 *    Get list of users blocked from sending to a specific user ID.
472	 *
473	 * @param int|mixed $to - user ID
474	 * @return array of blocked users as user IDs
475	 */
476	function block_get($to = USERID)
477	{
478		$sql = e107::getDb();
479		$ret = array();
480		$to = intval($to);		// Precautionary
481		if ($sql->select('private_msg_block', 'pm_block_from', 'pm_block_to = '.$to))
482		{
483			while($row = $sql->fetch())
484			{
485				$ret[] = $row['pm_block_from'];
486			}
487		}
488		return $ret;
489	}
490
491
492	/**
493	 *	Get list of users blocked from sending to a specific user ID.
494	 *
495	 *	@param integer $to - user ID
496	 *
497	 *	@return array of blocked users, including specific user info
498	 */
499	function block_get_user($to = USERID)
500	{
501		$sql = e107::getDb();
502		$ret = array();
503		$to = intval($to);		// Precautionary
504		if ($sql->gen('SELECT pm.*, u.user_name FROM `#private_msg_block` AS pm LEFT JOIN `#user` AS u ON `pm`.`pm_block_from` = `u`.`user_id` WHERE pm_block_to = '.$to))
505		{
506			while($row = $sql->fetch())
507			{
508				$ret[] = $row;
509			}
510		}
511		return $ret;
512	}
513
514
515	/**
516	 *	Add a user block
517	 *
518	 *	@param int $from - sender to block
519	 *	@param int $to - user doing the blocking
520	 *
521	 *	@return string result message
522	 */
523	function block_add($from, $to = USERID)
524	{
525		$sql = e107::getDb();
526		$from = intval($from);
527		if($sql->select('user', 'user_name, user_perms', 'user_id = '.$from))
528		{
529			$uinfo = $sql->fetch();
530			if (($uinfo['user_perms'] == '0') || ($uinfo['user_perms'] == '0.'))
531			{  // Don't allow block of main admin
532				return LAN_PM_64;
533			}
534
535			if(!$sql->count('private_msg_block', '(*)', 'WHERE pm_block_from = '.$from." AND pm_block_to = '".e107::getParser()->toDB($to)."'"))
536			{
537				if($sql->insert('private_msg_block', array(
538						'pm_block_from' => $from,
539						'pm_block_to' => $to,
540						'pm_block_datestamp' => time()
541					)))
542				{
543					return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_47);
544				}
545				else
546				{
547					return LAN_PM_48;
548				}
549			}
550			else
551			{
552				return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_49);
553			}
554		}
555		else
556		{
557			return LAN_PM_17;
558		}
559	}
560
561
562
563	/**
564	 *	Delete user block
565	 *
566	 *	@param int $from - sender to block
567	 *	@param int $to - user doing the blocking
568	 *
569	 *	@return string result message
570	 */
571	function block_del($from, $to = USERID)
572	{
573		$sql = e107::getDb();
574		$from = intval($from);
575		if($sql->select('user', 'user_name', 'user_id = '.$from))
576		{
577			$uinfo = $sql->fetch();
578			if($sql->select('private_msg_block', 'pm_block_id', 'pm_block_from = '.$from.' AND pm_block_to = '.intval($to)))
579			{
580				$row = $sql->fetch();
581				if($sql->delete('private_msg_block', 'pm_block_id = '.intval($row['pm_block_id'])))
582				{
583					return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_44);
584				}
585				else
586				{
587					return LAN_PM_45;
588				}
589			}
590			else
591			{
592				return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_46);
593			}
594		}
595		else
596		{
597			return LAN_PM_17;
598		}
599	}
600
601
602	/**
603	 *	Get user ID matching a name
604	 *
605	 *	@param string var - name to match
606	 *
607	 *	@return boolean|array - FALSE if no match, array of user info if found
608	 */
609	function pm_getuid($var)
610	{
611		$sql = e107::getDb();
612
613		if(is_numeric($var))
614		{
615			$where = "user_id = ".intval($var);
616		}
617		else
618		{
619			$var = strip_if_magic($var);
620			$var = str_replace("'", '&#039;', trim($var));		// Display name uses entities for apostrophe
621			$where = "user_name LIKE '".$sql->escape($var, FALSE)."'";
622		}
623
624		if($sql->select('user', 'user_id, user_name, user_class, user_email', $where))
625		{
626			$row = $sql->fetch();
627			return $row;
628		}
629
630		return false;
631
632	}
633
634
635	/**
636	 *	Get list of users in class
637	 *
638	 *	@param int $class - class ID
639	 *
640	 *	@return boolean|array - FALSE on error/none found, else array of user information arrays
641	 */
642	function get_users_inclass($class)
643	{
644
645		return e107::getUserClass()->getUsersInClass($class, 'user_name, user_email, user_class');
646
647
648		/*$sql = e107::getDb();
649
650		if($class == e_UC_MEMBER)
651		{
652			$qry = "SELECT user_id, user_name, user_email, user_class FROM `#user` WHERE 1";
653		}
654		elseif($class == e_UC_ADMIN)
655		{
656			$qry = "SELECT user_id, user_name, user_email, user_class FROM `#user` WHERE user_admin = 1";
657		}
658		elseif($class)
659		{
660			$regex = "(^|,)(".e107::getParser()->toDB($class).")(,|$)";
661			$qry = "SELECT user_id, user_name, user_email, user_class FROM `#user` WHERE user_class REGEXP '{$regex}'";
662		}
663
664
665		if(!empty($qry) && $sql->gen($qry))
666		{
667			$ret = $sql->db_getList();
668			return $ret;
669		}
670		return FALSE;*/
671	}
672
673
674	/**
675	 * Check permission to send a PM to someone.
676	 * @param int $uid user_id of the person to send to
677	 * @return bool
678	 */
679	function canSendTo($uid)
680	{
681		if(empty($uid))
682		{
683			return false;
684		}
685
686		if(!empty($this->pmPrefs['vip_class']))
687		{
688			if(check_class($this->pmPrefs['vip_class'],null,$uid) && !check_class($this->pmPrefs['vip_class']))
689			{
690				return false;
691			}
692
693		}
694
695		$user = e107::user($uid);
696
697		$uclass = explode(",", $user['user_class']);
698
699		if($this->pmPrefs['send_to_class'] == 'matchclass')
700		{
701			$tmp = explode(",", USERCLASS);
702			$result = array_intersect($uclass, $tmp);
703
704			return !empty($result);
705		}
706
707		return in_array($this->pmPrefs['send_to_class'], $uclass);
708
709	}
710
711
712
713
714	/**
715	 *	Get inbox - up to $limit messages from $from
716	 *
717	 *	@param int $uid - user ID
718	 *	@param int $from - first message
719	 *	@param int $limit - number of messages
720	 *
721	 *	@return boolean|array - FALSE if none found or error, array of PMs if available
722	 */
723	function pm_get_inbox($uid = USERID, $from = 0, $limit = 10)
724	{
725		$sql = e107::getDb();
726		$ret = array();
727		$total_messages = 0;
728		$uid = intval($uid);
729		$limit = intval($limit);
730		if ($limit < 2) { $limit = 10; }
731		$from = intval($from);
732		$qry = "
733		SELECT SQL_CALC_FOUND_ROWS pm.*, u.user_image, u.user_name FROM `#private_msg` AS pm
734		LEFT JOIN `#user` AS u ON u.user_id = pm.pm_from
735		WHERE pm.pm_to='{$uid}' AND pm.pm_read_del=0
736		ORDER BY pm.pm_sent DESC
737		LIMIT ".$from.", ".$limit."
738		";
739
740		if($sql->gen($qry))
741		{
742			$total_messages = $sql->foundRows(); 		// Total number of messages
743			$ret['messages'] = $sql->db_getList();
744		}
745
746		$ret['total_messages'] = $total_messages;		// Should always be defined
747		return $ret;
748	}
749
750
751	/**
752	 *	Get outbox - up to $limit messages from $from
753	 *
754	 *	@param int $uid - user ID
755	 *	@param int $from - first message
756	 *	@param int $limit - number of messages
757	 *
758	 *	@return boolean|array - FALSE if none found or error, array of PMs if available
759	 */
760	function pm_get_outbox($uid = USERID, $from = 0, $limit = 10)
761	{
762		$sql = e107::getDb();
763		$ret = array();
764		$total_messages = 0;
765		$uid = intval($uid);
766		$limit = intval($limit);
767		if ($limit < 2) { $limit = 10; }
768		$from = intval($from);
769		$qry = "
770		SELECT SQL_CALC_FOUND_ROWS pm.*, u.user_image, u.user_name FROM #private_msg AS pm
771		LEFT JOIN #user AS u ON u.user_id = pm.pm_to
772		WHERE pm.pm_from='{$uid}' AND pm.pm_sent_del = '0'
773
774		ORDER BY pm.pm_sent DESC
775		LIMIT ".$from.', '.$limit;
776
777		if($sql->gen($qry))
778		{
779			$total_messages = $sql->total_results;		// Total number of messages
780			$ret['messages'] = $sql->db_getList();
781		}
782		$ret['total_messages'] = $total_messages;
783		return $ret;
784	}
785
786
787	/**
788	 *	Send a file down to the user
789	 *
790	 *	@param	int $pmid - PM ID
791	 *	@param	string $filenum - attachment number within the list associated with the PM
792	 *
793	 *	@return none
794	 *
795	 */
796	function send_file($pmid, $filenum)
797	{
798		$pm_info = $this->pm_get($pmid);
799
800		$attachments = explode(chr(0), $pm_info['pm_attachments']);
801
802		if(!isset($attachments[$filenum]))
803		{
804			return false;
805		}
806
807		$fname = $attachments[$filenum];
808		list($timestamp, $fromid, $rand, $file) = explode("_", $fname, 4);
809
810
811		$filename = false; // getcwd()."/attachments/{$fname}";
812
813		$pathList = array();
814		$pathList[] = e_PLUGIN."pm/attachments/"; // getcwd()."/attachments/"; // legacy path.
815		$pathList[] = e107::getFile()->getUserDir($fromid, false, 'attachments'); // new media path.
816
817		foreach($pathList as $path)
818		{
819			$tPath = $path.$fname;
820
821			if(is_file($tPath))
822			{
823				$filename = $tPath;
824				break;
825			}
826
827		}
828
829		if(empty($filename) || !is_file($filename))
830		{
831			return false;
832		}
833
834
835		if($fromid != $pm_info['pm_from'])
836		{
837			return false;
838		}
839
840	//	e107::getFile()->send($filename); // limited to Media and system folders. Won't work for legacy plugin path.
841	//	exit;
842
843
844
845		@set_time_limit(10 * 60);
846		@e107_ini_set("max_execution_time", 10 * 60);
847		while (@ob_end_clean()); // kill all output buffering else it eats server resources
848		if (connection_status() == 0)
849		{
850			if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
851				$file = preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1);
852			}
853			if (isset($_SERVER['HTTP_RANGE']))
854			{
855				$seek = intval(substr($_SERVER['HTTP_RANGE'] , strlen('bytes=')));
856			}
857			$bufsize = 2048;
858			ignore_user_abort(true);
859			$data_len = filesize($filename);
860			if ($seek > ($data_len - 1)) $seek = 0;
861			$res =& fopen($filename, 'rb');
862			if ($seek)
863			{
864				fseek($res , $seek);
865			}
866			$data_len -= $seek;
867			header("Expires: 0");
868			header("Cache-Control: max-age=30" );
869			header("Content-Type: application/force-download");
870			header("Content-Disposition: attachment; filename={$file}");
871			header("Content-Length: {$data_len}");
872			header("Pragma: public");
873			if ($seek)
874			{
875				header("Accept-Ranges: bytes");
876				header("HTTP/1.0 206 Partial Content");
877				header("status: 206 Partial Content");
878				header("Content-Range: bytes {$seek}-".($data_len - 1)."/{$data_len}");
879			}
880			while (!connection_aborted() && $data_len > 0)
881			{
882				echo fread($res , $bufsize);
883				$data_len -= $bufsize;
884			}
885			fclose($res);
886		}
887	}
888
889
890
891
892
893
894
895
896
897	function updateTemplate($template)
898	{
899		$array = array(
900		'FORM_TOUSER'		=> 'PM_FORM_TOUSER',
901		'FORM_TOCLASS'		=> 'PM_FORM_TOCLASS',
902		'FORM_SUBJECT'		=> 'PM_FORM_SUBJECT',
903		'FORM_MESSAGE'		=> 'PM_FORM_MESSAGE',
904		'EMOTES'			=> 'PM_EMOTES',
905		'ATTACHMENT'		=> 'PM_ATTACHMENT',
906		'RECEIPT'			=> 'PM_RECEIPT',
907		'INBOX_TOTAL'		=> 'PM_INBOX_TOTAL',
908		'INBOX_UNREAD'		=> 'PM_INBOX_UNREAD',
909		'INBOX_FILLED'		=> 'PM_INBOX_FILLED',
910		'OUTBOX_TOTAL'		=> 'PM_OUTBOX_TOTAL',
911		'OUTBOX_UNREAD'		=> 'PM_OUTBOX_UNREAD',
912		'OUTBOX_FILLED'		=> 'PM_OUTBOX_FILLED',
913
914		'SEND_PM_LINK'		=> 'PM_SEND_PM_LINK',
915		'NEWPM_ANIMATE'		=> 'PM_NEWPM_ANIMATE',
916
917		'BLOCKED_SENDERS_MANAGE'		=> 'PM_BLOCKED_SENDERS_MANAGE',
918		'DELETE_BLOCKED_SELECTED'		=> 'DELETE_BLOCKED_SELECTED'
919		);
920
921
922		foreach($array as $old => $new)
923		{
924			$template = str_replace("{".$old."}", "{".$new."}", $template);
925		}
926
927		return $template;
928
929	}
930
931}
932