<?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');
}
}
?>