#!/usr/bin/php
<?
chdir(dirname(__FILE__));
require_once('../nmail/include/global.php');
require_once("include/mail_lib.php");
require_once("include/admin_lib.php");
require_once("include/file.php");
require_once('include/mail_send_lib.php');


// 웹상에서의 실행방지.
if ($_SERVER['DOCUMENT_ROOT'] || $_SERVER['SERVER_SOFTWARE'])
{
	die("Access Denied");
}	// if()


echo "[Nmail] 메일데이타와 디비 동기화 작업 - ".date('y/m/d H:i:s')."\n\n";

if ($_SERVER['argv'][1] != 'ALL')
{
	echo "1. 메일데이타 동기화는 아웃룩에서 가져간 메일이나 디비에러등으로 인해 기록되지 않은 메일들을 정상적으로 동기화 시켜줍니다.\n";
	echo "2. 메일보관기간이 지났지만 새로운 메일을 받지 않아 자동삭제되지 않은 메일들을 찾아 자동삭제해줍니다.\n";

	if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
	{
		echo "메일사용량이 많은곳에서는 [제어판 - 예약된 작업]에 mail_box_dbsync_all.bat 를 등록해두고 시스템 부하가 적은 새벽 시간대등을 골라 매일 실행해주면 효율적입니다.\n";
	} else
	{
		echo "메일사용량이 많은곳에서는 crontab 에 등록해두고 시스템 부하가 적은 새벽 시간대등을 골라 매일 실행해주면 효율적입니다.\n";
	}	// if()
}	// if()


// [2007-04-03] 중복실행방지
	$pname = basename(__FILE__);
	$pname2 = preg_replace('/\.php$/i', "", $pname);

	$pid = $pname2.'.pid';
	// 파일이 있을 경우 먼저 실행중인 스크립트가 존재하는지 확인함.
	if (file_exists($pid))
	{
		list($pid_old) = file($pid);
		if (is_numeric($pid_old))
		{
			if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
			{
				$cmd = "powershell \"Get-WmiObject Win32_Process -Filter 'ProcessId = ".$pid_old."' | Select-Object CommandLine -ExpandProperty 'CommandLine' | Format-Table -Wrap\"";
                // D:\NmailPHP\PHP70\php.exe  -q -c D:\NmailPHP\PHP70\php.ini mail_box_dbsync.php ALL
			} else
			{
				$cmd = 'ps -fp '.$pid_old;
                // UID        PID  PPID  C STIME TTY          TIME CMD
				// root     19217 19216 15 15:21 pts/1    00:00:01 /usr/bin/php /home/nmail2/tools/mail_box_dbsync.php ALL
			}	// if()

			ob_start();
			system($cmd);
			$ps = ob_get_contents();
			ob_end_clean();
			if (strpos($ps, $pname) !== false)      // 실행중인 프로세스 명령에 mail_box_dbsync.php 문자열 포함된 경우
			{
				// [2008-06-02] 실행된지 2시간이 지났을 경우에만 강제 종료함.
				//if ($_SERVER['argv'][1] == 'ALL')
				if ($_SERVER['argv'][1] == 'ALL' && filemtime($pid) <= (time()-7200))
				{
					if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
					{
						$cmd = "powershell \"Stop-Process -Id ".$pid_old."\"";
					} else
					{
						$cmd = 'kill -9 '.$pid_old;
					}	// if()

					// [2008-03-24] 동기화 프로세스의 문제로 이미 실행중일 때 강제종료하도록 함.
					echo "\n[경고]동기화 대상이 전체(ALL)이고 실행된지 2시간이 초과되었을 경우,\n  이미 진행중인 디비 동기화 프로세스는 강제 종료합니다.\n\n";
					echo $ps;
					system($cmd);
					unlink($pid);
					echo "\n";
				} else
				{
					echo "\n[경고]디비 동기화 작업이 이미 진행중이므로 중단합니다.\n\n";
					echo $ps;
					echo "\n";
					exit;
				}	// if()
			}	// if()
		}	// if()
	}	// if()

	// [2015-06] 메일경로 정상존재시 실행가능
	if (!is_dir($G_SYS[MAIL_ROOT])) {
		echo "\n[경고]MailRoot 경로가 정상적이지 않으므로 중단합니다.\n";
		echo $G_SYS[MAIL_ROOT];
		echo "\n\n";
		exit;
	}

	// pid
	$fh=fopen($pname2.'.pid',"w");
	fwrite($fh,getmypid());
	fclose($fh);

// set
set_time_limit(0);
ini_set('memory_limit', '2047M');
$memory_limit = ini_get('memory_limit');
#echo "memory_get_usage: ".number_format(memory_get_usage()) . "\n";

$_start = getmicrotime();

// 입력값 확인.
$d_name_input = addslashes($_SERVER['argv'][1]);
$m_id_input = addslashes($_SERVER['argv'][2]);
#if (!$d_name_input || !$m_id_input)
if (!$d_name_input)
{
	die("  사용방법)\n    - 특정 회  원 : ".$_SERVER['PHP_SELF']." domain.com userid\n    - 특정 도메인 : ".$_SERVER['PHP_SELF']." domain.com\n    - 전체 도메인 : ".$_SERVER['PHP_SELF']." ALL\n");
}	// if()


if ($d_name_input == 'ALL')
{
	$dm = db_get_rows("SELECT d_no, d_name FROM " . $TB['DOMAIN'] . "");
} else
{
	$d_no = db_get_one("SELECT d_no FROM " . $TB['DOMAIN'] . " WHERE d_name = '" . $d_name_input . "'");
	if (!$d_no)
		die("존재하지 않는 도메인입니다.\n=> " . $d_name_input."\n");

	$q_where = '';
	if ($m_id_input)
	{
		$q_where = " m_id = '" . $m_id_input . "' AND ";
	}	// if()

	$dm = array(array('d_no'=>$d_no, 'd_name'=>$d_name_input));
}	// if()

for ($di=0; $di<sizeof($dm); $di++)
{
	$d_no = $dm[$di]['d_no'];
	$d_name = $dm[$di]['d_name'];

	echo "\n";
	#echo "#############################################\n";
	#echo "# [".($di+1)."/".sizeof($dm)."] ".$d_name."\n";
	echo "[".($di+1)."/".sizeof($dm)."] ".$d_name." - ";
	#echo "#############################################\n";

	// [2007-07-21] 메일링 리스트 계정은 제외
	//$mbr = db_get_rows("SELECT m_no, m_id, m_mail_file_group FROM " . $TB['MEMBER'] . " WHERE ".$q_where." d_no = '" . $d_no . "'");
	$mbr = db_get_rows("SELECT m_no, m_id, m_mail_file_group, m_name, m_quota FROM " . $TB['MEMBER'] . " WHERE ".$q_where." d_no = '" . $d_no . "' AND m_usertype IS NULL");
	$mbr_cnt = sizeof($mbr);
	if ($mbr_cnt < 1)
	{
		if ($m_id_input)
		{
			die("존재하지 않는 사용자입니다.\n=> " . $m_id_input."\n");
		} else if ($d_name_input != 'ALL')
		{
			die("도메인내에 등록된 사용자가 없습니다.\n");
		}	// if()
	} else
	{
		#echo "총 ".number_format($mbr_cnt)."명의 메일데이타 동기화 작업을 시작합니다.\n";
		echo number_format($mbr_cnt)."\n";


		for ($mi=0; $mi<$mbr_cnt; $mi++)
		{
			// set
			$m_id = $mbr[$mi]['m_id'];
			$AUTH['auth_m_no'] = $mbr[$mi]['m_no'];
			$AUTH['auth_m_id'] = $mbr[$mi]['m_id'];
			$AUTH['auth_m_name'] = $mbr[$mi]['m_name'];
			$AUTH['auth_m_mail_file_group'] = $mbr[$mi]['m_mail_file_group'];
			$AUTH['auth_m_mf_table'] = $G_SYS[PRE_FIX] . 'mail_file_' . $d_no . '_' . $mbr[$mi]['m_mail_file_group'];
			$G_SYS['MAIL_DOMAIN'] = $d_name;

			#echo "[".($mi+1)."/".$mbr_cnt."][".$m_id."]님의 동기화를 시작합니다.(" . round((getmicrotime() - $_start),4) . "sec)\n";


			// [2006-10-25] 하루중 처음 메일을 받을때 실행되는 루틴. - 지정된 기간이 지난 메일들은 자동 삭제함.
			mail_day_once($d_no, $d_name, $AUTH['auth_m_no'], $AUTH['auth_m_id'], $AUTH['auth_m_mail_file_group']);

		/*
			메일박스내의 파일과 디비데이타 동기화
				-. 데이타변환 등 기존 데이타의 문제를 해결하는것이 주 용도임.
				-. 메일박스내의 파일을 기준으로 처리함.
				-. 아웃룩에서 삭제된 경우는 해당 메일박스에서 제일 먼저 받은 메일의 파일이 없을때만 동기화 시작함.

				주의)
				opendir() 사용시메일 디렉토리의 퍼미션제한으로 인해 쉘스크립트로 동작해야함.


		*/


		// 메일파일 갯수
			$DEBUG['get_mails_cnt']['start'] = getmicrotime();
			$md = array('new','out','tmp');
			$md_mb_id = array('inbox','sent','trash');
			$maildir = array();
			$mails = array();
			$mails_cnt = array();
			for ($m=0; $m<sizeof($md); $m++)
			{
				// 메일폴더내의 파일수와 디비데이타수가 틀릴때 동기화를 함.
				$maildir[$md[$m]] = get_mail_dir().'/'.$md[$m].'/';
				$mails[$md[$m]] = array();
				$mails_cnt[$md[$m]] = 0;
				if (is_dir($maildir[$md[$m]]) && $handle=opendir($maildir[$md[$m]]))
				{
				   while ($node = readdir($handle))
				   {
					   #$nodebase = basename($node);
					   if ($node!="." && $node!="..")
					   {
						   #echo "\n". $node;
						   $mails[$md[$m]][] = $node;
						   $mails_cnt[$md[$m]]++;
					   }
				   }
				   closedir($handle);
				} else
				{
					echo "메일폴더를 열 수 없습니다.=> " . $maildir[$md[$m]];
				}	// if()

				// 빠른검색을 위해 파일명으로 정렬
				#sort($mails[$md[$m]]);
				#reset($mails[$md[$m]]);
			}	// for()
			$DEBUG['get_mails_cnt']['exec'] += getmicrotime() - $DEBUG['get_mails_cnt']['start'];
			#vd($mails_cnt, 'mails_cnt');

			#echo "[" . round((getmicrotime() - $_start),4) . "sec]mails_cnt : ".number_format($mails_cnt)."\n"; flush();

		// 메일박스가져오기
			$DEBUG['get_mail_box']['start'] = getmicrotime();
			$sql = "
				SELECT
					mb_id
				FROM
					".$TB['MAIL_BOX']."
				WHERE
					m_no='". $AUTH['auth_m_no'] . "'
				ORDER BY
					mb_sort
				";
			$mb = db_get_rows($sql);
			$DEBUG['get_mail_box']['exec'] += getmicrotime() - $DEBUG['get_mail_box']['start'];

			$DEBUG['get_maildb_cnt']['start'] = getmicrotime();
			$maildb_cnt = array();
			$mb_dir_id = array();
			// [2012-09-27] 메일용량 부족시 알림 메일.
			$m_mf_table_sum = 0;
			for ($m=0; $m<sizeof($mb); $m++)
			{
				$_mb_id = $mb[$m]['mb_id'];
				$_mb_dir = get_mb_dir($_mb_id);
				$mb_dir_id[$_mb_dir][] = $_mb_id;
				$sql = "
					SELECT
						COUNT(*) cnt , SUM(mf_filesize) sm
					FROM
						" . $AUTH['auth_m_mf_table'] . "
					WHERE
						m_no='" . $AUTH['auth_m_no'] . "'
						AND mb_id = '" . $mb[$m]['mb_id'] . "'
					";
				$_mf_row = db_get_row($sql);
				$maildb_cnt[$_mb_dir] += $_mf_row['cnt'];
				$m_mf_table_sum += $_mf_row['sm'];
			}	// for()
			$DEBUG['get_maildb_cnt']['exec'] += getmicrotime() - $DEBUG['get_maildb_cnt']['start'];
			#vd($maildb_cnt, 'maildb_cnt');
			#vd($mb_dir_id, 'mb_dir_id');

			#echo "[" . round((getmicrotime() - $_start),4) . "sec]maildb_cnt : ".number_format($maildb_cnt)."\n"; flush();


		// [임시]개발과정에서 중복된 파일명을 가진 데이타가 편지함마다 들어간 데이타 삭제.
		if ($_SERVER['argv'][3] == 'DUPLICATE')
		{
			for ($m=0; $m<sizeof($md); $m++)
			{
				if (sizeof($mb_dir_id[$md[$m]]) > 0)
				{
					$q_mb_id = set_array2comma(" AND mb_id IN (", ") ", $mb_dir_id[$md[$m]]);

					if ($G_SYS[DB] == 'oracle')
					{
						$sql = "
							SELECT mf_filename, count(*) cnt
							FROM " . $AUTH['auth_m_mf_table'] . "
							WHERE
								m_no='" . $AUTH['auth_m_no'] . "'
								$q_mb_id
							GROUP BY mf_filename
							HAVING count(*) > 1
							ORDER BY cnt DESC
							";
					} else
					{
						$sql = "
							SELECT mf_filename, count(*) cnt
							FROM " . $AUTH['auth_m_mf_table'] . "
							WHERE
								m_no='" . $AUTH['auth_m_no'] . "'
								$q_mb_id
							GROUP BY mf_filename
							HAVING cnt > 1
							ORDER BY cnt DESC
							";
					}	// if()
					$rows = db_get_rows($sql, true);
					if (sizeof($rows['mf_filename']) > 0)
					{
						echo "하나의 파일명이 여러번 저장된 경우 하나만 남기고 나머지는 삭제합니다.(개발초기버젼에서만 잠깐 발생했던 문제)\n";
						echo "동일 폴더내에서 파일명이 중복된 메일수 : ".sizeof($rows['mf_filename'])."\n";
						for ($i=0; $i<sizeof($rows['mf_filename']); $i++)
						{
							$sql = "SELECT mf_no FROM " . $AUTH['auth_m_mf_table'] . " WHERE mf_filename='".$rows['mf_filename'][$i]."' AND m_no='" . $AUTH['auth_m_no'] . "'".$q_mb_id. " ORDER BY mf_no DESC";
							#echo $sql."\n";
							$mf_nos = db_get_rows($sql, 0, $rows['cnt'][$i]-1, true);
							if (sizeof($mf_nos['mf_no']) > 0)
							{
								$q_mf_no = set_array2comma(" (", ") ", $mf_nos['mf_no']);
								$sql = "DELETE FROM " . $AUTH['auth_m_mf_table'] . " WHERE mf_no IN ".$q_mf_no." AND m_no='" . $AUTH['auth_m_no'] . "'".$q_mb_id;
								echo $sql."\n";
								db_query($sql);
							}	// if()
						}	// for()
					}	// if()

					// [2007-08-23] mf_filename 이 비어있는 경우 디비에서만 삭제후 다시 동기화시키도록 함.
					$q = "SELECT count(*) FROM " . $AUTH['auth_m_mf_table'] . " WHERE mf_filename=''";
					$cnt = db_get_one($q);
					if ($cnt > 0)
					{
						echo "파일명이 디비에 기록되지 않은 경우 디비에서 삭제후 다시 동기화시킵니다.(일부 버젼에서 일시적으로 발생했던 문제)\n";
						$sql = "DELETE FROM " . $AUTH['auth_m_mf_table'] . " WHERE mf_filename=''";
						echo $sql."\n";
						db_query($sql);
					}	// if()

				}	// if()
			}	// for()
			#echo "완료.\n";
			continue;
			#exit;
		}	// if()


		// 실제 아웃룩에서 가져갈때는 메일이 한두개씩 차이날 일은 거의 없음.
		for ($m=0; $m<sizeof($md); $m++)
		{
			if (sizeof($mb_dir_id[$md[$m]]) > 0)
			{
				$q_mb_id = set_array2comma(" AND mb_id IN (", ") ", $mb_dir_id[$md[$m]]);
				$mb_id = $md_mb_id[$m];

				#vd('[파일수와 디비수가 동일한지 체크]' . $mails_cnt[$md[$m]] .' > '. $maildb_cnt[$md[$m]]);
				if ($mails_cnt[$md[$m]] > $maildb_cnt[$md[$m]])		// 파일이 더 많을때.   서버레벨에서 기존 이메일을 추가한 경우 등.
				{
					#echo "[".($mi+1)."/".$mbr_cnt."][".$m_id."][".$mb_id."]파일갯수가 디비갯수 보다 많음. : ".$mails_cnt[$md[$m]] .' > '. $maildb_cnt[$md[$m]]." (" . round((getmicrotime() - $_start),4) . "sec)\n";
					$DEBUG['proc_insert']['start'] = getmicrotime();

					// [2012-04-24] 튜닝
					$cnt_mails = array();
					$wi_limit = 0;
					$wi = 0;
					for ($i=0; $i<$mails_cnt[$md[$m]] ; $i++)
					{
						// test
						#if ($i > 1000) break;
						/*
							-. 다음 인덱스를 추가하면 검색시 array_search() 보다 40배이상 빠름.
								ALTER TABLE `nmail_mail_file_1_0000` ADD INDEX `mf_filename` ( `mf_filename` ) ;
									=> 90 sec
								ALTER TABLE `nmail_mail_file_1_0000` ADD INDEX mf_filename2 ( `m_no` , `mb_id` , `mf_filename` );
									=> 140 sec

								200건)
									proc_insert_array_search 5.1859 sec
									proc_insert_db_search 0.7685 sec

								38000건)
									4000초?
									proc_insert_db_search 148.3176 sec
						*/

						//$_mail_file = $mails[$md[$m]][$i];

						$cnt_mails[$wi_limit][] = $mails[$md[$m]][$i];
						$wi++;
						if ($wi%100 == 0)
							$wi_limit++;
					}	// for()

					$i = 0;
					$i_insert = 0;
					for ($wi_limit=0; $wi_limit<sizeof($cnt_mails); $wi_limit++)
					{
						// [2012-04-24] 디비갯수가 같아지면 중단.
						if ($mails_cnt[$md[$m]] <=  $maildb_cnt[$md[$m]] + $i_insert)
							break;

						if (sizeof($cnt_mails[$wi_limit]) > 0)
						{
							$q_mf_filename = '';
							for($ii=0; $ii<sizeof($cnt_mails[$wi_limit]); $ii++)
							{
								if ($ii > 0)
									$q_mf_filename .= ",";
								$q_mf_filename .= "'" . addslashes($cnt_mails[$wi_limit][$ii]) . "'";
							}	// for()

							$DEBUG['proc_insert_db_search']['start'] = getmicrotime();
							$sql = "
								SELECT
									mf_filename
								FROM
									" .$AUTH['auth_m_mf_table'] . "
								WHERE
									mf_filename IN (" . $q_mf_filename . ")
									AND m_no='" . $AUTH['auth_m_no'] . "'
									$q_mb_id
									";
							$_mf_filenames = db_get_rows($sql, true);
							// 대소문자 구별해야함.
							$mf_cnt = (strcmp($_mf_filename, $_mail_file)) ? 0 : 1;
							$DEBUG['proc_insert_db_search']['exec'] += getmicrotime() - $DEBUG['proc_insert_db_search']['start'];

							// [2012-05-14] 디비갯수가 0일 경우, 추가가 안되던 문제 해결.
							if (!is_array($_mf_filenames['mf_filename']))
								$_mf_filenames['mf_filename'] = array();

							for($ii=0; $ii<sizeof($cnt_mails[$wi_limit]); $ii++)
							{
								// 디비에 존재하지않는 메일파일명일때 새로 추가함.
								if (!in_array($cnt_mails[$wi_limit][$ii], $_mf_filenames['mf_filename']))
								{
									$_mail_file = $cnt_mails[$wi_limit][$ii];
									#echo "[" . round((getmicrotime() - $_start),4) . "sec]insert - " . $mb_id . " / " . $i . " / " . $_mail_file."\n";
									echo " [".($mi+1)."/".$mbr_cnt."][".$m_id."][".$mb_id."]DB insert - ". $_mail_file."\n";
									if ($i%10 == 0)
									{
										flush();
									}	// if()
									$DEBUG['proc_insert_mailparse']['start'] = getmicrotime();
									$data = get_mailparse_body_dbdata($maildir[$md[$m]].$_mail_file);
									$DEBUG['proc_insert_mailparse']['exec'] += getmicrotime() - $DEBUG['proc_insert_mailparse']['start'];

									// [2013-11-27] mf_filename 이 비어서 들어오는 문제
									if ($data !== false)
									{
										$DEBUG['proc_insert_db']['start'] = getmicrotime();
										$data['mf_from'] = to_db_str($data['mf_from'], 255, false);
										$data['mf_reply_to'] = to_db_str($data['mf_reply_to'], 255, false);
										$data['mf_sender'] = to_db_str($data['mf_sender'], 255, false);
										$data['mf_to'] = to_db_str($data['mf_to'], $G_SYS['DB_TEXT'], false);
										$data['mf_cc'] = to_db_str($data['mf_cc'], $G_SYS['DB_TEXT'], false);
										#$data['mf_bcc'] = to_db_str($data['mf_bcc'], $G_SYS['DB_TEXT'], false);
										$data['mf_subject'] = to_db_str($data['mf_subject'], 255, false);
										$data['mf_body'] = to_db_str($data['mf_body'], $G_SYS['DB_MEDIUMTEXT'], false);
										$data['mf_charset'] = to_db_str($data['mf_charset'], 20, false);
										$data['mf_send_date_str'] = to_db_str($data['mf_send_date_str'], 255, false);
										// [2006-05-04] 첨부파일갯수가 많을때의 길이 오류 방지.
										$data['mf_attach_names'] = to_db_str($data['mf_attach_names'], $G_SYS['DB_TEXT'], false);

										if ($G_SYS[DB] == 'oracle')
										{
											// [2008-07-04]
											$data['mf_send_date'] = to_db_str($data['mf_send_date'], 19, false);

											$sql = "
												INSERT INTO
													" . $AUTH['auth_m_mf_table'] . "
													( mf_no , m_no , mb_id , mf_from , mf_reply_to , mf_sender , mf_to , mf_cc , mf_importance, mf_subject , mf_content_type , mf_charset , mf_arrival_date , mf_send_date , mf_send_date_str , mf_filename, mf_filesize , mf_attach_names , mf_is_read , mf_is_reply , mf_is_forward , mf_body )
												VALUES
													( ".db_sqc_next($AUTH['auth_m_mf_table']).", ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
												";
											$data_insert = array(
												$AUTH['auth_m_no'],
												$mb_id,
												$data['mf_from'],
												$data['mf_reply_to'],
												$data['mf_sender'],
												$data['mf_to'],
												$data['mf_cc'],
												$data['mf_importance'],
												$data['mf_subject'],
												$data['mf_content_type'],
												$data['mf_charset'],
												$data['mf_arrival_date'],
												$data['mf_send_date'],
												$data['mf_send_date_str'],
												$data['mf_filename'],
												$data['mf_filesize'],
												$data['mf_attach_names'],
												'N',
												'N',
												'N',
												$data['mf_body']
												);
											#vd($data_insert);
											db_query($sql, $data_insert);
										} else
										{
											$sql = "
												INSERT INTO
													" . $AUTH['auth_m_mf_table'] . "
													( mf_no , m_no , mb_id , mf_from , mf_reply_to , mf_sender , mf_to , mf_cc , mf_importance, mf_subject , mf_body , mf_content_type , mf_charset , mf_arrival_date , mf_send_date , mf_send_date_str , mf_filename, mf_filesize , mf_attach_names , mf_is_read , mf_is_read_date , mf_is_reply , mf_is_reply_date , mf_is_forward , mf_is_forward_date )
												VALUES
													(
														NULL,
														'" . $AUTH['auth_m_no'] . "',
														'" . $mb_id . "',
														'" . $data['mf_from'] . "' ,
														'" . $data['mf_reply_to'] . "' ,
														'" . $data['mf_sender'] . "' ,
														'" . $data['mf_to'] . "' ,
														'" . $data['mf_cc'] . "' ,
														'" . $data['mf_importance'] . "' ,
														'" . $data['mf_subject'] . "' ,
														'" . $data['mf_body'] . "' ,
														'" . $data['mf_content_type'] . "' ,
														'" . $data['mf_charset'] . "' ,
														'" . $data['mf_arrival_date'] . "' ,
														'" . $data['mf_send_date'] . "' ,
														'" . $data['mf_send_date_str'] . "' ,
														'" . $data['mf_filename'] . "' ,
														'" . $data['mf_filesize'] . "' ,
														'" . $data['mf_attach_names'] . "' ,
														'N',
														NULL,
														'N',
														NULL,
														'N',
														NULL
													)
												";
											db_query($sql);

											$mf_no = db_sqc_curr($AUTH['auth_m_mf_table']);

											// [2007-08-09] MySQL 4.1, 5.0 일부 버젼에서 '뷁,샾,젹' 등의 한글이 잘리는 문제.
											mail_db_char_fix($AUTH['auth_m_mf_table'], $AUTH['auth_m_no'], $mf_no, $data);

											// [2012-04-24] 디비갯수가 같아지면 중단.
											$i_insert++;
											if ($mails_cnt[$md[$m]] <=  $maildb_cnt[$md[$m]] + $i_insert)
												break;
										}	// if()

										$DEBUG['proc_insert_db']['exec'] += getmicrotime() - $DEBUG['proc_insert_db']['start'];
									}	// if()
								} else
								{
									// 메일파일 배열에서 검색속도 향상을 위해 사용된 파일 삭제함.
									// => array_search 보다 시간이 더 많이 걸리므로 삭제.
									#$DEBUG['proc_insert_array_splice']['start'] = getmicrotime();
									#array_splice($rows['mf_filename'], $_as, 1);
									#$DEBUG['proc_insert_array_splice']['exec'] += getmicrotime() - $DEBUG['proc_insert_array_splice']['start'];

									#if ($i%500 == 0)
									if ($ii%1000 == 0 && $ii > 0)
									{
										echo ".";
										flush();
										#if ($i%5000 == 0)
										if ($ii%10000 == 0)
										{
											echo " [" . round((getmicrotime() - $_start),4) . "sec] ".($ii+1)."\n";
											flush();
										}	// if()
									}	// if()
								}	// if()

								$i++;
							}	// for()
						}	// if()
					}	// for()
					$DEBUG['proc_insert']['exec'] += getmicrotime() - $DEBUG['proc_insert']['start'];
				} else if ($mails_cnt[$md[$m]] < $maildb_cnt[$md[$m]])	// 디비가 더 많을때.   아웃룩에서 사본을 저장하지 않고 가져가서 파일이 삭제된 경우 등.
				{
					#echo "[".($mi+1)."/".$mbr_cnt."][".$m_id."][".$mb_id."]파일갯수가 디비갯수 보다 적음. : ".$mails_cnt[$md[$m]] .' < '. $maildb_cnt[$md[$m]]." (" . round((getmicrotime() - $_start),4) . "sec)\n";

					$DEBUG['get_mf_filenames']['start'] = getmicrotime();
					$sql = "
						SELECT
							mf_filename, mf_no, mf_filesize
						FROM
							" .$AUTH['auth_m_mf_table'] . "
						WHERE
							m_no='" . $AUTH['auth_m_no'] . "'
							$q_mb_id
						";
					$rows = db_get_rows($sql, true);
					$rows_cnt = sizeof($rows['mf_filename']);
					$DEBUG['get_mf_filenames']['exec'] += getmicrotime() - $DEBUG['get_mf_filenames']['start'];
					#echo "[" . round((getmicrotime() - $_start),4) . "sec]get mf_filename - ".$mb_id." : ".$rows_cnt . "\n";
					#flush();

					$DEBUG['proc_delete']['start'] = getmicrotime();
					$del_mails = array();
					$wi_limit = 0;
					$wi = 0;
					for ($i=0; $i<$rows_cnt; $i++)
					{
						// [2015-06] 메일경로 정상존재시 실행가능
						#if (!file_exists($maildir[$md[$m]].$rows['mf_filename'][$i]))
						if (is_dir($maildir[$md[$m]]) && !file_exists($maildir[$md[$m]].$rows['mf_filename'][$i]))
						{
							$del_mails[$wi_limit][] = $rows['mf_no'][$i];
							$wi++;
							if ($wi%100 == 0)
								$wi_limit++;

							$m_mf_table_sum -= $rows['mf_filesize'][$i];
						}	// if()
					}	// for()

					for ($wi_limit=0; $wi_limit<sizeof($del_mails); $wi_limit++)
					{
						if (sizeof($del_mails[$wi_limit]) > 0)
						{
							$q_mf_no = set_array2comma(" (", ") ", $del_mails[$wi_limit]);
							$sql = "
								DELETE
								FROM
									" . $AUTH['auth_m_mf_table'] . "
								WHERE
									mf_no IN ".$q_mf_no."
									AND m_no='" . $AUTH['auth_m_no'] . "'
									$q_mb_id
								";
							#vd($sql);
							db_query($sql);
						}	// if()
					}	// for()
					#echo "[" . round((getmicrotime() - $_start),4) . "sec]del_mails - ".$mb_id." : ".$wi . "\n";
					echo " [".($mi+1)."/".$mbr_cnt."][".$m_id."][".$mb_id."]DB delete - ".$wi . "EA\n";
					flush();

					$DEBUG['proc_delete']['exec'] += getmicrotime() - $DEBUG['proc_delete']['start'];
				}	// if()
			}	// if()
		}	// for()


		// [2012-09-27] 메일용량 부족시 알림 메일.
		/*
					메일 용량이 100% 이상일 때
						qa_type = S / L / NULL  => 발송
						단, qa_date가 24시간이내이고, qa_type = S 인 경우 생략함.

					메일 용량이 90% 이상일 때.
						qa_type = S / NULL => 발송
						단, qa_date가 24시간이내이고, qa_type = S 인 경우 생략함.

					메일 용량이 85% 이하이고, qa_type = L / O 일때
						db insert : qa_type = S
		*/
			if ($G_SYS['MAIL_QUOTA_ALERT_ISUSE'])
			{
				$q = "SELECT qa_date, qa_type FROM ".$TB['QUOTA_ALERT']." WHERE m_no='". $AUTH['auth_m_no'] . "' ORDER BY qa_date DESC";
				$rows = db_get_rows($q, 0, 1);
				$last_qa_date = $rows[0]['qa_date'];
				$last_qa_type = $rows[0]['qa_type'];

				// [2013-11-15]
				if ($mbr[$mi]['m_quota'] > 0)
				{
					$m_quota_rate = floor(($m_mf_table_sum/($mbr[$mi]['m_quota']*1024))*100);
				} else
				{
					$m_quota_rate = 0;
				}	// if()

				$qa_mail_send = '';
				$qa_type = '';

				if ($m_quota_rate >= 100)
				{
					if (($last_qa_type == 'S' && $last_qa_date < date('Y-m-d H:i:s', time()-86400)) || $last_qa_type == 'L' || $last_qa_type == '')
					{
						$qa_mail_send = 'O';
						$qa_type = 'O';
					}	// if()
				} else if ($m_quota_rate >= $G_SYS['MAIL_QUOTA_ALERT_RATE'])
				{
					if (($last_qa_type == 'S' && $last_qa_date < date('Y-m-d H:i:s', time()-86400)) || $last_qa_type == '')
					{
						$qa_mail_send = 'L';
						$qa_type = 'L';
					}	// if()
				} else if ($m_quota_rate <= $G_SYS['MAIL_QUOTA_ALERT_RATE2'])
				{
					if ($last_qa_type == 'L' || $last_qa_type == 'O')
					{
						$qa_type = 'S';
					}	// if()
				}	// if()

				// 메일 발송
				if ($qa_mail_send != '')
				{
					if ($qa_mail_send == 'O')
					{
						$mf_subject = $G_SYS['MAIL_QUOTA_ALERT_SUBJECT_OVER'];
						$mf_body_skin = 'quota_alert_over_mail.html';
					} else
					{
						$mf_subject = $G_SYS['MAIL_QUOTA_ALERT_SUBJECT_LACK'];
						$mf_body_skin = 'quota_alert_lack_mail.html';
					}	// if()

					$ar = array();
					// body
						// 도메인별 스킨 적용.
						$G['DINFO'] = get_domain($G_SYS['MAIL_DOMAIN']);
						set_nskin();

						ob_start();
						include(nskindir('webmail').'/'.$mf_body_skin);
						$ar['body'] = ob_get_contents();
						ob_end_clean();

					// mail send
						$ar['recipients'] = $AUTH['auth_m_id'].'@'.$G_SYS['MAIL_DOMAIN'];
						$ar['hdrs']['To'] = '"'.mime_encode($AUTH['auth_m_name']).'" <'.$AUTH['auth_m_id'].'@'.$G_SYS['MAIL_DOMAIN'].'>';
						$ar['hdrs']['From'] = '"'.mime_encode($G_SYS[ADMIN_EMAIL_NAME]).'" <'.$G_SYS[ADMIN_EMAIL].'>';
						$ar['hdrs']["Date"] = date('r');
						$ar['hdrs']['Subject'] = mime_encode($mf_subject);
						$ar['body_type'] = "HTML";

						// 용량이 초과되더라도 메일이 발송되어야 하므로, 메일 로그에 남지 않더라도 사용자 폴더에 eml을 저장하고 db insert 해야 함. (포워딩, 자동분류 등 모두 동작안함)
						//$ar['result'] = mail_smtp($ar['recipients'], $ar['hdrs'], $ar['body'], $ar['body_type'], NULL, NULL, $G_SYS[SMTP_ADDR]);
						$ar['result'] = mail_smtp($ar['recipients'], $ar['hdrs'], $ar['body'], $ar['body_type'], NULL, NULL, $G_SYS[SMTP_ADDR], 'Y', true);

						$crlf = "\r\n";
						$mail_src = '';
						if ($ar['result']['headers'])
						{
							foreach ($ar['result']['headers'] as $key=>$val)
							{
								$mail_src .= $key.': '.$val.$crlf;
							}	// foreach()
						}	// if()
						$mail_src .= $crlf.$ar['result']['body'];

						$mail_dir = get_mail_dir().'/new';
						$mail_file = getmicrotime().'.'.mt_rand(0,999).'.QuotaAlert.eml';
						$mail_file_size = (int)file_write($mail_dir.'/'.$mail_file, $mail_src);

						$data = get_mailparse_body_dbdata($mail_dir.'/'.$mail_file);
						$data['m_no'] = $AUTH['auth_m_no'];
						$data['mb_id'] = 'inbox';
						$data['mf_is_read'] = 'N';
						mail_db_insert($AUTH['auth_m_mf_table'], $data, false);
				}	// if()

				// 디비 기록
				if ($qa_type != '')
				{
					$q = "INSERT INTO ".$TB['QUOTA_ALERT']." (qa_no, m_no, qa_cursize, qa_maxsize, qa_date, qa_type) VALUES (".db_sqc_next($TB['QUOTA_ALERT']).", '". $AUTH['auth_m_no'] . "', '".$m_mf_table_sum."', '".($mbr[$mi]['m_quota']*1024)."', '".date('Y-m-d H:i:s')."', '".$qa_type."')";
					db_query($q);
				}	// if()
			}	// if()

		}	// for()

		#echo "[" . round((getmicrotime() - $_start),4) . "sec]메일데이타 동기화 작업이 완료되었습니다.\n";

	}	// if()

}	// for()


// [2008-05-22] 메일 로그 분석
// [2012-09-27] 전체 도메인의 동기화시에만 로그 분석함. (크론 등 자동 실행시 기본값임)
if ($d_name_input == 'ALL')
{
	echo "\n\n# 서버에서 세션이 만료된 '로그인 기기'정보를 삭제합니다...\n";
	tfa_device_expire();

	#$_start = getmicrotime();
	echo "\n\n# 새로운 메일 로그를 분석합니다...\n";
	$last_analyze_time = mail_log_analyze(date('Ymd'));

	if ($last_analyze_time > 0)
	{
		echo "이미 로그분석이 진행중이므로, 분석 작업을 생략합니다.\n";
	} else
	{
		echo "[" . round((getmicrotime() - $_start),4) . "sec]로그 분석이 완료되었습니다.\n";
	}	// if()
} else
{
	echo "[" . round((getmicrotime() - $_start),4) . "sec]메일데이타 동기화 작업이 완료되었습니다.\n";
}	// if()


// [2007-04-03] 중복실행방지
unlink($pid);


if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
{
	#system('pause');
}	// if()

#require_once('include/global_end.php');
?>