View file fmget-client/fmget/fmget.php

File size: 18.29Kb
<?php
# FMGET ver. 1.1
# © Alex Extend, 2008
# 
# Данная программа является свободным программным обеспечением. Вы вправе
# распространять ее и/или модифицировать в соответствии с условиями версии 2 либо
# по вашему выбору с условиями более поздней версии Стандартной Общественной
# Лицензии GNU, опубликованной Free Software Foundation.
# 
# Мы распространяем данную программу в надежде на то, что она будет вам полезной
# однако НЕ ПРЕДОСТАВЛЯЕМ НА НЕЕ НИКАКИХ ГАРАНТИЙ, в том числе ГАРАНТИИ ТОВАРНОГО
# СОСТОЯНИЯ ПРИ ПРОДАЖЕ и ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ. Для
# получения более подробной информации ознакомьтесь со Стандартной Общественной
# Лицензией GNU.

// fmget.php - собственно клиент fmail
error_reporting(E_ALL);
set_time_limit(0);
//ini_set('default_socket_timeout', '3600');
include_once('func.php');
include_once('POP3.php');
if (@getenv('windir')) $win=true; else $win=false;

$basedir=dirname(__FILE__);

// читаем конфигурацию email
$cnf=@unserialize(file_get_contents("$basedir/config.txt"));
// читаем информацию о файле
$info=@unserialize(file_get_contents("$basedir/info.txt"));
$serverurl=@$cnf['serverurl'];
$serverurl=preg_replace('|/$|', '', $serverurl);
$serverurl.='/req.php';

if (empty($nofirst)) mwrite("FMGET ver. 1.1\n");
$mes="Использование:\n";
$mes.="fmget URL [ФАЙЛ]   Начать загрузку файла\n";
$mes.="fmget stop         Приостановить загрузку\n";
$mes.="fmget start        Продолжить после паузы\n";
$mes.="fmget del          Удалить файл\n";
$mes.="fmget config       Конфигурация email\n";

// обработка параметров командной строки
$gui=false;
$action='get';
$schange=false;
$web=false;
foreach ($argv as $n=>$p) {
	if ($p=='config') $action='config';
	if ($p=='stop') $action='stop';
	if ($p=='start') $action='start';
	if ($p=='del') $action='del';
	if ($p=='web') $web=true;
	if (strstr($p, 'http://')) {
		$url=trim($p);
		if ($win) $url=iconv('CP866', 'UTF-8', $url);
	}
	if (($action=='get') and @strstr($argv[$n-1], 'http://')) {
		$file=$p;
		if ($win) $file=iconv('CP866', 'UTF-8', $file);
	}
	if ($p=='shutdown') {
		file_put_contents("$basedir/shutdown.txt", "");
		mwrite("Система будет отключена после завершения загрузки\n");
		$schange=true;
	}
	if ($p=='noshutdown') {
		unlink("$basedir/shutdown.txt");
		mwrite("Система не будет отключена после завершения загрузки\n");
		$schange=true;
	}
	if ($p=='gui') {
		$gui=true;
		file_put_contents("$basedir/last.txt", '');
		file_put_contents("$basedir/log.txt", '');
	}
}

if (($action=='start') and empty($info['file'])) {
	$action='get';
	$web=true;
}

if (empty($cnf)) {
	$action='config';
} else {
	$rurl=$serverurl.'?email='.urlencode($cnf['email']).'&pass='.urlencode($cnf['spass']);
}

// запрос файла
if ($action=='get') {
	if (empty($url) and $schange) {sleep(3);exit;}
	if (empty($url) and (!$web)) {mwrite($mes);exit;}
	// если инфо не пустое, значит загружается файл и его надо докачать или удалить
	if (!empty($info)) {mwrite("Ошибка. Уже загружается $info[file]. Используйте fmget del для удаления\n");exit;}
	foreach (glob("$basedir/data/*.part") as $filename) {
    	unlink($filename);
	}
	mwrite("Запрос файла\n");
	if ($web) $url='web';
	// посылаем запрос серверу
	$res=unserialize(file_get_contents("$rurl&mode=get&partsize=$cnf[partsize]&url=".urlencode($url)));
	if (!$res) {mwrite("Ошибка. Сервер не доступен $res\n");exit;}
	if ($res['status']!='ok') {mwrite("Ошибка. $res[mes]\n");exit;}
	$info=$res;
	// url файла
	$url=$info['url'];
	mwrite("URL: $url\n");
	mwrite("Размер: $info[size]\n");
	mwrite("Частей: ".count($info['parts'])."\n");
	// имя файла
	if (empty($file) or $web) {
		$aurl=preg_replace('|\?.*$|', '', $url);
		$file=basename(str_replace('http://', '', $aurl));
		if (empty($file)) $file='file';
		if (is_dir('../files/')) $file="../files/$file";
	}
	file_put_contents($file, "");
	$file=realpath($file);
	if ((!file_exists($file)) or is_dir($file)) {mwrite("Ошибка записи в $file\n");exit;}
	$info['file']=$file;
	// количество обработанных частей и номер ожидаемой части
	$info['cnum']=0;
	// записываем инфо
	file_put_contents("$basedir/info.txt", serialize($info));
	@unlink("$basedir/stop.txt");
	$astart=true;
}

// возобновление загрузки файла
if ($action=='start') {
	if (empty($info['file'])) {mwrite("Ошибка. Файл не найден\n");exit;}
	$file=$info['file'];
	if ($info['cnum']>=count($info['parts'])) {mwrite("Ошибка. Файл уже загружен\n");exit;}
	// ожидаемый размер файла
	$csize=$info['cnum']*$info['partsize'];
	/*$rsile=filesize($file);
	if ($csize!=$rsile) {
		mwrite("Размер файла $rsile, а ожидается $csize. Урезать и продолжить загрузку? [y/n]\n");
		if (mread()!='y') exit;
		$buf=file_get_contents($file);
		$buf=substr($buf, 0, $csize);
		file_put_contents($file, $buf);
		unset($buf);
	}*/
	mwrite("Запрос части $info[cnum]\n");
	// отправляем запрос части
	$res=unserialize(file_get_contents("$rurl&mode=rget&rid=$info[rid]&num=$info[cnum]"));
	if (!$res) {mwrite("Ошибка. Сервер не доступен $res\n");exit;}
	if ($res['status']!='ok') {mwrite("Ошибка. $res[mes]\n");exit;}
	$astart=true;
}

// остановка загрузки
if ($action=='stop') {
	$res=unserialize(file_get_contents("$rurl&mode=stop&rid=$info[rid]"));
	if (!$res) {mwrite("Ошибка. Сервер не доступен $res\n");exit;}
	if ($res['status']!='ok') {mwrite("Ошибка. $res[mes]\n");exit;}
	// это сигнал запущенному fmget остановится
	file_put_contents("$basedir/stop.txt", time());
	mwrite("OK\n");
	mwrite("Дождитесь завершения основного процесса\n");
	sleep(3);
	exit;
}

// удаление недогруженного файла
if ($action=='del') {
	file_get_contents("$rurl&mode=del");
	@unlink($info['file']);
	foreach (glob("$basedir/data/*.part") as $filename) {
    	unlink($filename);
	}
	$info=array();
	file_put_contents("$basedir/info.txt", serialize($info));
	if (file_exists("$basedir/stop.txt")) {
		unlink("$basedir/stop.txt");
	}
	if (file_exists("$basedir/shutdown.txt")) {
		unlink("$basedir/shutdown.txt");
	}
	mwrite("OK\n");
	sleep(3);
	exit;
}

// установка параметров
if ($action=='config') {
	if ($gui) {
		$newemail=true;
		$cnf=parse_ini_file("$basedir/config.ini");
	} else {
		$newemail=false;
		mwrite("Параметры сервера\n");
		mwrite("URL сервиса: ");
		//if (empty($cnf['serverurl'])) $cnf['serverurl']='';
		if (!empty($cnf['serverurl'])) mwrite('['.$cnf['serverurl'].'] ');
		$buf=mread();
		if (!empty($buf)) {$cnf['serverurl']=$buf;$newemail=true;}
		
		mwrite("Email: ");
		if (!empty($cnf['email'])) mwrite('['.$cnf['email'].'] ');
		$buf=mread();
		if (!empty($buf)) {$cnf['email']=$buf;$newemail=true;}
		
		mwrite("Размер части (mb): ");
		if (empty($cnf['partsize'])) $cnf['partsize']=1024*1024;
		if (!empty($cnf['partsize'])) mwrite('['.round($cnf['partsize']/1024/1024, 2).'] ');
		$buf=mread();
		if (!empty($buf)) $cnf['partsize']=round($buf*1024*1024);
		
		mwrite("SMTP сервер: ");
		if (!empty($cnf['smtphost'])) mwrite('['.$cnf['smtphost'].'] ');
		$buf=mread();
		if (!empty($buf)) {$cnf['smtphost']=$buf;$newemail=true;}
		
		mwrite("SMTP логин: (без авторизации - n)");
		if (empty($cnf['smtplogin'])) $cnf['smtplogin']='n';
		if (!empty($cnf['smtplogin'])) mwrite('['.$cnf['smtplogin'].'] ');
		$buf=mread();
		if (!empty($buf)) {$cnf['smtplogin']=$buf;$newemail=true;}
		
		mwrite("SMTP пароль: (без авторизации - n)");
		if (empty($cnf['smtppass'])) $cnf['smtppass']='n';
		if (!empty($cnf['smtppass'])) mwrite('['.$cnf['smtppass'].'] ');
		$buf=mread();
		if (!empty($buf)) {$cnf['smtppass']=$buf;$newemail=true;}
		
		
		mwrite("Параметры клиента\n");
		mwrite("POP3 сервер: ");
		if (!empty($cnf['host'])) mwrite('['.$cnf['host'].'] ');
		$buf=mread();
		if (!empty($buf)) $cnf['host']=$buf;
		
		mwrite("POP3 логин: ");
		if (!empty($cnf['login'])) mwrite('['.$cnf['login'].'] ');
		$buf=mread();
		if (!empty($buf)) $cnf['login']=$buf;
		
		mwrite("POP3 пароль: ");
		if (!empty($cnf['pass'])) mwrite('['.$cnf['pass'].'] ');
		$buf=mread();
		if (!empty($buf)) $cnf['pass']=$buf;
		
		
	}
	if (!strstr($cnf['serverurl'], 'http://')) $cnf['serverurl']='http://'.$cnf['serverurl'];
	// если изменился email, то надо послать запрос на активацию
	if ($newemail) {
		$serverurl=@$cnf['serverurl'];
		$serverurl=preg_replace('|/$|', '', $serverurl);
		$lurl=$serverurl;
		$serverurl.='/req.php';
		// подключение к pop3
		$pop3=new Net_POP3();
		$pop3->connect($cnf['host'], 110);
		$pop3->login($cnf['login'], $cnf['pass'], 'USER');
		// запрос кол-ва сообщений
		$n=$pop3->numMsg();
		// отправка запроса
		$smtplogin=$cnf['smtplogin'];
		$smtppass=$cnf['smtppass'];
		if ($smtplogin=='n') $smtplogin='';
		if ($smtppass=='n') $smtppass='';
		$opass=@$cnf['spass'];
		$res=unserialize($fres=file_get_contents("$serverurl?mode=reg&email=".urlencode($cnf['email'])."&opass=$opass".
		"&smtphost=".urlencode($cnf['smtphost'])."&smtplogin=".urlencode($smtplogin).
		"&smtppass=".urlencode($smtppass)));
		if (!$res) {mwrite("Ошибка. Сервер не доступен $fres\n");exit;}
		if ($res['status']!='ok') {mwrite("Ошибка. $res[mes]\n");exit;}
		mwrite("Ожидание активации...\n");
		// ждем письма с паролем
		while($pop3->numMsg()==$n) {
			sleep(5);
			$pop3->disconnect();
			$pop3->connect($cnf['host'], 110);
			$pop3->login($cnf['login'], $cnf['pass'], 'USER');
		}
		$h=$pop3->getParsedHeaders($n+1);
		$buf=$pop3->getBody($n+1);
		if (!$pop3->deleteMsg($n+1)) {mwrite("Ошибка. Сообщение не удалено\n");exit;}
		if (!preg_match('|pass:\s+(\S{32})|', $buf, $m)) exit;
		// запись пароля
		$cnf['spass']=$m[1];
		// отправка подтверждения
		$res=unserialize(file_get_contents("$serverurl?mode=reg&apass=$cnf[spass]&email=".urlencode($cnf['email'])));
		if (!$res) {mwrite("Ошибка. Сервер не доступен $res\n");exit;}
		if ($res['status']!='ok') {mwrite("Ошибка. $res[mes]\n");exit;}
		mwrite("OK\n");
		$pop3->disconnect();
		$flink="[InternetShortcut]\r\nURL=$lurl/profile.php?email=".urlencode($cnf['email'])."&pass=".urlencode($cnf['spass'])."\r\n";
		file_put_contents('../fmget-list.url', $flink);
		mwrite("Используйте fmget-list для управления файлами\n");
	}
	// записываем конфигурацию
	if ($gui) file_put_contents("$basedir/status.txt", 'ok');
	file_put_contents("$basedir/config.txt", serialize($cnf));
	exit;
}

if ($gui) file_put_contents("$basedir/status.txt", 'begin');
// кол-во частей всего
$pcount=count($info['parts']);
// кол-во писем в ящике
$nmes=0;
// ид запроса
$rid=$info['rid'];
// пауза
if (empty($cnf['pause'])) $pause=20; else $pause=$cnf['pause'];
$mainstart=true;
// основной цикл
for ($cnum=$info['cnum']; $cnum<$pcount; $cnum++) {
	$maxcheck=120;
	if ($cnum>5) $maxcheck=60;
	if ($cnum>15) $maxcheck=20;
	if (!$mainstart) {
		mwrite(round($cnum/$pcount*100)."% ($cnum/$pcount) Ожидание...      \r");
	} else {
		mwrite(round($cnum/$pcount*100)."% ($cnum/$pcount) Загрузка...      \r");
		$mainstart=false;
		$maxcheck=2;
	}
	// спим паузу
	sleep($pause);
	// подключение к pop3
	if (!empty($pop3)) $pop3->disconnect();
	$pop3=new Net_POP3();
	$pop3->connect($cnf['host'], 110);
	$pop3->login($cnf['login'], $cnf['pass'], 'USER');
	// кол-во проверок
	$ncheck=0;
	// кол-во ошибок
	$err=0;
	// проверка почты
	while ($pop3->numMsg()==$nmes) {
		// отключение от pop3
		$pop3->disconnect();
		// спим 10 сек
		sleep(10);
		if ($ncheck>$maxcheck) {
			$res=unserialize(file_get_contents("$rurl&mode=loaderstatus"));
			if (!$res) {mwrite("\nСервер не доступен $res\n");}
			if ($res['status']!='ok') {mwrite("\n$res[mes]\n");}
			if ($res['loaderstatus']=='load') {
				mwrite(round($cnum/$pcount*100)."% ($cnum/$pcount) Загрузка... ($res[loadnum])      \r");
				$ncheck=0;
			} elseif ($maxcheck==2) {
				$maxcheck=120;
				$ncheck=0;
			} else {
				mwrite("Timeout                    \n");
				if ($err>30) {mwrite("Ошибка. Количество попыток исчерпано\n");exit;}
				if ($err>1) {
					mwrite("Пауза 10 мин...\n");
					sleep(600);
				}
				mwrite("Запрос части $cnum\n");
				$res=unserialize(file_get_contents("$rurl&mode=rget&rid=$rid&num=$cnum"));
				if (!$res) {mwrite("\nСервер не доступен $res\n");}
				if ($res['status']!='ok') {mwrite("\n$res[mes]\n");}
				$ncheck=0;
				$err++;
			}
		}
		$ncheck++;
		$pop3->connect($cnf['host'], 110);
		$pop3->login($cnf['login'], $cnf['pass'], 'USER');
	}
	if ($astart) {
		$astart=false;
	} else {
		// подбираем паузу
		if ($ncheck==0) $pause-=10;
		if ($ncheck>2) $pause+=10;
		if ($pause<0) $pause=0;
	}
	// обработка писем
	for ($i=1; $i<=$pop3->numMsg()-$nmes; $i++) {
		$h=$pop3->getParsedHeaders($i);
		// если письмо не наше, то пропускаем его
		if (!preg_match("|fmail\s+request\s+(\d+)\s+(\d+)\s+|", $h['Subject'], $m)) {$nmes++;continue;}
		// если ид запроса не совпадает, то это наверно от старой скачки - удаляем
		if ($m[2]!=$rid) {$pop3->deleteMsg($i);$cnum--;continue;}
		$rnum=$m[1];
		// если это с уже полученной частью, то тоже удаляем
		if ($rnum<$cnum) {$pop3->deleteMsg($i);$cnum--;continue;}
		// а если с более старшей, то удаляем и посылаем повторный запрос
		if ($rnum>$cnum) {
			mwrite("Получена часть $rnum, а ожидалась $cnum\n");
			$pop3->deleteMsg($i);
			mwrite("Запрос части $cnum\n");
			$res=unserialize(file_get_contents("$rurl&mode=rget&rid=$rid&num=$cnum"));
			if (!$res) {mwrite("\nСервер не доступен\n");}
			if ($res['status']!='ok') {mwrite("\n$res[mes]\n");}
			$cnum--;continue;
		}
		// если все нормально, то идем дальше
		/*if (!file_exists("$basedir/stop.txt")) {*/
			// посылаем запрос, что часть получена
			$res=unserialize(file_get_contents("$rurl&mode=ok&rid=$rid&num=$cnum"));
			if (!$res) {mwrite("Сервер не доступен $res\n");}
			if ($res['status']!='ok') {mwrite("$res[mes]\n");}
		/*}*/
		mwrite(round($cnum/$pcount*100)."% ($cnum/$pcount) Получение...      \r");
		// загрузка письма
		$b=$pop3->getBody($i);
		// и удаление
		$pop3->deleteMsg($i);
		mwrite(round($cnum/$pcount*100)."% ($cnum/$pcount) Обработка...      \r");
		// извлечение и декодировка
		$part=base64_decode(substr($b, strpos($b, "fmail:begin\r\n\r\n")+15, strpos($b, "\r\n\r\nfmail:end")-15));
		// извлечение хеша
		$md5=substr($b, strpos($b, "\nmd5: ")+6, 32);
		unset($b);
		$an=0;
		for ($k=0; $k<6-strlen($cnum); $k++) $an.='0';
		// запись части в файл
		file_put_contents("$basedir/data/$an$cnum.part", $part);
		unset($part);
		// проверка хешей
		if (md5_file("$basedir/data/$an$cnum.part")!=$md5) {
			mwrite("Ошибка. md5 не совпали $md5 ".md5($part)." . Часть $cnum размер ".strlen($part)."\n");
			unlink("$basedir/data/$an$cnum.part");
			exit;
		}
		
		$info['cnum']=$cnum+1;
		// запись инфо
		file_put_contents("$basedir/info.txt", serialize($info));
		$cnf['pause']=$pause;
		file_put_contents("$basedir/config.txt", serialize($cnf));
		if (file_exists("$basedir/stop.txt")) {
			unlink("$basedir/stop.txt");
			mwrite("Остановлено. Получено $info[cnum] частей.\n");
			if ($gui) file_put_contents("$basedir/status.txt", 'stop');
			exit;
		}
	}
	$pop3->disconnect();
	unset($pop3);
}
sleep(5);
// сборка файла
	chdir($basedir);
	exec("cat data/*.part > \"$file\"");

mwrite("Файл ".basename($file)." загружен\n");
if ($gui) file_put_contents("$basedir/status.txt", 'ok');
// удаление на сервере
file_get_contents("$rurl&mode=del");
// отчистка инфо
$info=array();
file_put_contents("$basedir/info.txt", serialize($info));

$res=unserialize(file_get_contents("$rurl&mode=loaderstatus"));
if (!$res) {mwrite("\nСервер не доступен $res\n");}
if ($res['listcount']>0) {
	$nofirst=true;
	$argv=array('web');
	include(__FILE__);
	exit;
}

// сигнал выключить машину
if (file_exists("$basedir/shutdown.txt")) {
	unlink("$basedir/shutdown.txt");
	if ($win) {
		exec('shutdown -s');
	} else {
		exec('shutdown -h now');
	}
}


?>