├── .gitignore
├── LICENSE
├── README.md
├── board.sql
├── install.sh
├── proftpd.conf
├── rm.sh
└── src
├── .htaccess
├── bootstrap
├── css
│ ├── bootstrap-theme.css
│ ├── bootstrap-theme.min.css
│ ├── bootstrap.css
│ └── bootstrap.min.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
└── js
│ ├── bootstrap.js
│ └── bootstrap.min.js
├── controllers
├── action.php
├── admin.php
├── boxe.php
├── compte.php
├── connect.php
├── downloads.php
├── layout
│ ├── default.php
│ └── external.php
├── messagerie.php
├── rss.php
├── stats.php
└── torrents.php
├── core
├── bdd.php
├── controller.php
├── core.php
├── languages
│ ├── en.php
│ └── fr.php
└── tools.php
├── favicon.ico
├── index.php
├── models
├── Transmission.php
├── bdecode.php
├── cloud.php
├── download.php
├── rpc.php
├── rss.php
├── rssm.php
├── stats.php
├── torrent.php
├── torrents.php
├── user.php
├── xfer.php
└── zip.php
├── theme
├── css
│ ├── facelist.css
│ ├── facelist_ie.css
│ ├── farbtastic.css
│ ├── glyphicons.css
│ ├── jquery.pnotify.default.css
│ ├── jquery.pnotify.default.icons.css
│ └── style.min.css
├── fonts
│ ├── glyphicons-regular.eot
│ ├── glyphicons-regular.eot@
│ ├── glyphicons-regular.svg
│ ├── glyphicons-regular.ttf
│ └── glyphicons-regular.woff
├── images
│ ├── friendly-torrent-logo.png
│ ├── home.png
│ ├── loader.png
│ ├── login-colors.jpg
│ ├── token.gif
│ ├── token_hover.gif
│ ├── token_selected.gif
│ └── token_x.gif
└── scripts
│ ├── autocomplete.js
│ ├── farbtastic.js
│ ├── flot
│ ├── jquery.flot.js
│ ├── jquery.flot.pie.js
│ ├── jquery.flot.resize.js
│ └── jquery.flot.tooltip.js
│ ├── jquery-1.8.2.min.js
│ ├── jquery.autocomplete.js
│ ├── jquery.cookie.js
│ ├── jquery.facelist.js
│ ├── jquery.hammer.min.js
│ ├── jquery.pnotify.min.js
│ ├── jquery.tablesorter.min.js
│ ├── load.js
│ ├── plupload
│ └── js
│ │ ├── Descr.WD3
│ │ ├── jquery.plupload.queue
│ │ ├── Descr.WD3
│ │ ├── css
│ │ │ ├── Descr.WD3
│ │ │ └── jquery.plupload.queue.css
│ │ ├── img
│ │ │ ├── Descr.WD3
│ │ │ ├── backgrounds.gif
│ │ │ ├── buttons-disabled.png
│ │ │ ├── buttons.png
│ │ │ ├── done.gif
│ │ │ ├── error.gif
│ │ │ └── transp50.png
│ │ └── jquery.plupload.queue.js
│ │ ├── plupload.flash.swf
│ │ ├── plupload.full.js
│ │ └── plupload.silverlight.xap
│ └── script.php
├── tmp
└── band.txt
├── tornado
├── BitTornado
│ ├── BT1
│ │ ├── Choker.py
│ │ ├── Connecter.py
│ │ ├── Downloader.py
│ │ ├── DownloaderFeedback.py
│ │ ├── Encrypter.py
│ │ ├── FileSelector.py
│ │ ├── Filter.py
│ │ ├── HTTPDownloader.py
│ │ ├── NatCheck.py
│ │ ├── PiecePicker.py
│ │ ├── Rerequester.py
│ │ ├── Statistics.py
│ │ ├── Storage.py
│ │ ├── StorageWrapper.py
│ │ ├── StreamCheck.py
│ │ ├── T2T.py
│ │ ├── Uploader.py
│ │ ├── __init__.py
│ │ ├── btformats.py
│ │ ├── fakeopen.py
│ │ ├── makemetafile.py
│ │ └── track.py
│ ├── BTcrypto.py
│ ├── ConfigDir.py
│ ├── ConfigReader.py
│ ├── ConnChoice.py
│ ├── CreateIcons.py
│ ├── CurrentRateMeasure.py
│ ├── HTTPHandler.py
│ ├── PSYCO.py
│ ├── RateLimiter.py
│ ├── RateMeasure.py
│ ├── RawServer.py
│ ├── ServerPortHandler.py
│ ├── SocketHandler.py
│ ├── __init__.py
│ ├── bencode.py
│ ├── bitfield.py
│ ├── clock.py
│ ├── download_bt1.py
│ ├── inifile.py
│ ├── iprangeparse.py
│ ├── launchmanycore.py
│ ├── natpunch.py
│ ├── parseargs.py
│ ├── parsedir.py
│ ├── piecebuffer.py
│ ├── selectpoll.py
│ ├── subnetparse.py
│ ├── torrentlistparse.py
│ └── zurllib.py
├── btmakemetafile.py
├── btshowmetainfo.py
├── tftornado.py
├── tftornado.py.save
└── tornado.pyproj
├── uploadify
├── jquery.uploadify.js
├── jquery.uploadify.min.js
├── uploadify.css
└── uploadify.swf
└── views
├── Admin
├── editUser.php
├── index.php
└── newUser.php
├── Boxe
└── index.php
├── Compte
└── index.php
├── Connect
└── index.php
├── Downloads
└── index.php
├── Rss
└── index.php
├── Stats
└── stats.php
├── Torrents
└── index.php
├── layout
├── default.php
├── external.php
└── header.php
└── messagerie
├── chat.php
├── index.php
└── message.php
/.gitignore:
--------------------------------------------------------------------------------
1 | ### PHPSTORM ###
2 | .idea
3 |
4 | ### MAC ###
5 | .com.apple.timemachine.supported
6 |
7 | ### CONFIG FOLDER ###
8 | /src/core/config/*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |  FriendlyTorrent
2 | =======
3 |
4 | FriendlyTorrent is a web PHP script to download torrents with a beautiful an intuitive web responsive interface.
5 | Moreover it allow you to explore and share download files "in the cloud" with your friends.
6 | This software is based on [Transmission](http://www.transmissionbt.com) torrent software.
7 |
8 | This is a BETA version, maybe you can help us ? :) [TODO List](https://github.com/Cclleemm/FriendlyTorrent/wiki/TODO)
9 |
10 | 
11 |
12 | ### What's included
13 |
14 | Within the download you'll find the following directories and files. You'll see something like this:
15 |
16 | ```
17 | bootstrap/
18 | ├── board.sql
19 | ├── install.sh
20 | └── src/
21 | ├── bootstrap/
22 | ├── controllers/
23 | ├── core/
24 | ├── models/
25 | ├── theme/
26 | ├── tmp/
27 | ├── tornado/
28 | ├── uploadify/
29 | ├── views/
30 | ├── .htaccess
31 | ├── favicon.ico
32 | └── index.php
33 | ```
34 |
35 |
36 | ## Automatic installation (Ubuntu, Debian ...)
37 | * [Download the latest release](https://github.com/Cclleemm/FriendlyTorrent/archive/master.zip).
38 | * run the install wizard with this following commands
39 |
40 | ```
41 | sudo chmod +x ./install.sh
42 | sudo ./install.sh
43 | ```
44 | * Enable HTACESS for the web folder (vhost file).
45 |
46 | Solution to enable HTACCESS but it's not secure :
47 |
48 | ```
49 | sudo nano /etc/apache2/apache2.conf
50 | ```
51 | Change Directory directive
52 | ```
53 |
54 | Options Indexes FollowSymLinks
55 | AllowOverride None
56 | Require all granted
57 |
58 | ```
59 |
60 | To
61 |
62 | ```
63 |
64 | Options Indexes FollowSymLinks
65 | AllowOverride All
66 | Require all granted
67 |
68 | ```
69 | Then, restart the apache service
70 |
71 | ```
72 | sudo service apache2 restart
73 | ```
74 |
75 | Go to : http://localhost/
76 |
77 | ## Manual installation
78 |
79 | ### Dependencies
80 | You must have installed this before :
81 | * Apache2
82 | * php5
83 | * mysql-server
84 | * libapache2-mod-php5
85 | * php5-curl
86 | * php5-mysql
87 | * memcached
88 | * php5-memcache
89 | * php5-memcached
90 | * transmission
91 | * transmission-daemon
92 | * zip
93 |
94 | ### Files Import
95 | Put all files of the `src/` folder in your web folder (for example in /var/www/).
96 |
97 | Create the download folder where all your downloads will be stored (ex : /var/downloads/)
98 |
99 | Create `.transfert` folder (ex : /var/downloads/.transferts/)
100 |
101 | Create user folder (ex : /var/downloads/user-name/)
102 |
103 | Give folders rights with `sudo chown www-data /var/downloads/ -R`
104 |
105 | Cofigure the `src/core/config/global.php` file with yours settings :
106 | ```
107 |
112 | ```
113 |
114 | ### MySQL Import
115 | Import the MySQL database `board.sql`
116 |
117 | Configure the `src/core/config/bdd.php` file with yours settings :
118 | ```
119 |
126 | ```
127 |
128 | Add user in the `users` table with MD5 encryption for the password :
129 | ```
130 | insert into users(login,mail,password,boxe,couleur,lastScan,rss,admin,port) values('USERNAME','-','MD5_PASSWORD','/YOUR_DOWNLOADS_FLODER/USERNAME', '78ba00', 0, '', 1, 9091);
131 | ```
132 |
133 | ### Apache Configuration
134 |
135 | Enable memcache in your `php.ini` file (/etc/php5/apache2/php.ini) adding line `extension=memcache.so`
136 |
137 | Enable HTACESS for the web folder.
138 |
139 | Solution to enable HTACCESS but it's not secure :
140 |
141 | ```
142 | sudo nano /etc/apache2/apache2.conf
143 | ```
144 | Change Directory directive
145 | ```
146 |
147 | Options Indexes FollowSymLinks
148 | AllowOverride None
149 | Require all granted
150 |
151 | ```
152 |
153 | To
154 |
155 | ```
156 |
157 | Options Indexes FollowSymLinks
158 | AllowOverride All
159 | Require all granted
160 |
161 | ```
162 |
163 |
164 |
165 | Add thoose lines in the cron table `/etc/cron.d/php5`
166 | ```
167 | */1 * * * * www-data wget "http://localhost/action/refreshTorrent/" -O /dev/null' >> /etc/cron.d/php5
168 | ```
169 |
170 |
171 | ### Initialization
172 | Restart cron `sudo /etc/init.d/cron restart`
173 |
174 | Restart Apache `sudo service apache2 reload`
175 |
176 | Stop transmission `sudo service transmission stop`
177 |
178 | Go to : http://localhost/
179 |
180 | ***
181 |
182 | Read the [Official Website](http://cclleemm.github.io/FriendlyTorrent/) for more information.
183 |
184 | ***
185 |
186 |
187 | ## Community
188 |
189 | Keep track of development and community news.
190 |
191 | * Follow [@FriendlyTorrent on Twitter](http://twitter.com/friendlytorrent).
192 | * Read and subscribe to [The Official Website](http://friendlytorrent.com).
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | checkInstall()
4 | {
5 | echo "------------ Check for $1 depedency ------------"
6 |
7 | PKG_OK=$(dpkg-query -W --showformat='${Status}\n' $1|grep "install ok installed")
8 | echo Checking for $1: $PKG_OK
9 | if [ "" == "$PKG_OK" ]; then
10 | echo "No $1. Setting up $1."
11 | if [ $1 == "sudo" ]; then
12 | apt-get --force-yes --yes install $1
13 | else
14 | sudo apt-get --force-yes --yes install $1
15 | fi
16 | fi
17 | }
18 |
19 | checkInstall sudo
20 | checkInstall apache2
21 | a2enmod rewrite
22 | checkInstall php5
23 | checkInstall mysql-server
24 | checkInstall libapache2-mod-php5
25 | checkInstall php5-curl
26 | checkInstall php5-mysql
27 | checkInstall memcached
28 | checkInstall php5-memcache
29 | checkInstall php5-memcached
30 | checkInstall transmission
31 | checkInstall transmission-daemon
32 | checkInstall zip
33 |
34 |
35 | echo "----------------------------------------------------"
36 | echo "Welcome in the Friendly Torrent installation wizard"
37 | echo "----------------------------------------------------"
38 |
39 | #Ask for Website dir
40 | echo -n "Application language (fr or en) [default : en] "
41 | read language
42 | if [[ $language == "" ]]
43 | then
44 | language=en
45 | fi
46 | echo -n "Website directory [default : /var/www/] "
47 | read websiteFolder
48 | if [[ $websiteFolder == "" ]]
49 | then
50 | websiteFolder=/var/www/
51 | fi
52 |
53 | cd src
54 | cp -R ./ $websiteFolder 1> /dev/null
55 | cd ..
56 | echo "Files copied"
57 |
58 | echo -n "Admin login : "
59 | read login
60 | echo -n "Admin password : "
61 | read -s pass
62 | echo ""
63 |
64 | #Ask for download storage folder
65 | echo -n "Downloads storage folder [default : /var/downloads/] "
66 | read dossierBoxes
67 | if [[ $dossierBoxes == "" ]]
68 | then
69 | dossierBoxes=/var/downloads/
70 | fi
71 | if mkdir $dossierBoxes
72 | then
73 | echo "Folder created with success "
74 | else
75 | echo "Can't create this folder"
76 | fi
77 |
78 | mkdir "$dossierBoxes/$login/"
79 | mkdir "$dossierBoxes/.transferts/"
80 | sudo chown www-data $dossierBoxes -R
81 |
82 | echo "------------ PHP/Apache2 Configuration ------------ "
83 | echo 'extension=memcache.so' >> /etc/php5/apache2/php.ini
84 | echo "PHP Memcache extension enabled"
85 | echo '*/1 * * * * www-data wget "http://localhost/action/refreshTorrent/" -O /dev/null' >> /etc/cron.d/php5
86 |
87 | if [ -f "$websiteFolder/index.html" ]; then
88 | sudo mv "$websiteFolder/index.html" "$websiteFolder/index-old.html"
89 |
90 | fi
91 |
92 | echo "------------ MySQL configuration ------------ "
93 |
94 | while true; do
95 | echo -n "MySQL user : "
96 | read userBDD
97 | echo -n "MySQL password : "
98 | read -s passBDD
99 | echo ""
100 | echo -n "MySQL database: "
101 | read bdd
102 | mysql -u $userBDD -p$passBDD -e "CREATE DATABASE IF NOT EXISTS $bdd;"
103 | if mysql -u $userBDD -p$passBDD $bdd < board.sql
104 | then
105 | echo "Database importation succeed ! "
106 | break
107 | else
108 | echo "Can't import the database !"
109 | fi
110 |
111 | done
112 |
113 | md5=`echo -n $pass|md5sum|awk '{ print $1 }'`
114 | mysql -u $userBDD -p$passBDD $bdd << EOF
115 | insert into users(login,mail,password,boxe,couleur,lastScan,rss,admin,port) values('$login','-','$md5','$dossierBoxes/$login', '78ba00', 0, '', 1, 9091);
116 | EOF
117 |
118 | mkdir "$websiteFolder""core/config/"
119 |
120 | echo "" > "$websiteFolder""core/config/bdd.php"
130 |
131 | echo "" > "$websiteFolder""core/config/global.php"
136 |
137 | sudo service apache2 reload
138 | sudo service transmission-daemon stop
139 | sudo /etc/init.d/cron restart
140 |
141 | echo "----------------------------------------------------"
142 | echo "----- Thank you for installing Friendly Torrent ----"
143 | echo "---------- Don't forget to enable HTACCESS ---------"
144 | echo "----------- And go to : http://localhost -----------"
145 | echo "----------------------------------------------------"
146 |
--------------------------------------------------------------------------------
/rm.sh:
--------------------------------------------------------------------------------
1 | sudo apt-get remove apache2
2 | sudo apt-get remove php5
3 | sudo apt-get remove mysql-server
4 | sudo apt-get remove libapache2-mod-php5
5 | sudo apt-get remove php5-mysql
--------------------------------------------------------------------------------
/src/.htaccess:
--------------------------------------------------------------------------------
1 | RewriteEngine on
2 | Options +FollowSymlinks
3 |
4 | RewriteRule ^/$ index.php?p=accueil [L,QSA]
5 | RewriteRule ^$ index.php?p=accueil [L,QSA]
6 |
7 | RewriteRule ^connect/([a-zA-Z0-9\-\_\/]*)$ index.php?p=connect/$1 [L,QSA]
8 | RewriteRule ^boxe/([a-zA-Z0-9\-\_\/]*)$ index.php?p=boxe/$1 [L,QSA]
9 | RewriteRule ^action/([a-zA-Z0-9\-\_\/]*)$ index.php?p=action/$1 [L,QSA]
10 | RewriteRule ^downloads/(.*)$ index.php?p=downloads/index/$1 [L,QSA]
11 | RewriteRule ^torrents/([a-zA-Z0-9\-\_\/]*)$ index.php?p=torrents/$1 [L,QSA]
12 | RewriteRule ^compte/([a-zA-Z0-9\-\_\/]*)$ index.php?p=compte/$1 [L,QSA]
13 | RewriteRule ^gks/([a-zA-Z0-9\-\_\/]*)$ index.php?p=gks/$1 [L,QSA]
14 | RewriteRule ^messagerie/([a-zA-Z0-9\-\_\/]*)$ index.php?p=messagerie/$1 [L,QSA]
15 | RewriteRule ^rss/([a-zA-Z0-9\-\_\/]*)$ index.php?p=rss/$1 [L,QSA]
16 | RewriteRule ^admin/([a-zA-Z0-9\-\_\/]*)$ index.php?p=admin/$1 [L,QSA]
17 | RewriteRule ^stats/([a-zA-Z0-9\-\_\/]*)$ index.php?p=stats/$1 [L,QSA]
--------------------------------------------------------------------------------
/src/bootstrap/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/bootstrap/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/src/bootstrap/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/bootstrap/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/src/bootstrap/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/bootstrap/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/src/controllers/boxe.php:
--------------------------------------------------------------------------------
1 | LANG_TITLE);
16 |
17 | ////////////////////////////////////
18 | // ACTION INDEX //
19 | ////////////////////////////////////
20 |
21 | function index(){
22 | $d = array();
23 |
24 | Tools::scanBoxe(Core::idCo());
25 |
26 | $boxe = new Cloud();
27 | $d['boxe'] = $boxe->boxeData;
28 |
29 | $xfer = new Xfer(Core::idCo());
30 | $xfer->scanTorrent();
31 | $stats = $xfer->getStat();
32 |
33 | $d['uploadTotal'] = $stats['up'];
34 | $d['downloadTotal'] = $stats['down'];
35 |
36 | $d['color'] = $d['boxe']['couleur'];
37 |
38 | $totalspace = disk_total_space(ROOT_DOWNLOADS);
39 | $freespace = disk_free_space(ROOT_DOWNLOADS);
40 |
41 | $free = 100;
42 |
43 | $d['pourcent'] = round((Tools::dirsize($boxe->boxeData['boxe']) / $totalspace)*100);
44 | $d['space'] = Tools::dirsize($boxe->boxeData['boxe']);
45 |
46 | $this->set($d);
47 | $this->render('index');
48 | }
49 |
50 | function users($login){
51 | $d = array();
52 |
53 | $boxe = new Cloud($login);
54 | $d['boxe'] = $boxe->boxeData;
55 |
56 | Tools::scanBoxe($boxe->boxeData['id']);
57 |
58 | $xfer = new Xfer($boxe->boxeData['id']);
59 | $xfer->scanTorrent();
60 | $stats = $xfer->getStat();
61 |
62 | $d['uploadTotal'] = $stats['up'];
63 | $d['downloadTotal'] = $stats['down'];
64 |
65 | $this->title['users'] = $login."'s box";
66 | $this->setTitle();
67 |
68 | $totalspace = disk_total_space(ROOT_DOWNLOADS);
69 | $freespace = disk_free_space(ROOT_DOWNLOADS);
70 |
71 | $free = 100;
72 |
73 | $d['pourcent'] = round((Tools::dirsize($boxe->boxeData['boxe']) / $totalspace)*100);
74 | $d['space'] = Tools::dirsize($boxe->boxeData['boxe']);
75 |
76 |
77 | $d['color'] = $d['boxe']['couleur'];
78 |
79 | $this->set($d);
80 | $this->render('index');
81 | }
82 |
83 | }
84 | ?>
--------------------------------------------------------------------------------
/src/controllers/compte.php:
--------------------------------------------------------------------------------
1 | LANG_TITLE_MY_ACCOUNT);
16 |
17 | ////////////////////////////////////
18 | // ACTION INDEX //
19 | ////////////////////////////////////
20 |
21 | function index(){
22 | $d = array();
23 |
24 | $d['user'] = $this->user->userData;
25 |
26 | if($this->post['oldPass'] != "" && $this->post['newPass'] != "" ){
27 | if(md5($this->post['oldPass']) == $d['user']['password']){
28 | if($this->post['newPass'] == $this->post['newPass2']){
29 | $this->user->changeMdp($this->post['newPass']);
30 | $d['java'] = '';
31 | }else{
32 | $d['error'] = LANG_PASSWORD_DIFERENT;
33 | }
34 | }else{
35 | $d['error'] = LANG_OLD_PASSWORD_DIFERENT;
36 | }
37 | }
38 |
39 | if($this->post['rss'] != $d['user']['rss'] && $this->post['rss']){
40 | $this->user->changeRss($this->post['rss']);
41 | $d['user']['rss'] = $this->post['rss'];
42 | }
43 |
44 | $this->set($d);
45 | $this->render('index');
46 | }
47 |
48 | }
49 | ?>
--------------------------------------------------------------------------------
/src/controllers/connect.php:
--------------------------------------------------------------------------------
1 | LANG_CONNECTION);
16 |
17 | ////////////////////////////////////
18 | // ACTION INDEX //
19 | ////////////////////////////////////
20 |
21 | function index(){
22 | $d = array();
23 |
24 | $this->setLayout('external');
25 |
26 | $user = new User();
27 |
28 | if($_POST['login'] != '' OR $_POST['mdp'] != ''){
29 | if($user->connect($_POST['login'], $_POST['mdp'])){
30 | header('Location: '.WEBROOT);
31 | }
32 | }
33 |
34 |
35 | $this->set($d);
36 | $this->render('index');
37 | }
38 |
39 | }
40 | ?>
--------------------------------------------------------------------------------
/src/controllers/layout/default.php:
--------------------------------------------------------------------------------
1 | models)){
22 | foreach($this->models as $v){
23 | $this->loadModel($v);
24 | }
25 | }
26 |
27 | parent::__construct();
28 | }
29 |
30 |
31 | ////////////////////////////////////
32 | // LISTE DES VARS ENVOYE AU LAYOUT//
33 | // DES VAR ENVOYE //
34 | // AU LAYOUT //
35 | ////////////////////////////////////
36 |
37 | function vars(){
38 |
39 | $tab = array();
40 |
41 | $user = new User();
42 |
43 | $tab['user'] = $user->userData;
44 |
45 | $sql = "SELECT users.* FROM users WHERE login != '".$tab['user']['login']."';";
46 | $rst = $this->bdd->query($sql);
47 |
48 | $tab['other'] = $rst;
49 |
50 | $freespace = disk_free_space(ROOT_DOWNLOADS);
51 | $tab['freespace'] = $freespace;
52 |
53 | $this->set($tab);
54 | }
55 |
56 |
57 | ////////////////////////////////////
58 | // FONCTION DE DECLARATION //
59 | // VAR DU LAYOUT //
60 | ////////////////////////////////////
61 |
62 | function set($d){
63 | $this->vars = array_merge($this->vars,$d);
64 | }
65 |
66 |
67 |
68 | ////////////////////////////////////
69 | // FONCTION DE Vu LAYOUT //
70 | ////////////////////////////////////
71 |
72 | function viewLayout($content){
73 |
74 | $this->vars();
75 |
76 | //Extraction pour le layout
77 | extract($this->vars);
78 |
79 | $content_for_layout = $content;
80 |
81 | //Affichage du layout
82 | require(ROOT.'views/layout/default.php');
83 |
84 | }
85 |
86 | ////////////////////////////////////
87 | // FONCTION DE LOAD MODEL //
88 | ////////////////////////////////////
89 |
90 | function loadModel($name){
91 | require_once(ROOT.'models/'.strtolower($name).'.php');
92 | }
93 |
94 | }
95 |
96 | ?>
--------------------------------------------------------------------------------
/src/controllers/layout/external.php:
--------------------------------------------------------------------------------
1 | models)){
22 | foreach($this->models as $v){
23 | $this->loadModel($v);
24 | }
25 | }
26 |
27 | parent::__construct();
28 | }
29 |
30 |
31 | ////////////////////////////////////
32 | // LISTE DES VARS ENVOYE AU LAYOUT//
33 | // DES VAR ENVOYE //
34 | // AU LAYOUT //
35 | ////////////////////////////////////
36 |
37 | function vars(){
38 |
39 | $tab = array();
40 | $this->set($tab);
41 | }
42 |
43 |
44 | ////////////////////////////////////
45 | // FONCTION DE DECLARATION //
46 | // VAR DU LAYOUT //
47 | ////////////////////////////////////
48 |
49 | function set($d){
50 | $this->vars = array_merge($this->vars,$d);
51 | }
52 |
53 |
54 |
55 | ////////////////////////////////////
56 | // FONCTION DE Vu LAYOUT //
57 | ////////////////////////////////////
58 |
59 | function viewLayout($content){
60 |
61 | $this->vars();
62 |
63 | //Extraction pour le layout
64 | extract($this->vars);
65 |
66 | $content_for_layout = $content;
67 |
68 | //Affichage du layout
69 | require(ROOT.'views/layout/external.php');
70 |
71 | }
72 |
73 | ////////////////////////////////////
74 | // FONCTION DE LOAD MODEL //
75 | ////////////////////////////////////
76 |
77 | function loadModel($name){
78 | require_once(ROOT.'models/'.strtolower($name).'.php');
79 | }
80 |
81 | }
82 |
83 | ?>
--------------------------------------------------------------------------------
/src/controllers/messagerie.php:
--------------------------------------------------------------------------------
1 | LANG_INBOX);
16 |
17 | ////////////////////////////////////
18 | // ACTION INDEX //
19 | ////////////////////////////////////
20 |
21 | function index(){
22 | $d = array();
23 |
24 |
25 | $sql = "SELECT users.login, users.id, messagerie.idUser, messagerie.idUserTarget, COUNT(messagerie.id) as nb FROM messagerie, users WHERE ((idUserTarget = '".Core::idCo()."' AND idUser != '".Core::idCo()."' AND users.id = messagerie.idUser) OR (idUser = '".Core::idCo()."' AND idUserTarget != '".Core::idCo()."' AND users.id = messagerie.idUserTarget) OR (idUser = '".Core::idCo()."' AND idUserTarget = '".Core::idCo()."' AND users.id = messagerie.idUser)) GROUP BY users.login ;";
26 | $messages = $this->bdd->query($sql);
27 |
28 | $messagesFinal = array();
29 |
30 | while($rslt = mysql_fetch_assoc($messages)){
31 | $sql = "SELECT messagerie.text, messagerie.time, messagerie.idUserTarget, messagerie.seen FROM messagerie WHERE ((idUserTarget = '".$rslt['idUserTarget']."' AND idUser = '".$rslt['idUser']."') OR (idUser = '".$rslt['idUserTarget']."' AND idUserTarget = '".$rslt['idUser']."')) ORDER BY messagerie.time DESC LIMIT 0, 1;";
32 | $message = $this->bdd->query($sql);
33 | $messageRst = mysql_fetch_assoc($message);
34 |
35 | $rslt['time'] = intval($messageRst['time']);
36 | $rslt['text'] = $messageRst['text'];
37 |
38 | if($messageRst['idUserTarget'] == Core::idCo())
39 | $rslt['seen'] = $messageRst['seen'];
40 | else
41 | $rslt['seen'] = 1;
42 |
43 | $messagesFinal[] = $rslt;
44 | }
45 | usort($messagesFinal, function($a, $b) {
46 |
47 | if ($a['time'] == $b['time']) {
48 | return 0;
49 | }
50 |
51 | return ($a['time'] > $b['time']) ? -1 : 1;
52 | });
53 |
54 | $d['messages'] = $messagesFinal;
55 |
56 | $this->set($d);
57 | $this->render('index');
58 | }
59 |
60 |
61 | function chat($idUser){
62 | $d = array();
63 |
64 | $sql = "SELECT messagerie.id, messagerie.text, users.login, users.mail, messagerie.time, messagerie.seen FROM messagerie, users, users as ut WHERE users.id = messagerie.idUser AND ut.id = messagerie.idUserTarget AND (idUserTarget = '".Core::idCo()."' AND idUser = '".$idUser."' OR idUser = '".Core::idCo()."' AND idUserTarget = '".$idUser."') ORDER BY messagerie.time DESC;";
65 | $d['messages'] = $this->bdd->query($sql);
66 |
67 | $sql = "UPDATE messagerie SET seen = 1 WHERE (idUserTarget = '".Core::idCo()."' AND idUser = '".$idUser."');";
68 | $rst = $this->bdd->query($sql);
69 |
70 | $user = new User($idUser);
71 |
72 | $d['idUser'] = $user->userData['id'];
73 |
74 | $this->title['chat'] = LANG_CONVERSATION_WITH." ".$user->userData['login'];
75 | $this->setTitle();
76 |
77 | $this->set($d);
78 | $this->render('chat');
79 | }
80 |
81 | function nouveau($idRep){
82 | $d = array();
83 |
84 | $user = new User();
85 |
86 | if($this->post['to_user'] && $this->post['message']){
87 |
88 | //NEW message
89 | $sql = "INSERT INTO messagerie VALUES ('', '".Core::idCo()."', '".$this->post['to_user']."', '".addslashes($this->post['message'])."', 0, '".time()."');";
90 | $this->bdd->query($sql);
91 | }
92 | header('Location: '.WEBROOT.'messagerie/chat/'.$this->post['to_user'].'/');
93 | }
94 |
95 | function delete($id){
96 | $sql = "DELETE FROM messagerie WHERE id = '".$id."';";
97 | $this->bdd->query($sql);
98 | header('Location: '.WEBROOT.'messagerie/');
99 | }
100 |
101 | }
102 | ?>
--------------------------------------------------------------------------------
/src/controllers/rss.php:
--------------------------------------------------------------------------------
1 | LANG_RSS);
16 |
17 | ////////////////////////////////////
18 | // ACTION INDEX //
19 | ////////////////////////////////////
20 |
21 | function index(){
22 | $d = array();
23 |
24 | $d['lien'] = $this->user->userData['rss'];
25 |
26 | $this->set($d);
27 | $this->render('index');
28 | }
29 |
30 | }
31 | ?>
--------------------------------------------------------------------------------
/src/controllers/stats.php:
--------------------------------------------------------------------------------
1 | LANG_CHARTS);
17 |
18 | ////////////////////////////////////
19 | // ACTION INDEX //
20 | ////////////////////////////////////
21 |
22 | function index(){
23 | $d = array();
24 |
25 | $total = 0;
26 | $totalOff = 0;
27 | $me = 0;
28 |
29 | $sql = "SELECT * FROM torrents;";
30 | $rst = $this->bdd->query($sql);
31 |
32 | while($rslt = mysql_fetch_assoc($rst)){
33 | ++$totalOff;
34 | if($rslt['idBoxe'] == Core::idCo())
35 | ++$me;
36 | }
37 |
38 | $d['total'] = $total;
39 | $d['totalOff'] = $totalOff;
40 | $d['me'] = $me;
41 |
42 | $totalspace = disk_total_space(ROOT_DOWNLOADS);
43 | $freespace = disk_free_space(ROOT_DOWNLOADS);
44 |
45 | // Ne rien changer par la suite
46 | $usedspace = $totalspace - $freespace;
47 | $pourcent = round(($usedspace / $totalspace)*100);
48 |
49 | $d['usedspace'] = $usedspace;
50 | $d['totalspace'] = $totalspace;
51 | $d['pourcent'] = $pourcent;
52 | $d['space'] = round(($freespace / $totalspace)*100);
53 | $d['free'] = Tools::convertFileSize($freespace);
54 |
55 | $sql = "SELECT users.login, users.mail, users.couleur, sessions.lastTime FROM sessions, users WHERE sessions.idUser = users.id AND lastTime >= '".(time()-(5*60))."' GROUP BY users.login ORDER BY sessions.lastTime DESC;";
56 | $rst = $this->bdd->query($sql);
57 |
58 | $d['connect'] = $rst;
59 |
60 |
61 | $xfer = new Xfer();
62 | $stats = $xfer->getStatTotal();
63 |
64 | $d['uploadTotal'] = $stats['up'];
65 | $d['downloadTotal'] = $stats['down'];
66 |
67 | $this->set($d);
68 | $this->render('stats');
69 | }
70 |
71 | }
72 | ?>
--------------------------------------------------------------------------------
/src/controllers/torrents.php:
--------------------------------------------------------------------------------
1 | LANG_TITLE_MY_TORRENTS);
16 |
17 | ////////////////////////////////////
18 | // ACTION INDEX //
19 | ////////////////////////////////////
20 |
21 | function index(){
22 | $d = array();
23 |
24 | $this->set($d);
25 | $this->render('index');
26 | }
27 |
28 | }
29 | ?>
--------------------------------------------------------------------------------
/src/core/bdd.php:
--------------------------------------------------------------------------------
1 | server = $BDD_MYSQL_SERVER;
31 | $this->user = $BDD_MYSQL_LOGIN;
32 | $this->pass = $BDD_MYSQL_PASS;
33 | $this->database = $BDD_MYSQL_BDD;
34 |
35 | $this->memcache = new Memcache;
36 | $this->memcache->connect('localhost', 11211) or die ("Connexion impossible");
37 |
38 | }
39 |
40 | ////////////////////////////////////
41 | ////////////////////////////////////
42 | // MYSQL //
43 | ////////////////////////////////////
44 | ////////////////////////////////////
45 |
46 | public function clear(){
47 | $this->query = null;
48 | }
49 |
50 | public function getCache(){
51 | return $this->memcache;
52 | }
53 |
54 | //Fonction pour se connecter à la BDD MYSQL
55 | public function open(){
56 | // On vérifie avant si on est connecté ou pas
57 | if(!$this->connected){
58 | $this->co = mysql_connect($this->server, $this->user, $this->pass);
59 |
60 | $this->connected = true;
61 |
62 | mysql_select_db($this->database);
63 | }
64 | }
65 |
66 | // Fonction pour faire une requete MYSQL AVEC Cache pour éviter de faire la même requête mysql plusieure fois
67 | public function query($sql){
68 |
69 | if($this->query[($sql)] == NULL){
70 | $this->open();
71 | $temp = mysql_query($sql, $this->co) or die("Erreur: ".mysql_error()."
Requète: ".$sql);
72 |
73 | if($this->queryNb[($sql)]){
74 | $this->queryNb[($sql)][0]++;
75 | $this->queryNb[($sql)][1] = ($time - $this->timeStart);
76 | }else
77 | $this->queryNb[($sql)] =array(1, ($time - $this->timeStart));
78 |
79 | if($temp != 1 AND $temp != 0){
80 | $this->query[($sql)] = $temp;
81 |
82 | $num_rows = mysql_num_rows($temp);
83 | if($num_rows != false AND $num_rows != 0){
84 | mysql_data_seek($temp, 0);
85 | }
86 | }
87 | }else{
88 | $temp = $this->query[($sql)];
89 | $num_rows = mysql_num_rows($temp);
90 | if($num_rows != false AND $num_rows != 0){
91 | mysql_data_seek($temp, 0);
92 | }
93 | }
94 | return $temp;
95 | }
96 |
97 | // Fonction pour faire une requete MYSQL SANS CACHE
98 | public function queryNoCache($sql){
99 | $this->open();
100 | $temp = mysql_query($sql, $this->co) or die("Erreur: ".mysql_error()."
Requète: ".$sql);
101 | return $temp;
102 | }
103 |
104 | public function data($source){
105 |
106 | $result = array();
107 |
108 | while($rslt=mysql_fetch_assoc($source)){
109 | $return[]=$rslt;
110 | }
111 |
112 | return $return;
113 | }
114 | }
115 |
116 | ?>
--------------------------------------------------------------------------------
/src/core/controller.php:
--------------------------------------------------------------------------------
1 | post = $_POST;
26 | }
27 |
28 | //Sert pour charger les models utilisé
29 | if(isset($this->models)){
30 | foreach($this->models as $v){
31 | $this->loadModel($v);
32 | }
33 | }
34 |
35 | if($notLayout == false){
36 | $this->setLayout('default');
37 | $this->notLayout = false;
38 | }else{
39 | $this->notLayout = true;
40 | }
41 |
42 | if(Core::isCo()){
43 | $this->user = new User();
44 | }
45 |
46 | parent::__construct();
47 | }
48 |
49 | function virtual($adresse){
50 |
51 | $params = explode('/',$adresse);
52 | $controller = $params[0];
53 | $action = $params[1] != '' ? $params[1] : 'index';
54 |
55 | // Instancie le controller corespondant, ainsi que la fonction corespondant à l'action
56 | require(ROOT.'controllers/'.$controller.'.php');
57 | $controller = new $controller(true);
58 |
59 | if(method_exists($controller, $action)){
60 | unset($params[0]); unset($params[1]);
61 | $controller->action = $action;
62 | call_user_func_array(array($controller,$action),$params);
63 | }
64 | else{
65 | return false;
66 | }
67 | }
68 |
69 | ////////////////////////////////////
70 | // FONCTION DE DECLARATION //
71 | // d'envoi de valeurs au render //
72 | ////////////////////////////////////
73 |
74 | function set($d){
75 | $this->vars = array_merge($this->vars,$d);
76 | }
77 |
78 | ////////////////////////////////////
79 | // FONCTION DE DEFINITION //
80 | // DE LAYOUT //
81 | ////////////////////////////////////
82 |
83 | function setLayout($layout){
84 |
85 | //Exception ajax
86 | if($layout != '' AND $this->notLayout == false){
87 | $this->layout = $layout;
88 |
89 | include(ROOT.'controllers/layout/'.$this->layout.'.php');
90 |
91 | $aff = 'Layout'.$this->layout;
92 | $this->Layout = '';
93 | $this->Layout = new $aff;
94 | }else{
95 | $this->Layout = '';
96 | }
97 | }
98 |
99 | function setTitle(){
100 |
101 | $d['title'] = $this->title[$this->action];
102 | if(!$this->notLayout)
103 | $this->Layout->set($d);
104 | $this->set($d);
105 |
106 | }
107 |
108 | function setHeadMore($head){
109 | if(!$this->notLayout){
110 | $d['headMore'] = $head;
111 | $this->Layout->set($d);
112 | }
113 | }
114 |
115 | ////////////////////////////////////
116 | // FONCTION DE VU SANS LAYOUT //
117 | ////////////////////////////////////
118 |
119 | function viewSimple(){
120 | extract($this->vars);
121 | $lang = $this->lang;
122 |
123 | ob_start();
124 | require(ROOT.'views/'.get_class($this).'/'.$this->filename.'.php');
125 | return ob_get_clean();
126 | }
127 |
128 | ////////////////////////////////////
129 | // FONCTION D'AFFICHAGE //
130 | // affichage du render demandé //
131 | ////////////////////////////////////
132 |
133 | function render($filename){
134 |
135 | $this->filename = $filename;
136 |
137 | //Si Pas de layout on met les varables en places et on affiche JUSTE le contenu !
138 | if($this->layout==false){
139 | echo $this->viewSimple();
140 | if($this->title[$this->action] != ''){
141 | echo '';
142 | }
143 |
144 | }else{ // Sinon affichage spéciale sans layout
145 | $this->Layout->viewLayout($this->viewSimple());
146 | }
147 | }
148 |
149 | ////////////////////////////////////
150 | // FONCTION DE LOAD MODEL //
151 | ////////////////////////////////////
152 |
153 | function loadModel($name){
154 | require_once(ROOT.'models/'.strtolower($name).'.php');
155 |
156 | // On instancie à la main !
157 | //$this->$name = new $name();
158 | }
159 | }
160 | ?>
--------------------------------------------------------------------------------
/src/core/core.php:
--------------------------------------------------------------------------------
1 | bdd=new BDD;
35 |
36 |
37 | if($token){
38 | $sql = "SELECT sessions.*, users.admin FROM sessions, users WHERE users.id = sessions.idUser AND sessions.cle = '".$token."';";
39 | $query = $this->bdd->query($sql);
40 | $donnees = mysql_fetch_assoc($query);
41 | if($donnees['idUser']){
42 | $this->co = true;
43 | $this->idUser = $donnees['idUser'];
44 |
45 | $sql = "UPDATE sessions SET lastTime = '".time()."' WHERE cle = '".$token."';";
46 | $query = $this->bdd->query($sql);
47 |
48 | if($donnees['time'] < time()-(24*60*60)){
49 | $sql = "UPDATE sessions SET time = '".time()."' WHERE cle = '".$token."';";
50 | $query = $this->bdd->query($sql);
51 |
52 | setcookie('SEED_connect', $_COOKIE['SEED_connect'], (time() + 2592000), '/');
53 | }
54 |
55 | $this->admin = $donnees['admin'];
56 | }
57 | }
58 | }
59 | /**
60 | * Méthode qui crée l'unique instance de la classe
61 | * si elle n'existe pas encore puis la retourne.
62 | *
63 | * @param void
64 | * @return Singleton
65 | */
66 | public static function getInstance($token = '') {
67 |
68 | if(!$token)
69 | $token = $_COOKIE['SEED_connect'];
70 |
71 | if(is_null(self::$_instance)) {
72 | self::$_instance = new Core($token);
73 | }
74 | return self::$_instance;
75 | }
76 |
77 | /////////////////////
78 | // METHODES STATIC //
79 | /////////////////////
80 |
81 | static function isCo(){
82 | $Core = Core::getInstance();
83 |
84 | if($Core->co){
85 | return true;
86 | }else{
87 | return false;
88 | }
89 | }
90 |
91 | static function isAdmin(){
92 | $Core = Core::getInstance();
93 | if($Core->admin){
94 | return true;
95 | }else{
96 | return false;
97 | }
98 | }
99 |
100 | static function idCo(){
101 | $Core = Core::getInstance();
102 | if($Core->idUser){
103 | return $Core->idUser;
104 | }else{
105 | return false;
106 | }
107 |
108 | }
109 | }
110 |
111 | // PARENT A toutes les autres class ou lang et bdd est utile
112 | class Common {
113 |
114 | protected $bdd;
115 |
116 | function __construct(){
117 | // on utilise la seule instance du coeur ...
118 | $Core = Core::getInstance();
119 |
120 |
121 | //INITIALISATION de la base de donnée
122 | $this->bdd = $Core->bdd;
123 |
124 | }
125 | }
126 |
127 | ?>
128 |
--------------------------------------------------------------------------------
/src/core/languages/en.php:
--------------------------------------------------------------------------------
1 | Administrator !");
42 |
43 |
44 | //Boxes
45 | define("LANG_NAME", "Name");
46 | define("LANG_INFO", "Info");
47 | define("LANG_TYPE", "Type");
48 | define("LANG_SIZE", "Size");
49 | define("LANG_FILE", "File");
50 | define("LANG_FOLDER", "Folder");
51 | define("LANG_USE_ON_SERVER", "used on the server");
52 | define("LANG_OF_SERVER", "of server");
53 | define("LANG_TO_MUCH_SPACE", "Be careful, no a lot free space !");
54 | define("LANG_DOWNLOADING", "DOWNLOADING");
55 | define("LANG_NO_DOWNLOAD", "NO DL");
56 | define("LANG_DOWNLOADING_DESC", "Downloading");
57 | define("LANG_NO_DOWNLOAD_DESC", "You never download this file");
58 |
59 |
60 | //Account
61 | define("LANG_BASIC_INFO", "Basics informations");
62 | define("LANG_OLD_PASSWORD", "Old password");
63 | define("LANG_NEW_PASSWORD", "New password");
64 | define("LANG_LINK_RSS", "Link to RSS feed");
65 | define("LANG_PROFIL_PICTURE", "Profil picture");
66 | define("LANG_MANAGE_MY_PROFIL_PICTURE", "Manage my profil picture");
67 |
68 | //Connect
69 | define("LANG_CONNECTION", "Log In !");
70 | define("LANG_LOG_IN", "Log In");
71 |
72 | //Download
73 | define("LANG_YOU_WILL_DOWNLOAD", "You are going to download the ");
74 | define("LANG_START_DOWNLOAD", "Start the download");
75 | define("LANG_ERROR_INEXISTING", "Error : nothing to download !");
76 |
77 | //INBOX
78 | define("LANG_REPLY", "Reply");
79 | define("LANG_DELETE_MESSAGE", "Delete this message");
80 | define("LANG_MESSAGE_SENDED", "Message sended !");
81 | define("LANG_CONVERSATION_WITH", "Chat with ");
82 |
83 |
84 | //Charts
85 | define("LANG_NETWORK", "Network");
86 | define("LANG_MY_NETWORK", "My Network transferts");
87 | define("LANG_THIS_MONTH", "this month");
88 | define("LANG_MONTH_UPLOAD_USE", "Data uploaded this month");
89 | define("LANG_MONTH_DOWNLOAD_USE", "Data downloaded this month");
90 | define("LANG_DISK_SPACE", "Disk space");
91 |
92 | //Controllers actions
93 | define("LANG_NO_MORE_SPACE", "No more free space on the server");
94 | define("LANG_CANT_START_TORRENT", "Can't start the torrent");
95 | define("LANG_CANT_STOP_TORRENT", "Can't stop the torrent");
96 | define("LANG_TORRENT_ADDED", "Torrent added successfully");
97 | define("LANG_CANT_ADD_TORRENT", "Can't add this torrent");
98 | define("LANG_CANT_ADD_TORRENT_ALREADY", "Can't add this torrent because you already downloaded it.");
99 | define("LANG_CANT_DELETE_TORRENT", "Can't delete the torrent");
100 | define("LANG_CHOOSE_TORRENT", "Please choose a .torrent file !");
101 | define("LANG_FREE_SPACE", "Free space");
102 |
103 | //Controllers admin
104 | define("LANG_PASSWORD_DIFERENT", "New passwords are different");
105 | define("LANG_OLD_PASSWORD_DIFERENT", "Incorrect old password");
106 | define("LANG_CANT_CREATE_FOLDER", "Can't create boxe folder !");
107 |
108 | //Account
109 | define("LANG_PASSWORD_CHANGED", "Password changed successfully !");
110 |
111 | //Titles
112 | define("LANG_TITLE_ADMINISTRATION", "Administration panel");
113 | define("LANG_TITLE_MY_ACCOUNT", "My account");
114 | define("LANG_TITLE_MY_TORRENTS", "My torrents");
115 |
116 | ?>
--------------------------------------------------------------------------------
/src/core/languages/fr.php:
--------------------------------------------------------------------------------
1 | Administrateur !");
42 |
43 |
44 | //Boxes
45 | define("LANG_NAME", "Nom");
46 | define("LANG_INFO", "Info");
47 | define("LANG_TYPE", "Type");
48 | define("LANG_SIZE", "Taille");
49 | define("LANG_FILE", "Fichier");
50 | define("LANG_FOLDER", "Dossier");
51 | define("LANG_USE_ON_SERVER", "utilisé sur le serveur");
52 | define("LANG_OF_SERVER", "du serveur");
53 | define("LANG_TO_MUCH_SPACE", "Attention, vous utilisez beaucoup d'espace !");
54 | define("LANG_DOWNLOADING", "EN DL");
55 | define("LANG_NO_DOWNLOAD", "NO DL");
56 | define("LANG_DOWNLOADING_DESC", "En cours de téléchargement");
57 | define("LANG_NO_DOWNLOAD_DESC", "Vous n'avez jamais téléchargé");
58 |
59 |
60 | //Account
61 | define("LANG_BASIC_INFO", "Informations de bases");
62 | define("LANG_OLD_PASSWORD", "Ancien mot de passe");
63 | define("LANG_NEW_PASSWORD", "Nouveau mot de passe");
64 | define("LANG_LINK_RSS", "Lien vers le Flux RSS");
65 | define("LANG_PROFIL_PICTURE", "Avatar");
66 | define("LANG_MANAGE_MY_PROFIL_PICTURE", "Gérer mon avatar");
67 |
68 | //Connect
69 | define("LANG_CONNECTION", "Connexion");
70 | define("LANG_LOG_IN", "Connectez-vous");
71 |
72 | //Download
73 | define("LANG_YOU_WILL_DOWNLOAD", "Vous allez télécharger le ");
74 | define("LANG_START_DOWNLOAD", "Démarrer le téléchargement");
75 | define("LANG_ERROR_INEXISTING", "Erreur : téléchargement inéxistant !");
76 |
77 | //INBOX
78 | define("LANG_REPLY", "Répondre");
79 | define("LANG_DELETE_MESSAGE", "Supprimer ce message");
80 | define("LANG_MESSAGE_SENDED", "Envoi du message réussi !");
81 | define("LANG_CONVERSATION_WITH", "Conversation avec");
82 |
83 |
84 | //Charts
85 | define("LANG_NETWORK", "Transferts");
86 | define("LANG_MY_NETWORK", "Mes transferts");
87 | define("LANG_THIS_MONTH", "ce mois");
88 | define("LANG_MONTH_UPLOAD_USE", "Utilisation de l'upload ce mois");
89 | define("LANG_MONTH_DOWNLOAD_USE", "Utilisation du download ce mois");
90 | define("LANG_DISK_SPACE", "Espace disque");
91 |
92 | //Controllers actions
93 | define("LANG_NO_MORE_SPACE", "Il reste plus assez d'espace sur le serveur !");
94 | define("LANG_CANT_START_TORRENT", "Le torrent ne peut être démarré");
95 | define("LANG_CANT_STOP_TORRENT", "Le torrent ne peut être stoppé");
96 | define("LANG_TORRENT_ADDED", "Ajout du torrent effectué");
97 | define("LANG_CANT_ADD_TORRENT", "Impossible d'ajouter ce torrent");
98 | define("LANG_CANT_ADD_TORRENT_ALREADY", "Ajout impossible de ce torrent car vous le téléchargez déjà !");
99 | define("LANG_CANT_DELETE_TORRENT", "Le torrent ne peut être supprimé !");
100 | define("LANG_CHOOSE_TORRENT", "Veuillez choisir un fichier .torrent !");
101 | define("LANG_FREE_SPACE", "Espace libre");
102 |
103 | //Controllers admin
104 | define("LANG_PASSWORD_DIFERENT", "Les nouveaux mot de passe le correspondent pas !");
105 | define("LANG_OLD_PASSWORD_DIFERENT", "L'ancien mot de passe ne correspond pas !");
106 | define("LANG_CANT_CREATE_FOLDER", "Problème de création du dossier de la boxe !");
107 |
108 | //Account
109 | define("LANG_PASSWORD_CHANGED", "Le mot de passe a bien été changé !");
110 |
111 | //Titles
112 | define("LANG_TITLE_ADMINISTRATION", "Administration");
113 | define("LANG_TITLE_MY_ACCOUNT", "Mon compte");
114 | define("LANG_TITLE_MY_TORRENTS", "Mes torrents");
115 |
116 | ?>
117 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.php:
--------------------------------------------------------------------------------
1 | action = $action;
65 | $controller->setTitle();
66 | call_user_func_array(array($controller,$action),$params);
67 | //$controller->$action();
68 |
69 | $paramsString = '';
70 | foreach($params as $key=>$value){
71 | $paramsString .= '/'.$value;
72 | }
73 | //$core->bdd->sendReport($nameController.'/'.$action.$paramsString);
74 | }
75 | else{
76 | echo '/!\\ Error 404 /!\\';
77 | }
78 | ?>
--------------------------------------------------------------------------------
/src/models/cloud.php:
--------------------------------------------------------------------------------
1 | bdd->query($sql));
34 |
35 | if($rslt['id'] != NULL){
36 | $this->boxeData = $rslt;
37 | }
38 | }
39 |
40 | function scanDossier($rep){
41 |
42 | $racine=@opendir($rep);
43 | $taille=0;
44 |
45 | while($dossier=@readdir($racine)){
46 | if(!in_array($dossier, array("..", ".", ".config"))){
47 |
48 | $stat = stat("$rep/$dossier");
49 |
50 |
51 |
52 | if(is_dir("$rep/$dossier")){
53 | $this->scanDossier("$rep/$dossier");
54 | $type = 'FOLDER';
55 | $taille = 0;
56 | }else{
57 | $taille=@filesize("$rep/$dossier");
58 | $tab = explode('.', $dossier);
59 | $ext = $tab[count($tab)-1];
60 | $type = 'FILE';
61 | }
62 |
63 | //if($stat['mtime'] >= $this->boxeData['lastScan']){
64 | $sql = "SELECT * FROM files WHERE link = '".addslashes($rep).'/'.addslashes($dossier)."' AND type = '".$type."' AND idBoxe = '".$this->boxeData['id']."';";
65 | $rst = mysql_query($sql);
66 | $rslt = mysql_fetch_assoc($rst);
67 |
68 | if(!$rslt['id']){
69 | mysql_query('INSERT INTO files VALUES("", "'.addslashes($rep).'/'.addslashes($dossier).'", "'.$type.'", "'.$this->boxeData['id'].'", "'.$taille.'", "'.time().'");');
70 | $id = mysql_insert_id();
71 | }
72 | //}
73 | }
74 | }
75 | @closedir($racine);
76 |
77 | mysql_query('UPDATE users SET lastScan = "'.time().'" WHERE id = "'.$this->boxeData['id'].'"');
78 | }
79 |
80 | function scanDossierSup(){
81 |
82 | $sql = "SELECT * FROM files WHERE idBoxe = '".$this->boxeData['id']."'";
83 | $rst = mysql_query($sql);
84 | while($rslt = mysql_fetch_assoc($rst)){
85 | if (!file_exists(stripcslashes($rslt['link']))){
86 | mysql_query('DELETE FROM files WHERE id = "'.$rslt['id'].'"');
87 | mysql_query('DELETE FROM actions WHERE idFile = "'.$rslt['id'].'"');
88 | mysql_query('DELETE FROM downloads WHERE idFichier = "'.$rslt['id'].'"');
89 | }
90 | }
91 | }
92 |
93 | function scan(){
94 | $this->scanDossier($this->boxeData['boxe']);
95 | $this->scanDossierSup();
96 | }
97 |
98 | }
99 |
100 | ?>
--------------------------------------------------------------------------------
/src/models/download.php:
--------------------------------------------------------------------------------
1 | idFile = $idFichier;
22 |
23 | if($id){
24 | $sql = "SELECT * FROM downloads WHERE clef = '".$id."';";
25 | $rst = $this->bdd->query($sql);
26 | $this->downloadData = mysql_fetch_assoc($rst);
27 | }else if($idFichier){
28 | $sql = "SELECT * FROM downloads WHERE idFichier = '".$idFichier."';";
29 | $rst = $this->bdd->query($sql);
30 | $this->downloadData = mysql_fetch_assoc($rst);
31 | if(!$this->downloadData){
32 | $clef = $this->creatDownloads($idFichier);
33 | $this->bdd->clear();
34 | $sql = "SELECT * FROM downloads WHERE idFichier = '".$idFichier."';";
35 | $rst = $this->bdd->query($sql);
36 | $this->downloadData = mysql_fetch_assoc($rst);
37 | }
38 | }
39 | }
40 |
41 | function ifDownloaded(){
42 |
43 | $sql = "SELECT * FROM checkDownload WHERE idFile = '".$this->idFile."' AND idUser = '".Core::idCo()."';";
44 | $rst = $this->bdd->query($sql);
45 | $rslt = mysql_fetch_assoc($rst);
46 |
47 | if($rslt['idFile']){
48 | return true;
49 | }else{
50 | $sql45 = "SELECT * FROM files WHERE id = '".$this->idFile."';";
51 | $rst45 = mysql_query($sql45);
52 | $rslt45 = mysql_fetch_assoc($rst45);
53 | $user = new User();
54 |
55 | return Tools::getDownloadFtpLogUsers($rslt45['link'], $user->userLogin);
56 | }
57 | }
58 |
59 | function downloaded(){
60 | if(Core::isCo()){
61 | $sql = "INSERT INTO checkDownload VALUE('".$this->downloadData['idFichier']."', '".Core::idCo()."', '".time()."');";
62 | $this->bdd->query($sql);
63 | }else{
64 | $ip = $_SERVER['REMOTE_ADDR'];
65 | $sql = "SELECT * FROM sessions WHERE ip = '".$ip."' ORDER BY lastTime DESC LIMIT 0,1;";
66 | $rst = $this->bdd->query($sql);
67 | if($rslt['idUser']){
68 | $sql = "INSERT INTO checkDownload VALUE('".$this->downloadData['idFichier']."', '".$rslt['idUser']."', '".time()."');";
69 | $this->bdd->query($sql);
70 | }
71 | }
72 | }
73 |
74 | function creatDownloads($idFichier){
75 |
76 | $sql = "SELECT * FROM files WHERE id = '".$idFichier."';";
77 | $rst = $this->bdd->query($sql);
78 | $rslt = mysql_fetch_assoc($rst);
79 |
80 | if($rslt['id']){
81 |
82 | $clef = md5($rslt['link']);
83 |
84 | $link = $rslt['link'];
85 |
86 | $sql = "INSERT INTO downloads VALUE('".$clef."', '".$rslt['id']."', '".addslashes($link)."');";
87 | $rst = $this->bdd->query($sql);
88 |
89 | return $clef;
90 | }else{
91 | return false;
92 | }
93 | }
94 |
95 | }
96 |
97 | ?>
--------------------------------------------------------------------------------
/src/models/rpc.php:
--------------------------------------------------------------------------------
1 | get(array(), $afields);
17 | $torrentlist = $response['arguments']['torrents'];
18 |
19 | if (!empty($torrentlist)) {
20 | foreach ($torrentlist as $aTorrent) {
21 | if ( $aTorrent['hashString'] == $transfer )
22 | return $aTorrent;
23 | }
24 | }
25 | return false;
26 | }
27 |
28 | /**
29 | * checks if transfer is Transmission
30 | *
31 | * @param $transfer hash of the transfer
32 | * @return boolean
33 | */
34 | function isTransmissionTransfer($transfer, $instance) {
35 | $aTorrent = getTransmissionTransfer($transfer, array(), $instance);
36 | return is_array($aTorrent);
37 | }
38 |
39 | /**
40 | * This method retrieves the current ID in transmission for the transfer that matches the $hash hash
41 | *
42 | * @return transmissionTransferId
43 | */
44 | function getTransmissionTransferIdByHash($hash, $instance) {
45 | $transmissionTransferId = false;
46 | $rpc = $instance;
47 | $response = $rpc->get(array(), array('id','hashString'));
48 | if ( $response['result'] != "success" ) rpc_error("Getting ID for Hash failed: ".$response['result']);
49 | $torrentlist = $response['arguments']['torrents'];
50 | foreach ($torrentlist as $aTorrent) {
51 | if ( $aTorrent['hashString'] == $hash ) {
52 | $transmissionTransferId = $aTorrent['id'];
53 | break;
54 | }
55 | }
56 | return $transmissionTransferId;
57 | }
58 |
59 | /**
60 | * This method starts the Transmission transfer with the matching hash
61 | *
62 | * @return void
63 | */
64 | function startTransmissionTransfer($hash,$startPaused=false,$params=array(), $instance) {
65 |
66 | $rpc = $instance;
67 | $transmissionId = getTransmissionTransferIdByHash($hash, $instance);
68 | $response = $rpc->set($transmissionId, array_merge(array("seedRatioMode" => 1), $params) );
69 | $response = $rpc->start($transmissionId);
70 | if ( $response['result'] != "success" ) {
71 | rpc_error("Start failed", "", "", $response['result']);
72 | return false;
73 | }
74 | return true;
75 | }
76 |
77 | /**
78 | * This method stops the Transmission transfer with the matching hash
79 | *
80 | * @return boolean
81 | */
82 | function stopTransmissionTransfer($hash, $instance) {
83 |
84 | $transmissionId = getTransmissionTransferIdByHash($hash, $instance);
85 | $response = $instance->stop($transmissionId);
86 | if ( $response['result'] != "success" ) return false;
87 |
88 | return true;
89 | }
90 |
91 | /**
92 | * convertTime
93 | *
94 | * @param $seconds
95 | * @return common time-delta-string
96 | */
97 | function convertTime($seconds) {
98 | // sanity-check
99 | if ($seconds < -1) $seconds=0-$seconds;
100 | // one week is enough
101 | if ($seconds >= 604800) return '-';
102 | // format time-delta
103 | $periods = array (/* 31556926, 2629743, 604800,*/ 86400, 3600, 60, 1);
104 | $seconds = floatval($seconds);
105 | $values = array();
106 | $leading = true;
107 | foreach ($periods as $period) {
108 | $count = floor($seconds / $period);
109 | if ($leading) {
110 | if ($count == 0)
111 | continue;
112 | $leading = false;
113 | }
114 | array_push($values, ($count < 10) ? "0".$count : $count);
115 | $seconds = $seconds % $period;
116 | }
117 | return (empty($values)) ? "?" : implode(':', $values);
118 | }
119 |
120 | /**
121 | * This method deletes the Transmission transfer with the matching hash, without removing the data
122 | *
123 | * @return void
124 | * TODO: test delete :)
125 | */
126 | function deleteTransmissionTransfer($hash, $deleteData = false, $rpc) {
127 |
128 | $transmissionId = getTransmissionTransferIdByHash($hash, $rpc);
129 | $response = $rpc->remove($transmissionId,$deleteData);
130 | if ( $response['result'] != "success" )
131 | return false;
132 |
133 | return true;
134 | }
135 |
136 | /**
137 | * convertTimeText
138 | *
139 | * @param $seconds
140 | * @return textual remaining time
141 | */
142 | function convertTimeText($seconds) {
143 | $hour_fmt = convertTime($seconds);
144 | if ($hour_fmt == '-')
145 | return '-';
146 | $parts = explode(':',$hour_fmt);
147 | if (count($parts) >= 4)
148 | return $parts[0]."d.";
149 | elseif (count($parts) == 3)
150 | return $parts[0]."h.";
151 | elseif (count($parts) == 2)
152 | return $parts[0]."m.";
153 | else
154 | return $parts[0]."s.";
155 | }
156 |
157 | /**
158 | * Returns a string in format of TB, GB, MB, or kB depending on the size
159 | *
160 | * @param $inBytes
161 | * @return string
162 | */
163 | function formatBytesTokBMBGBTB($inBytes) {
164 | if(!is_numeric($inBytes)) return "";
165 | if ($inBytes > 1099511627776)
166 | return round($inBytes / 1099511627776, 2) . " TB";
167 | elseif ($inBytes > 1073741824)
168 | return round($inBytes / 1073741824, 2) . " GB";
169 | elseif ($inBytes > 1048576)
170 | return round($inBytes / 1048576, 1) . " MB";
171 | elseif ($inBytes > 1024)
172 | return round($inBytes / 1024, 1) . " kB";
173 | else
174 | return $inBytes . " B";
175 | }
176 | ?>
177 |
--------------------------------------------------------------------------------
/src/models/rss.php:
--------------------------------------------------------------------------------
1 | channel->item as $item){
26 | $sql = "SELECT * FROM cacheRss WHERE url = '".addslashes($item->link)."';";
27 | $rst = $this->bdd->query($sql);
28 | $rslt = mysql_fetch_assoc($rst);
29 |
30 | if($rslt['id']){
31 | $id = $rslt['id'];
32 | $nameFile = $rslt['nameFile'];
33 | }else{
34 |
35 | $h = get_headers($this->get_final_url($item->link));
36 |
37 | foreach($h as $key => $value){
38 | if(strpos($value,'filename') !== FALSE){
39 | $e = explode("\"", $value);
40 | - $nameFile = $e[1];
41 | }
42 | }
43 |
44 | if($nameFile){
45 | $sqlI = "INSERT INTO cacheRss VALUE('', '".addslashes($item->link)."', '".addslashes($nameFile)."');";
46 | $this->bdd->query($sqlI);
47 | $id = mysql_insert_id();
48 | }
49 | }
50 |
51 | if($nameFile){
52 | $nameFile = str_replace(".torrent", "", $nameFile);
53 |
54 | $user = new User();
55 |
56 | $sql = "SELECT torrents.id, users.id as uid, users.login FROM torrents, users WHERE users.id = torrents.idBoxe AND name = '".addslashes($nameFile)."-".md5($user->userData['id'])."';";
57 | $rst = $this->bdd->query($sql);
58 | $rslt = mysql_fetch_assoc($rst);
59 |
60 | if($rslt['id']){
61 | if($rslt['uid'] == Core::idCo()){
62 | $etat = "Téléchargement en cours";
63 | $dl = false;
64 | }else{
65 | $etat = "Téléchargement en cours par ".$rslt['login'];
66 | $dl = true;
67 | }
68 | }else{
69 | $etat = "A télécharger";
70 | $dl = true;
71 | }
72 |
73 | $this->rssData[] = array('name' => $item->title, 'id' => $id, 'etat' => $etat, 'isDwn' => $dl);
74 | }else{
75 | $this->rssData[] = array('name' => array('Flux Rss incorrect'), 'id' => 0, 'etat' => 'Erreur', 'isDwn' => 0);
76 | }
77 | }
78 | }
79 | }
80 |
81 | /**
82 | * get_redirect_url()
83 | * Gets the address that the provided URL redirects to,
84 | * or FALSE if there's no redirect.
85 | *
86 | * @param string $url
87 | * @return string
88 | */
89 | function get_redirect_url($url){
90 | $redirect_url = null;
91 |
92 | $url_parts = @parse_url($url);
93 | if (!$url_parts) return false;
94 | if (!isset($url_parts['host'])) return false; //can't process relative URLs
95 | if (!isset($url_parts['path'])) $url_parts['path'] = '/';
96 |
97 | $sock = fsockopen($url_parts['host'], (isset($url_parts['port']) ? (int)$url_parts['port'] : 80), $errno, $errstr, 30);
98 | if (!$sock) return false;
99 |
100 | $request = "HEAD " . $url_parts['path'] . (isset($url_parts['query']) ? '?'.$url_parts['query'] : '') . " HTTP/1.1\r\n";
101 | $request .= 'Host: ' . $url_parts['host'] . "\r\n";
102 | $request .= "Connection: Close\r\n\r\n";
103 | fwrite($sock, $request);
104 | $response = '';
105 | while(!feof($sock)) $response .= fread($sock, 8192);
106 | fclose($sock);
107 |
108 | if (preg_match('/^Location: (.+?)$/m', $response, $matches)){
109 | if ( substr($matches[1], 0, 1) == "/" )
110 | return $url_parts['scheme'] . "://" . $url_parts['host'] . trim($matches[1]);
111 | else
112 | return trim($matches[1]);
113 |
114 | } else {
115 | return false;
116 | }
117 |
118 | }
119 |
120 | /**
121 | * get_all_redirects()
122 | * Follows and collects all redirects, in order, for the given URL.
123 | *
124 | * @param string $url
125 | * @return array
126 | */
127 | function get_all_redirects($url){
128 | $redirects = array();
129 | while ($newurl = $this->get_redirect_url($url)){
130 | if (in_array($newurl, $redirects)){
131 | break;
132 | }
133 | $redirects[] = $newurl;
134 | $url = $newurl;
135 | }
136 | return $redirects;
137 | }
138 |
139 | /**
140 | * get_final_url()
141 | * Gets the address that the URL ultimately leads to.
142 | * Returns $url itself if it isn't a redirect.
143 | *
144 | * @param string $url
145 | * @return string
146 | */
147 | function get_final_url($url){
148 | $redirects = $this->get_all_redirects($url);
149 | if (count($redirects)>0){
150 | return array_pop($redirects);
151 | } else {
152 | return $url;
153 | }
154 | }
155 |
156 | }
157 |
158 | ?>
159 |
--------------------------------------------------------------------------------
/src/models/rssm.php:
--------------------------------------------------------------------------------
1 | ';
25 | print_r($fluxrss);
26 | echo "";*/
27 |
28 | foreach($fluxrss->channel->item as $item){
29 | $sql = "SELECT * FROM cacheRss WHERE url = '".addslashes($item->link)."';";
30 | $rst = $this->bdd->query($sql);
31 | $rslt = mysql_fetch_assoc($rst);
32 |
33 | if($rslt['id']){
34 | $id = $rslt['id'];
35 | $nameFile = $rslt['nameFile'];
36 | }else{
37 | $h = get_headers($item->link);
38 | $e = explode("\"", $h[3]);
39 | $e2 = explode("\"", $e[1]);
40 | $nameFile = $e2[0];
41 |
42 | if($nameFile != NULL) {
43 | $sqlI = "INSERT INTO cacheRss VALUE('', '".addslashes($item->link)."', '".addslashes($nameFile)."');";
44 | $this->bdd->query($sqlI);
45 | $id = mysql_insert_id();
46 | }
47 | }
48 |
49 | $nameFile = str_replace(".torrent", "", $nameFile);
50 |
51 | $item->title=strip_tags($item->title);
52 |
53 | if($nameFile != NULL) {
54 | $user = new User();
55 |
56 | $sql = "SELECT torrents.id, users.id as uid, users.login FROM torrents, users WHERE users.id = '".Core::idCo()."' AND users.id = torrents.idBoxe AND name = '".addslashes($nameFile)."-".md5($user->userData['id'])."';";
57 | $rst = $this->bdd->query($sql);
58 | $rslt = mysql_fetch_assoc($rst);
59 |
60 | if($rslt['id']){
61 | $etat = "Téléchargement en cours";
62 | $dl = false;
63 | }else{
64 | $etat = "A télécharger";
65 | $dl = true;
66 | }
67 |
68 | $this->rssData[] = array('name' => $item->title, 'description' => $item->description, 'id' => $id, 'etat' => $etat, 'isDwn' => $dl);
69 | }else{
70 | $this->rssData[] = array('name' => $item->title, 'description' => $item->description, 'id' => null, 'etat' => 'Fichier non torrent', 'isDwn' => false);
71 | }
72 | }
73 | }
74 | }
75 | }
76 |
77 | ?>
--------------------------------------------------------------------------------
/src/models/torrents.php:
--------------------------------------------------------------------------------
1 | configRPC());
26 | } catch (Exception $e) {
27 | echo "unable to connect to transmission-daemon\n";
28 | return;
29 | }
30 |
31 | $tfs = $rpc->torrent_get_tf();
32 |
33 | if (empty($tfs)) {
34 | return;
35 | }
36 |
37 | $sql = "SELECT hash, name FROM torrents WHERE idBoxe = '".$idUser."'";
38 |
39 | $hashes = array("''");
40 | foreach ($tfs as $hash => $t) {
41 | $hashes[] = "'".strtolower($hash)."'";
42 | }
43 | $sql .= " AND hash IN (".implode(',',$hashes).")";
44 |
45 | $rst = $this->bdd->query($sql);
46 |
47 | $hashes=array();
48 | $sharekills=array();
49 | while ($rslt = mysql_fetch_assoc($rst)) {
50 | $hash = strtolower($rslt['hash']);
51 | $hashes[$hash] = $rslt['name'];
52 |
53 | if (!isset($tfs[$hash])) {
54 | $sf = new StatFile(ROOT_DOWNLOADS.'.transferts/'.$rslt['name']);
55 | $sf->running = 0;
56 | $sf->write();
57 | }
58 | }
59 |
60 | $totalRateUp = 0;
61 | $totalRateDown = 0;
62 | $nbUpdate=0;
63 | $missing=array();
64 | foreach ($tfs as $hash => $t) {
65 | $transfer = $hashes[$hash];
66 |
67 | //file_put_contents($cfg["path"].'.Transmission/'."updateStatFiles4.log",serialize($t));
68 | $sf = new StatFile(ROOT_DOWNLOADS.'.transferts/'.$transfer);
69 |
70 | $sf->running = $t['running'];
71 | $sf->eta = $t['eta'];
72 |
73 | if ($sf->running) {
74 |
75 | if ($t['eta'] > 0) {
76 | $sf->time_left = convertTimeText($t['eta']);
77 | }else{
78 | $sf->time_left = '-';
79 | }
80 |
81 | $sf->percent_done = $t['percentDone'];
82 | $sf->sharing = round($t['sharing'],1);
83 |
84 | if ($t['status'] != 9 && $t['status'] != 5) {
85 | $sf->peers = $t['peers'];
86 | $sf->seeds = $t['seeds'];
87 | }
88 |
89 | if ($t['seeds'] >= 0)
90 | $sf->seeds = $t['seeds'];
91 |
92 | if ($t['peers'] >= 0)
93 | $sf->peers = $t['peers'];
94 |
95 | $sf->peersList = $t['peersList'];
96 | $sf->files = $t['files'];
97 |
98 | if ($t['cons'] >= 0)
99 | $sf->cons = $t['cons'];
100 |
101 | if ((float)$t['speedDown'] >= 0.0)
102 | $sf->down_speed = formatBytesTokBMBGBTB($t['speedDown'])."/s";
103 | if ((float)$t['speedUp'] >= 0.0)
104 | $sf->up_speed = formatBytesTokBMBGBTB($t['speedUp'])."/s";
105 |
106 | $totalRateUp += $t['speedUp'];
107 | $totalRateDown += $t['speedDown'];
108 |
109 | if ($t['status'] == 8) {
110 | $sf->percent_done = 100 + $t['sharing'];
111 | $sf->down_speed = " ";
112 | if (trim($sf->up_speed) == '')
113 | $sf->up_speed = " ";
114 | }
115 | if ($t['status'] == 9) {
116 | $sf->percent_done = 100 + $t['sharing'];
117 | $sf->up_speed = " ";
118 | $sf->down_speed = " ";
119 | }
120 |
121 | if($t['trackerStats'][0]['lastAnnounceSucceeded'] != 1){
122 | $sf->time_left = $t['trackerStats'][0]['lastAnnounceResult'];
123 | $sf->error = 1;
124 | }
125 |
126 | /*echo '
';
127 | print_r($t);
128 | echo '
';*/
129 |
130 | /*if($t['error']){
131 | $sf->time_left = $t['errorString'];
132 | $sf->error = 1;
133 | }*/
134 |
135 | } else {
136 | //Stopped or finished...
137 |
138 | $sf->down_speed = "";
139 | $sf->up_speed = "";
140 | $sf->peers = "";
141 | $sf->time_left = "-";
142 | if ($t['eta'] < -1) {
143 | $sf->time_left = "Done in ".convertTimeText($t['eta']);
144 | } elseif ($sf->percent_done >= 100 && strpos($sf->time_left, 'Done') === false && strpos($sf->time_left, 'Finished') === false) {
145 | $sf->percent_done = 100;
146 | $sf->time_left = "Done!";
147 | }
148 |
149 | if ($sf->sharing == 0)
150 | $sf->sharing = round($t['sharing'],1);
151 | }
152 |
153 | $sf->downtotal = $t['downTotal'];
154 | $sf->uptotal = $t['upTotal'];
155 |
156 | if ($sf->size == 0)
157 | $sf->size = $t['size'];
158 |
159 | echo $sf->seeds.'|';
160 |
161 | if ($sf->write()) {
162 | $nbUpdate++;
163 | }
164 |
165 | }
166 |
167 | $this->bdd->getCache()->set($idUser."Stats", array('rateUp' => $totalRateUp, 'rateDown' => $totalRateDown), false, 10);
168 | }
169 |
170 | function refresh(){
171 | $sql = "SELECT id FROM users;";
172 | $rst = $this->bdd->query($sql);
173 | while($rslt = mysql_fetch_assoc($rst)){
174 | $this->updateStatFiles($rslt['id']);
175 | }
176 | }
177 |
178 | function myTorrents(){
179 |
180 | $torrents = array();
181 |
182 | $sql = "SELECT id FROM torrents WHERE idBoxe = '".Core::idCo()."' ORDER BY time DESC;";
183 | $rst = $this->bdd->query($sql);
184 | while($rslt = mysql_fetch_assoc($rst)){
185 | $torrent = new Torrent($rslt['id']);
186 | $torrents[] = $torrent;
187 | }
188 |
189 | return $torrents;
190 | }
191 |
192 | function torrents(){
193 |
194 | $torrents = array();
195 |
196 | $sql = "SELECT id FROM torrents ORDER BY time DESC;";
197 | $rst = $this->bdd->query($sql);
198 | while($rslt = mysql_fetch_assoc($rst)){
199 | $torrent = new Torrent($rslt['id']);
200 | $torrents[] = $torrent;
201 | }
202 |
203 | return $torrents;
204 | }
205 |
206 | }
207 |
208 | ?>
--------------------------------------------------------------------------------
/src/models/xfer.php:
--------------------------------------------------------------------------------
1 | userId){
24 |
25 | $year = date('Y');
26 | $month = date('n');
27 |
28 | $sql = "SELECT * FROM xferUser WHERE idUser = '".$user->userId."' AND `year` = '".$year."' AND `month` = '".$month."';";
29 | $rst = $this->bdd->query($sql);
30 | $rslt = mysql_fetch_assoc($rst);
31 |
32 | if(!$rslt['idUser']){
33 | $sql = "INSERT INTO xferUser VALUES ('".$user->userId."', '".$year."', '".$month."', '0', '0');";
34 | $rst = $this->bdd->query($sql);
35 | }
36 |
37 | $this->xfer = $user->userId;
38 | }
39 | }
40 | }
41 |
42 | function addValue($up = 0, $down = 0){
43 | $year = date('Y');
44 | $month = date('n');
45 |
46 | if($up != 0 || $down != 0){
47 | $sql = "UPDATE xferUser SET totalUp = totalUp + '".$up."', totalDown = totalDown + '".$down."' WHERE idUser = '".$this->xfer."' AND year = '".$year."' AND month = '".$month."';";
48 | $rst = $this->bdd->query($sql);
49 | }
50 | }
51 |
52 | function getStat($year = 0, $month = 0){
53 |
54 | if(!$year)
55 | $year = date('Y');
56 | if(!$month)
57 | $month = date('n');
58 |
59 | $sql = "SELECT * FROM xferUser WHERE idUser = '".$this->xfer."' AND year = '".$year."' AND month = '".$month."';";
60 | $rst = $this->bdd->query($sql);
61 | $rslt = mysql_fetch_assoc($rst);
62 |
63 | return (array('down' => $rslt['totalDown'], 'up' => $rslt['totalUp']));
64 | }
65 |
66 | function getStatTotal($year = 0, $month = 0){
67 |
68 | if(!$year)
69 | $year = date('Y');
70 | if(!$month)
71 | $month = date('n');
72 |
73 | $sql = "SELECT SUM(totalDown) as totalDown, SUM(totalUp) as totalUp FROM xferUser WHERE year = '".$year."' AND month = '".$month."';";
74 | $rst = $this->bdd->query($sql);
75 | $rslt = mysql_fetch_assoc($rst);
76 |
77 | return (array('down' => $rslt['totalDown'], 'up' => $rslt['totalUp']));
78 | }
79 |
80 | function scanTorrent($id = null){
81 |
82 | if($id)
83 | $sqlPlus = ' id = "'.$id.'" AND';
84 | else
85 | $sqlPlus = '';
86 |
87 | $sql = "SELECT id, name FROM torrents WHERE".$sqlPlus." idBoxe = '".$this->xfer."';";
88 | $rst = $this->bdd->query($sql);
89 | while($rslt = mysql_fetch_assoc($rst)){
90 |
91 | $stat = new StatFile(ROOT_DOWNLOADS.'.transferts/'.$rslt['name']);
92 |
93 | if($stat->running == 1){
94 | $sql45 = "SELECT * FROM xferTorrent WHERE idTorrent = '".$rslt['id']."';";
95 | $rst45 = $this->bdd->query($sql45);
96 | $rslt45 = mysql_fetch_assoc($rst45);
97 | if(!$rslt45['idTorrent']){
98 | $upAdd = $stat->uptotal;
99 | $downAdd = $stat->downtotal;
100 |
101 | $sql55 = "INSERT INTO xferTorrent VALUES ('".$rslt['id']."', '".$stat->uptotal."', '".$stat->downtotal."');";
102 | $this->bdd->query($sql55);
103 | }else{
104 | if($stat->uptotal != $rslt45['lastUp'] || $stat->downtotaltotal != $rslt45['lastDown']){
105 | $upAdd = $stat->uptotal - $rslt45['lastUp'];
106 | $downAdd = $stat->downtotal - $rslt45['lastDown'];
107 |
108 | $sql55 = "UPDATE xferTorrent SET lastUp = '".$stat->uptotal."', lastDown = '".$stat->downtotal."' WHERE idTorrent = '".$rslt['id']."';";
109 | $this->bdd->query($sql55);
110 | }
111 | }
112 | $this->addValue($upAdd, $downAdd);
113 | }
114 | }
115 | }
116 |
117 | function deleteTorrent($id){
118 | $this->scanTorrent($id);
119 | $sql = "DELETE FROM xferTorrent WHERE idTorrent = '".$id."';";
120 | $this->bdd->query($sql);
121 | }
122 |
123 | }
124 |
125 | ?>
--------------------------------------------------------------------------------
/src/theme/css/facelist.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | /* TextboxList sample CSS */
4 | ul.facelist {
5 | list-style: none;
6 | margin: 0;
7 | overflow: hidden;
8 | height: auto !important;
9 | height: 1%;
10 | padding: 4px 5px 0;
11 | width: 100%;
12 | }
13 | ul.facelist li {
14 | float: left;
15 | margin: 0 5px 4px 0;
16 | }
17 | ul.facelist li.token-input input {
18 | width: 150px;
19 | margin: 0;
20 | border: 1px solid #FFF;
21 | outline: 0;
22 | padding: 3px 0 2px;
23 | } /* no left/right padding here please */
24 |
25 | ul.facelist li.token-input {
26 | margin: 0;
27 | width: 5px;
28 | }
29 | .token{
30 | color:black;
31 | position: relative;
32 | background-color: #eff2f7;
33 | border: solid 1px #ccd5e4;
34 | -moz-border-radius: 3px;
35 | -webkit-border-radius: 3px;
36 | border-radius: 3px;
37 | -webkit-transition: background-color .2s ease-in;
38 | cursor: pointer;
39 | padding:2px 20px 2px 5px;
40 | }
41 | .tokenhover,
42 | .token:hover{
43 | position: relative;
44 | background-color: #d8dfea;
45 | border: solid 1px #ccd5e4;
46 | }
47 | .token_selected:hover,
48 | .token_selected{
49 | color:#fff;
50 | background-color: #5670a6;
51 | border: solid 1px #3b5998;
52 | }
53 |
54 | .token span.x,
55 | .token span.x_hover,
56 | .tokenhover span.x,
57 | .tokenhover span.x_hover{background-image:url('../images/token_x.gif');cursor:pointer;display:inline; width: 10px; height:9px; display: block; position:absolute; right: 0px; top: 3.5px;text-indent: -9999px;margin-right:5px;margin-top:3px;}
58 |
59 |
60 |
61 | /* Autocompleter */
62 |
63 | #result_list {
64 | position: absolute;
65 | width: 177px;
66 | }
67 | #result_list .default {
68 | padding: 5px 7px;
69 | background: #eee;
70 | color:black;
71 | }
72 | #result_list ul {
73 | margin: 0;
74 | padding: 0;
75 | background: #fff;
76 | width: 177px;
77 | }
78 | #result_list ul li {
79 | padding: 5px 12px;
80 | margin: 0;
81 | list-style-type: none;
82 | border: 0px solid #ccc;
83 | border-width: 0 1px 1px;
84 | font: 11px "Lucida Grande", "Verdana";
85 | color:black;
86 | width: 152px;
87 | background: #fff;
88 | }
89 | #result_list ul li em {
90 | font-weight: bold;
91 | font-style: normal;
92 | background: #dae1eb;
93 | color: blue;
94 | }
95 | #result_list ul li.auto-focus {
96 | background: #029ec6;
97 | }
98 | #result_list ul li.auto-focus em {
99 | background: none;
100 | }
--------------------------------------------------------------------------------
/src/theme/css/facelist_ie.css:
--------------------------------------------------------------------------------
1 | .token{background-image:url('../images/facelist/token.gif');background-repeat:no-repeat;color:black;white-space:nowrap;position: relative;}
2 | .token span{background-image:url('../images/facelist/token.gif');background-position:top right;background-repeat:no-repeat;display:block;}
3 | .token span span{background-position:bottom right;}
4 | .token span span span{background-position:bottom left;}
5 | .token span span span span{background-image:none;padding:2px 20px 2px 5px; font-size: 12px;}
6 |
7 | .tokenhover,
8 | html div.tokenizer_locked .tokenhover span{background-image:url('../images/facelist/token.gif');}
9 | .token:hover,
10 | .token:hover span{background-image:url('../images/facelist/token_hover.gif');text-decoration:none;}
11 | .token_selected,
12 | .token_selected span,
13 | .token_selected:hover,
14 | .token_selected:hover span{background-image:url('../images/facelist/token_selected.gif');color:white;text-decoration:none;}
--------------------------------------------------------------------------------
/src/theme/css/farbtastic.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Farbtastic Color Picker 1.2
3 | * © 2008 Steven Wittens
4 | *
5 | * This program is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 2 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 | */
19 | .farbtastic {
20 | position: relative;
21 | }
22 | .farbtastic * {
23 | position: absolute;
24 | cursor: crosshair;
25 | }
26 | .farbtastic, .farbtastic .wheel {
27 | width: 195px;
28 | height: 195px;
29 | }
30 | .farbtastic .color, .farbtastic .overlay {
31 | top: 47px;
32 | left: 47px;
33 | width: 101px;
34 | height: 101px;
35 | }
36 | .farbtastic .wheel {
37 | background: url(../images/wheel.png) no-repeat;
38 | width: 195px;
39 | height: 195px;
40 | }
41 | .farbtastic .overlay {
42 | background: url(../images/mask.png) no-repeat;
43 | }
44 | .farbtastic .marker {
45 | width: 17px;
46 | height: 17px;
47 | margin: -8px 0 0 -8px;
48 | overflow: hidden;
49 | background: url(../images/marker.png) no-repeat;
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/src/theme/css/jquery.pnotify.default.css:
--------------------------------------------------------------------------------
1 | /*
2 | Document : jquery.pnotify.default.css
3 | Created on : Nov 23, 2009, 3:14:10 PM
4 | Author : Hunter Perrin
5 | Version : 1.2.0
6 | Link : http://pinesframework.org/pnotify/
7 | Description:
8 | Default styling for Pines Notify jQuery plugin.
9 | */
10 | /* -- Notice */
11 | .ui-pnotify {
12 | top: 25px;
13 | right: 25px;
14 | position: absolute;
15 | height: auto;
16 | /* Ensures notices are above everything */
17 | z-index: 9999;
18 | }
19 | /* Hides position: fixed from IE6 */
20 | html > body .ui-pnotify {
21 | position: fixed;
22 | }
23 | .ui-pnotify .ui-pnotify-shadow {
24 | -webkit-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5);
25 | -moz-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5);
26 | box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5);
27 | }
28 | .ui-pnotify-container {
29 | background-position: 0 0;
30 | padding: .8em;
31 | height: 100%;
32 | margin: 0;
33 | }
34 | .ui-pnotify-sharp {
35 | -webkit-border-radius: 0;
36 | -moz-border-radius: 0;
37 | border-radius: 0;
38 | }
39 | .ui-pnotify-closer, .ui-pnotify-sticker {
40 | float: right;
41 | margin-left: .2em;
42 | }
43 | .ui-pnotify-title {
44 | display: block;
45 | margin-bottom: .4em;
46 | font-size: 14px
47 | }
48 | .ui-pnotify-text {
49 | display: block;
50 | }
51 | .ui-pnotify-text a {
52 | color:black;
53 | }
54 | .ui-pnotify-icon, .ui-pnotify-icon span {
55 | display: block;
56 | float: left;
57 | margin-right: .2em;
58 | }
59 | /* -- History Pulldown */
60 | .ui-pnotify-history-container {
61 | position: absolute;
62 | top: 0;
63 | right: 18px;
64 | width: 70px;
65 | border-top: none;
66 | padding: 0;
67 | -webkit-border-top-left-radius: 0;
68 | -moz-border-top-left-radius: 0;
69 | border-top-left-radius: 0;
70 | -webkit-border-top-right-radius: 0;
71 | -moz-border-top-right-radius: 0;
72 | border-top-right-radius: 0;
73 | /* Ensures history container is above notices. */
74 | z-index: 10000;
75 | display:none;
76 | }
77 | .ui-pnotify-history-container .ui-pnotify-history-header {
78 | padding: 2px;
79 | }
80 | .ui-pnotify-history-container button {
81 | cursor: pointer;
82 | display: block;
83 | width: 100%;
84 | }
85 | .ui-pnotify-history-container .ui-pnotify-history-pulldown {
86 | display: block;
87 | margin: 0 auto;
88 | }
--------------------------------------------------------------------------------
/src/theme/css/jquery.pnotify.default.icons.css:
--------------------------------------------------------------------------------
1 | /*
2 | Document : jquery.pnotify.default.icons.css
3 | Created on : Nov 24, 2009, 2:58:21 PM
4 | Author : Hunter Perrin
5 | Version : 1.2.0
6 | Link : http://pinesframework.org/pnotify/
7 | Description:
8 | Pines Icon styling for Pines Notify.
9 | */
10 |
11 | .ui-pnotify .picon {
12 | background-color: transparent;
13 | background-repeat: no-repeat;
14 | background-position: center center;
15 | width: 17px;
16 | height: 17px;
17 | }
18 | .ui-pnotify-title {
19 | line-height: 17px;
20 | min-height: 17px;
21 | }
--------------------------------------------------------------------------------
/src/theme/fonts/glyphicons-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/fonts/glyphicons-regular.eot
--------------------------------------------------------------------------------
/src/theme/fonts/glyphicons-regular.eot@:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/fonts/glyphicons-regular.eot@
--------------------------------------------------------------------------------
/src/theme/fonts/glyphicons-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/fonts/glyphicons-regular.ttf
--------------------------------------------------------------------------------
/src/theme/fonts/glyphicons-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/fonts/glyphicons-regular.woff
--------------------------------------------------------------------------------
/src/theme/images/friendly-torrent-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/friendly-torrent-logo.png
--------------------------------------------------------------------------------
/src/theme/images/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/home.png
--------------------------------------------------------------------------------
/src/theme/images/loader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/loader.png
--------------------------------------------------------------------------------
/src/theme/images/login-colors.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/login-colors.jpg
--------------------------------------------------------------------------------
/src/theme/images/token.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/token.gif
--------------------------------------------------------------------------------
/src/theme/images/token_hover.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/token_hover.gif
--------------------------------------------------------------------------------
/src/theme/images/token_selected.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/token_selected.gif
--------------------------------------------------------------------------------
/src/theme/images/token_x.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/images/token_x.gif
--------------------------------------------------------------------------------
/src/theme/scripts/flot/jquery.flot.resize.js:
--------------------------------------------------------------------------------
1 | /*
2 | Flot plugin for automatically redrawing plots when the placeholder
3 | size changes, e.g. on window resizes.
4 |
5 | It works by listening for changes on the placeholder div (through the
6 | jQuery resize event plugin) - if the size changes, it will redraw the
7 | plot.
8 |
9 | There are no options. If you need to disable the plugin for some
10 | plots, you can just fix the size of their placeholders.
11 | */
12 |
13 |
14 | /* Inline dependency:
15 | * jQuery resize event - v1.1 - 3/14/2010
16 | * http://benalman.com/projects/jquery-resize-plugin/
17 | *
18 | * Copyright (c) 2010 "Cowboy" Ben Alman
19 | * Dual licensed under the MIT and GPL licenses.
20 | * http://benalman.com/about/license/
21 | */
22 | (function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);
23 |
24 |
25 | (function ($) {
26 | var options = { }; // no options
27 |
28 | function init(plot) {
29 | function onResize() {
30 | var placeholder = plot.getPlaceholder();
31 |
32 | // somebody might have hidden us and we can't plot
33 | // when we don't have the dimensions
34 | if (placeholder.width() == 0 || placeholder.height() == 0)
35 | return;
36 |
37 | plot.resize();
38 | plot.setupGrid();
39 | plot.draw();
40 | }
41 |
42 | function bindEvents(plot, eventHolder) {
43 | plot.getPlaceholder().resize(onResize);
44 | }
45 |
46 | function shutdown(plot, eventHolder) {
47 | plot.getPlaceholder().unbind("resize", onResize);
48 | }
49 |
50 | plot.hooks.bindEvents.push(bindEvents);
51 | plot.hooks.shutdown.push(shutdown);
52 | }
53 |
54 | $.plot.plugins.push({
55 | init: init,
56 | options: options,
57 | name: 'resize',
58 | version: '1.0'
59 | });
60 | })(jQuery);
61 |
--------------------------------------------------------------------------------
/src/theme/scripts/flot/jquery.flot.tooltip.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jquery.flot.tooltip
3 | *
4 | * desc: create tooltip with values of hovered point on the graph,
5 | support many series, time mode, stacking and pie charts
6 | you can set custom tip content (also with use of HTML tags) and precision of values
7 | * version: 0.4.4
8 | * author: Krzysztof Urbas @krzysu [myviews.pl] with help of @ismyrnow
9 | * website: https://github.com/krzysu/flot.tooltip
10 | *
11 | * released under MIT License, 2012
12 | */
13 |
14 | (function ($) {
15 | var options = {
16 | tooltip: false, //boolean
17 | tooltipOpts: {
18 | content: "%s | X: %x | Y: %y.2", //%s -> series label, %x -> X value, %y -> Y value, %x.2 -> precision of X value, %p -> percent
19 | dateFormat: "%y-%0m-%0d",
20 | shifts: {
21 | x: 10,
22 | y: 20
23 | },
24 | defaultTheme: true
25 | }
26 | };
27 |
28 | var init = function(plot) {
29 |
30 | var tipPosition = {x: 0, y: 0};
31 | var opts = plot.getOptions();
32 |
33 | var updateTooltipPosition = function(pos) {
34 | tipPosition.x = pos.x;
35 | tipPosition.y = pos.y;
36 | };
37 |
38 | var onMouseMove = function(e) {
39 |
40 | var pos = {x: 0, y: 0};
41 |
42 | pos.x = e.pageX;
43 | pos.y = e.pageY;
44 |
45 | updateTooltipPosition(pos);
46 | };
47 |
48 | var timestampToDate = function(tmst) {
49 |
50 | var theDate = new Date(tmst);
51 |
52 | return $.plot.formatDate(theDate, opts.tooltipOpts.dateFormat);
53 | };
54 |
55 | plot.hooks.bindEvents.push(function (plot, eventHolder) {
56 |
57 | var to = opts.tooltipOpts;
58 | var placeholder = plot.getPlaceholder();
59 | var $tip;
60 |
61 | if (opts.tooltip === false) return;
62 |
63 | if( $('#flotTip').length > 0 ){
64 | $tip = $('#flotTip');
65 | }
66 | else {
67 | $tip = $('').attr('id', 'flotTip');
68 | $tip.appendTo('body').hide().css({position: 'absolute'});
69 |
70 | if(to.defaultTheme) {
71 | $tip.css({
72 | 'background': '#fff',
73 | 'z-index': '100',
74 | 'padding': '0.4em 0.6em',
75 | 'border-radius': '0.5em',
76 | 'font-size': '0.8em',
77 | 'border': '1px solid #111'
78 | });
79 | }
80 | }
81 |
82 | $(placeholder).bind("plothover", function (event, pos, item) {
83 | if (item) {
84 | var tipText;
85 |
86 | if(opts.xaxis.mode === "time" || opts.xaxes[0].mode === "time") {
87 | tipText = stringFormat(to.content, item, timestampToDate);
88 | }
89 | else {
90 | tipText = stringFormat(to.content, item);
91 | }
92 |
93 | $tip.html( tipText ).css({left: tipPosition.x + to.shifts.x, top: tipPosition.y + to.shifts.y}).show();
94 | }
95 | else {
96 | $tip.hide().html('');
97 | }
98 | });
99 |
100 | eventHolder.mousemove(onMouseMove);
101 | });
102 |
103 | var stringFormat = function(content, item, fnct) {
104 |
105 | var percentPattern = /%p\.{0,1}(\d{0,})/;
106 | var seriesPattern = /%s/;
107 | var xPattern = /%x\.{0,1}(\d{0,})/;
108 | var yPattern = /%y\.{0,1}(\d{0,})/;
109 |
110 | //percent match
111 | if( typeof (item.series.percent) !== 'undefined' ) {
112 | content = adjustValPrecision(percentPattern, content, item.series.percent);
113 | }
114 | //series match
115 | if( typeof(item.series.label) !== 'undefined' ) {
116 | content = content.replace(seriesPattern, item.series.label);
117 | }
118 | // xVal match
119 | if( typeof(fnct) === 'function' ) {
120 | content = content.replace(xPattern, fnct(item.series.data[item.dataIndex][0]) );
121 | }
122 | else if( typeof item.series.data[item.dataIndex][0] === 'number' ) {
123 | content = adjustValPrecision(xPattern, content, item.series.data[item.dataIndex][0]);
124 | }
125 | // yVal match
126 | if( typeof item.series.data[item.dataIndex][1] === 'number' ) {
127 | content = adjustValPrecision(yPattern, content, item.series.data[item.dataIndex][1]);
128 | }
129 |
130 | return content;
131 | };
132 |
133 | var adjustValPrecision = function(pattern, content, value) {
134 |
135 | var precision;
136 | if( content.match(pattern) !== 'null' ) {
137 | if(RegExp.$1 !== '') {
138 | precision = RegExp.$1;
139 | value = value.toFixed(precision)
140 | }
141 | content = content.replace(pattern, value);
142 | }
143 |
144 | return content;
145 | };
146 | }
147 |
148 | $.plot.plugins.push({
149 | init: init,
150 | options: options,
151 | name: 'tooltip',
152 | version: '0.4.4'
153 | });
154 | })(jQuery);
155 |
--------------------------------------------------------------------------------
/src/theme/scripts/jquery.cookie.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery Cookie Plugin v1.3.1
3 | * https://github.com/carhartl/jquery-cookie
4 | *
5 | * Copyright 2013 Klaus Hartl
6 | * Released under the MIT license
7 | */
8 | (function (factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as anonymous module.
11 | define(['jquery'], factory);
12 | } else {
13 | // Browser globals.
14 | factory(jQuery);
15 | }
16 | }(function ($) {
17 |
18 | var pluses = /\+/g;
19 |
20 | function raw(s) {
21 | return s;
22 | }
23 |
24 | function decoded(s) {
25 | return decodeURIComponent(s.replace(pluses, ' '));
26 | }
27 |
28 | function converted(s) {
29 | if (s.indexOf('"') === 0) {
30 | // This is a quoted cookie as according to RFC2068, unescape
31 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
32 | }
33 | try {
34 | return config.json ? JSON.parse(s) : s;
35 | } catch(er) {}
36 | }
37 |
38 | var config = $.cookie = function (key, value, options) {
39 |
40 | // write
41 | if (value !== undefined) {
42 | options = $.extend({}, config.defaults, options);
43 |
44 | if (typeof options.expires === 'number') {
45 | var days = options.expires, t = options.expires = new Date();
46 | t.setDate(t.getDate() + days);
47 | }
48 |
49 | value = config.json ? JSON.stringify(value) : String(value);
50 |
51 | return (document.cookie = [
52 | config.raw ? key : encodeURIComponent(key),
53 | '=',
54 | config.raw ? value : encodeURIComponent(value),
55 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
56 | options.path ? '; path=' + options.path : '',
57 | options.domain ? '; domain=' + options.domain : '',
58 | options.secure ? '; secure' : ''
59 | ].join(''));
60 | }
61 |
62 | // read
63 | var decode = config.raw ? raw : decoded;
64 | var cookies = document.cookie.split('; ');
65 | var result = key ? undefined : {};
66 | for (var i = 0, l = cookies.length; i < l; i++) {
67 | var parts = cookies[i].split('=');
68 | var name = decode(parts.shift());
69 | var cookie = decode(parts.join('='));
70 |
71 | if (key && key === name) {
72 | result = converted(cookie);
73 | break;
74 | }
75 |
76 | if (!key) {
77 | result[name] = converted(cookie);
78 | }
79 | }
80 |
81 | return result;
82 | };
83 |
84 | config.defaults = {};
85 |
86 | $.removeCookie = function (key, options) {
87 | if ($.cookie(key) !== undefined) {
88 | // Must not alter options, thus extending a fresh object...
89 | $.cookie(key, '', $.extend({}, options, { expires: -1 }));
90 | return true;
91 | }
92 | return false;
93 | };
94 |
95 | }));
96 |
--------------------------------------------------------------------------------
/src/theme/scripts/load.js:
--------------------------------------------------------------------------------
1 | var seedbox = new Object;
2 | seedbox.interval = null;
3 | CTRL = false;
4 |
5 | $(function()
6 | {
7 |
8 | // tooltips
9 | $('[data-toggle="tooltip"]').tooltip();
10 |
11 | $('.popover-btn').popover();
12 |
13 |
14 | var ctrlDown = false;
15 | var ctrlKey = 17, aKey = 65;
16 |
17 | $(document).keydown(function(e)
18 | {
19 | if (e.keyCode == ctrlKey) ctrlDown = true;
20 | }).keyup(function(e)
21 | {
22 | if (e.keyCode == ctrlKey) ctrlDown = false;
23 | });
24 |
25 |
26 | $('body').click(function() {
27 | $('#context').hide();
28 | });
29 |
30 | $('#context').click(function(event){
31 | event.stopPropagation();
32 | });
33 |
34 | //$("#ajaxContent").css('min-height', $(window).height()+'px');
35 | });
36 |
37 | function loadUpload(){
38 | $('#file_upload').uploadify({
39 | 'swf' : adresse+'/uploadify/uploadify.swf',
40 | 'uploader' : adresse+'/action/addTorrent/',
41 | 'buttonClass' : 'btn btn-success btn-sm',
42 | 'buttonText' : ' Ajouter',
43 | 'height' : 27,
44 | 'queueID' : 'queue',
45 | 'itemTemplate' : '',
48 | 'onUploadSuccess' : function(file, data, response) {
49 | evalscript(data);
50 | }
51 | });
52 | }
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/Descr.WD3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/Descr.WD3
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/Descr.WD3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/Descr.WD3
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/css/Descr.WD3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/css/Descr.WD3
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/css/jquery.plupload.queue.css:
--------------------------------------------------------------------------------
1 | /*
2 | Plupload
3 | ------------------------------------------------------------------- */
4 |
5 | .plupload_button {
6 | display: -moz-inline-box; /* FF < 3*/
7 | display: inline-block;
8 | font: normal 12px sans-serif;
9 | text-decoration: none;
10 | color: #42454a;
11 | border: 1px solid #bababa;
12 | padding: 2px 8px 3px 20px;
13 | margin-right: 4px;
14 | background: #f3f3f3 url('../img/buttons.png') no-repeat 0 center;
15 | outline: 0;
16 |
17 | /* Optional rounded corners for browsers that support it */
18 | -moz-border-radius: 3px;
19 | -khtml-border-radius: 3px;
20 | -webkit-border-radius: 3px;
21 | border-radius: 3px;
22 | }
23 |
24 | .plupload_button:hover {
25 | color: #000;
26 | text-decoration: none;
27 | }
28 |
29 | .plupload_disabled, a.plupload_disabled:hover {
30 | color: #737373;
31 | border-color: #c5c5c5;
32 | background: #ededed url('../img/buttons-disabled.png') no-repeat 0 center;
33 | cursor: default;
34 | }
35 |
36 | .plupload_add {
37 | background-position: -181px center;
38 | }
39 |
40 | .plupload_wrapper {
41 | font: normal 11px Verdana,sans-serif;
42 | width: 100%;
43 | }
44 |
45 | .plupload_container {
46 | padding: 8px;
47 | background: url('../img/transp50.png');
48 | /*-moz-border-radius: 5px;*/
49 | }
50 |
51 | .plupload_container input {
52 | border: 1px solid #DDD;
53 | font: normal 11px Verdana,sans-serif;
54 | width: 98%;
55 | }
56 |
57 | .plupload_header {background: #2A2C2E url('../img/backgrounds.gif') repeat-x;}
58 | .plupload_header_content {
59 | background: url('../img/backgrounds.gif') no-repeat 0 -317px;
60 | min-height: 56px;
61 | padding-left: 60px;
62 | color: #FFF;
63 | }
64 | .plupload_header_title {
65 | font: normal 18px sans-serif;
66 | padding: 6px 0 3px;
67 | }
68 | .plupload_header_text {
69 | font: normal 12px sans-serif;
70 | }
71 |
72 | .plupload_filelist {
73 | margin: 0;
74 | padding: 0;
75 | list-style: none;
76 | }
77 |
78 | .plupload_scroll .plupload_filelist {
79 | height: 185px;
80 | background: #F5F5F5;
81 | overflow-y: scroll;
82 | }
83 |
84 | .plupload_filelist li {
85 | padding: 10px 8px;
86 | background: #F5F5F5 url('../img/backgrounds.gif') repeat-x 0 -156px;
87 | border-bottom: 1px solid #DDD;
88 | }
89 |
90 | .plupload_filelist_header, .plupload_filelist_footer {
91 | background: #DFDFDF;
92 | padding: 8px 8px;
93 | color: #42454A;
94 | }
95 | .plupload_filelist_header {
96 | border-top: 1px solid #EEE;
97 | border-bottom: 1px solid #CDCDCD;
98 | }
99 |
100 | .plupload_filelist_footer {border-top: 1px solid #FFF; height: 22px; line-height: 20px; vertical-align: middle;}
101 | .plupload_file_name {float: left; overflow: hidden}
102 | .plupload_file_status {color: #777;}
103 | .plupload_file_status span {color: #42454A;}
104 | .plupload_file_size, .plupload_file_status, .plupload_progress {
105 | float: right;
106 | width: 80px;
107 | }
108 | .plupload_file_size, .plupload_file_status, .plupload_file_action {text-align: right;}
109 |
110 | .plupload_filelist .plupload_file_name {width: 205px}
111 |
112 | .plupload_file_action {
113 | float: right;
114 | width: 16px;
115 | height: 16px;
116 | margin-left: 15px;
117 | }
118 |
119 | .plupload_file_action * {
120 | display: none;
121 | width: 16px;
122 | height: 16px;
123 | }
124 |
125 | li.plupload_uploading {background: #ECF3DC url('../img/backgrounds.gif') repeat-x 0 -238px;}
126 | li.plupload_done {color:#AAA}
127 |
128 | li.plupload_delete a {
129 | background: url('../img/delete.gif');
130 | }
131 |
132 | li.plupload_failed a {
133 | background: url('../img/error.gif');
134 | cursor: default;
135 | }
136 |
137 | li.plupload_done a {
138 | background: url('../img/done.gif');
139 | cursor: default;
140 | }
141 |
142 | .plupload_progress, .plupload_upload_status {
143 | display: none;
144 | }
145 |
146 | .plupload_progress_container {
147 | margin-top: 3px;
148 | border: 1px solid #CCC;
149 | background: #FFF;
150 | padding: 1px;
151 | }
152 | .plupload_progress_bar {
153 | width: 0px;
154 | height: 7px;
155 | background: #CDEB8B;
156 | }
157 |
158 | .plupload_scroll .plupload_filelist_header .plupload_file_action, .plupload_scroll .plupload_filelist_footer .plupload_file_action {
159 | margin-right: 17px;
160 | }
161 |
162 | /* Floats */
163 |
164 | .plupload_clear,.plupload_clearer {clear: both;}
165 | .plupload_clearer, .plupload_progress_bar {
166 | display: block;
167 | font-size: 0;
168 | line-height: 0;
169 | }
170 |
171 | li.plupload_droptext {
172 | background: transparent;
173 | text-align: center;
174 | vertical-align: middle;
175 | border: 0;
176 | line-height: 165px;
177 | }
178 |
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/img/Descr.WD3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/img/Descr.WD3
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/img/backgrounds.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/img/backgrounds.gif
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/img/buttons-disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/img/buttons-disabled.png
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/img/buttons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/img/buttons.png
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/img/done.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/img/done.gif
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/img/error.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/img/error.gif
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/jquery.plupload.queue/img/transp50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/jquery.plupload.queue/img/transp50.png
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/plupload.flash.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/plupload.flash.swf
--------------------------------------------------------------------------------
/src/theme/scripts/plupload/js/plupload.silverlight.xap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/theme/scripts/plupload/js/plupload.silverlight.xap
--------------------------------------------------------------------------------
/src/tmp/band.txt:
--------------------------------------------------------------------------------
1 | a:4:{i:0;s:0:"";i:1;s:6:"518.74";i:2;s:8:"12255.25";s:4:"time";i:1371564058;}}
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/Choker.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from random import randrange, shuffle
5 | from BitTornado.clock import clock
6 | try:
7 | True
8 | except:
9 | True = 1
10 | False = 0
11 |
12 | class Choker:
13 | def __init__(self, config, schedule, picker, done = lambda: False):
14 | self.config = config
15 | self.round_robin_period = config['round_robin_period']
16 | self.schedule = schedule
17 | self.picker = picker
18 | self.connections = []
19 | self.last_preferred = 0
20 | self.last_round_robin = clock()
21 | self.done = done
22 | self.super_seed = False
23 | self.paused = False
24 | schedule(self._round_robin, 5)
25 |
26 | def set_round_robin_period(self, x):
27 | self.round_robin_period = x
28 |
29 | def _round_robin(self):
30 | self.schedule(self._round_robin, 5)
31 | if self.super_seed:
32 | cons = range(len(self.connections))
33 | to_close = []
34 | count = self.config['min_uploads']-self.last_preferred
35 | if count > 0: # optimization
36 | shuffle(cons)
37 | for c in cons:
38 | i = self.picker.next_have(self.connections[c], count > 0)
39 | if i is None:
40 | continue
41 | if i < 0:
42 | to_close.append(self.connections[c])
43 | continue
44 | self.connections[c].send_have(i)
45 | count -= 1
46 | for c in to_close:
47 | c.close()
48 | if self.last_round_robin + self.round_robin_period < clock():
49 | self.last_round_robin = clock()
50 | for i in xrange(1, len(self.connections)):
51 | c = self.connections[i]
52 | u = c.get_upload()
53 | if u.is_choked() and u.is_interested():
54 | self.connections = self.connections[i:] + self.connections[:i]
55 | break
56 | self._rechoke()
57 |
58 | def _rechoke(self):
59 | preferred = []
60 | maxuploads = self.config['max_uploads']
61 | if self.paused:
62 | for c in self.connections:
63 | c.get_upload().choke()
64 | return
65 | if maxuploads > 1:
66 | for c in self.connections:
67 | u = c.get_upload()
68 | if not u.is_interested():
69 | continue
70 | if self.done():
71 | r = u.get_rate()
72 | else:
73 | d = c.get_download()
74 | r = d.get_rate()
75 | if r < 1000 or d.is_snubbed():
76 | continue
77 | preferred.append((-r, c))
78 | self.last_preferred = len(preferred)
79 | preferred.sort()
80 | del preferred[maxuploads-1:]
81 | preferred = [x[1] for x in preferred]
82 | count = len(preferred)
83 | hit = False
84 | to_unchoke = []
85 | for c in self.connections:
86 | u = c.get_upload()
87 | if c in preferred:
88 | to_unchoke.append(u)
89 | else:
90 | if count < maxuploads or not hit:
91 | to_unchoke.append(u)
92 | if u.is_interested():
93 | count += 1
94 | hit = True
95 | else:
96 | u.choke()
97 | for u in to_unchoke:
98 | u.unchoke()
99 |
100 | def connection_made(self, connection, p = None):
101 | if p is None:
102 | p = randrange(-2, len(self.connections) + 1)
103 | self.connections.insert(max(p, 0), connection)
104 | self._rechoke()
105 |
106 | def connection_lost(self, connection):
107 | self.connections.remove(connection)
108 | self.picker.lost_peer(connection)
109 | if connection.get_upload().is_interested() and not connection.get_upload().is_choked():
110 | self._rechoke()
111 |
112 | def interested(self, connection):
113 | if not connection.get_upload().is_choked():
114 | self._rechoke()
115 |
116 | def not_interested(self, connection):
117 | if not connection.get_upload().is_choked():
118 | self._rechoke()
119 |
120 | def set_super_seed(self):
121 | while self.connections: # close all connections
122 | self.connections[0].close()
123 | self.picker.set_superseed()
124 | self.super_seed = True
125 |
126 | def pause(self, flag):
127 | self.paused = flag
128 | self._rechoke()
129 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/DownloaderFeedback.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from cStringIO import StringIO
5 | from urllib import quote
6 | from threading import Event
7 |
8 | try:
9 | True
10 | except:
11 | True = 1
12 | False = 0
13 |
14 | INIT_STATE = (('R','R+'),('L','L+'))
15 |
16 | class DownloaderFeedback:
17 | def __init__(self, choker, httpdl, add_task, upfunc, downfunc,
18 | ratemeasure, leftfunc, file_length, finflag, sp, statistics,
19 | statusfunc = None, interval = None):
20 | self.choker = choker
21 | self.httpdl = httpdl
22 | self.add_task = add_task
23 | self.upfunc = upfunc
24 | self.downfunc = downfunc
25 | self.ratemeasure = ratemeasure
26 | self.leftfunc = leftfunc
27 | self.file_length = file_length
28 | self.finflag = finflag
29 | self.sp = sp
30 | self.statistics = statistics
31 | self.lastids = []
32 | self.spewdata = None
33 | self.doneprocessing = Event()
34 | self.doneprocessing.set()
35 | if statusfunc:
36 | self.autodisplay(statusfunc, interval)
37 |
38 |
39 | def _rotate(self):
40 | cs = self.choker.connections
41 | for id in self.lastids:
42 | for i in xrange(len(cs)):
43 | if cs[i].get_id() == id:
44 | return cs[i:] + cs[:i]
45 | return cs
46 |
47 | def spews(self):
48 | l = []
49 | cs = self._rotate()
50 | self.lastids = [c.get_id() for c in cs]
51 | for c in cs:
52 | a = {}
53 | a['id'] = c.get_readable_id()
54 | a['ip'] = c.get_ip()
55 | a['optimistic'] = (c is self.choker.connections[0])
56 | a['direction'] = INIT_STATE[c.is_locally_initiated()][c.is_encrypted()]
57 | u = c.get_upload()
58 | a['uprate'] = int(u.measure.get_rate())
59 | a['uinterested'] = u.is_interested()
60 | a['uchoked'] = u.is_choked()
61 | d = c.get_download()
62 | a['downrate'] = int(d.measure.get_rate())
63 | a['dinterested'] = d.is_interested()
64 | a['dchoked'] = d.is_choked()
65 | a['snubbed'] = d.is_snubbed()
66 | a['utotal'] = d.connection.upload.measure.get_total()
67 | a['dtotal'] = d.connection.download.measure.get_total()
68 | if len(d.connection.download.have) > 0:
69 | a['completed'] = float(len(d.connection.download.have)-d.connection.download.have.numfalse)/float(len(d.connection.download.have))
70 | else:
71 | a['completed'] = 1.0
72 | a['speed'] = d.connection.download.peermeasure.get_rate()
73 |
74 | l.append(a)
75 |
76 | for dl in self.httpdl.get_downloads():
77 | if dl.goodseed:
78 | a = {}
79 | a['id'] = 'http seed'
80 | a['ip'] = dl.baseurl
81 | a['optimistic'] = False
82 | a['direction'] = 'L'
83 | a['uprate'] = 0
84 | a['uinterested'] = False
85 | a['uchoked'] = False
86 | a['downrate'] = int(dl.measure.get_rate())
87 | a['dinterested'] = True
88 | a['dchoked'] = not dl.active
89 | a['snubbed'] = not dl.active
90 | a['utotal'] = None
91 | a['dtotal'] = dl.measure.get_total()
92 | a['completed'] = 1.0
93 | a['speed'] = None
94 |
95 | l.append(a)
96 |
97 | return l
98 |
99 |
100 | def gather(self, displayfunc = None):
101 | s = {'stats': self.statistics.update()}
102 | if self.sp.isSet():
103 | s['spew'] = self.spews()
104 | else:
105 | s['spew'] = None
106 | s['up'] = self.upfunc()
107 | if self.finflag.isSet():
108 | s['done'] = self.file_length
109 | return s
110 | s['down'] = self.downfunc()
111 | obtained, desired = self.leftfunc()
112 | s['done'] = obtained
113 | s['wanted'] = desired
114 | if desired > 0:
115 | s['frac'] = float(obtained)/desired
116 | else:
117 | s['frac'] = 1.0
118 | if desired == obtained:
119 | s['time'] = 0
120 | else:
121 | s['time'] = self.ratemeasure.get_time_left(desired-obtained)
122 | return s
123 |
124 |
125 | def display(self, displayfunc):
126 | if not self.doneprocessing.isSet():
127 | return
128 | self.doneprocessing.clear()
129 | stats = self.gather()
130 | if self.finflag.isSet():
131 | displayfunc(dpflag = self.doneprocessing,
132 | upRate = stats['up'],
133 | statistics = stats['stats'], spew = stats['spew'])
134 | elif stats['time'] is not None:
135 | displayfunc(dpflag = self.doneprocessing,
136 | fractionDone = stats['frac'], sizeDone = stats['done'],
137 | downRate = stats['down'], upRate = stats['up'],
138 | statistics = stats['stats'], spew = stats['spew'],
139 | timeEst = stats['time'])
140 | else:
141 | displayfunc(dpflag = self.doneprocessing,
142 | fractionDone = stats['frac'], sizeDone = stats['done'],
143 | downRate = stats['down'], upRate = stats['up'],
144 | statistics = stats['stats'], spew = stats['spew'])
145 |
146 |
147 | def autodisplay(self, displayfunc, interval):
148 | self.displayfunc = displayfunc
149 | self.interval = interval
150 | self._autodisplay()
151 |
152 | def _autodisplay(self):
153 | self.add_task(self._autodisplay, self.interval)
154 | self.display(self.displayfunc)
155 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/Filter.py:
--------------------------------------------------------------------------------
1 | class Filter:
2 | def __init__(self, callback):
3 | self.callback = callback
4 |
5 | def check(self, ip, paramslist, headers):
6 |
7 | def params(key, default = None, l = paramslist):
8 | if l.has_key(key):
9 | return l[key][0]
10 | return default
11 |
12 | return None
13 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/StreamCheck.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from cStringIO import StringIO
5 | from binascii import b2a_hex
6 | from socket import error as socketerror
7 | from urllib import quote
8 | from traceback import print_exc
9 | import Connecter
10 | try:
11 | True
12 | except:
13 | True = 1
14 | False = 0
15 |
16 | DEBUG = False
17 |
18 |
19 | protocol_name = 'BitTorrent protocol'
20 | option_pattern = chr(0)*8
21 |
22 | def toint(s):
23 | return long(b2a_hex(s), 16)
24 |
25 | def tobinary(i):
26 | return (chr(i >> 24) + chr((i >> 16) & 0xFF) +
27 | chr((i >> 8) & 0xFF) + chr(i & 0xFF))
28 |
29 | hexchars = '0123456789ABCDEF'
30 | hexmap = []
31 | for i in xrange(256):
32 | hexmap.append(hexchars[(i&0xF0)/16]+hexchars[i&0x0F])
33 |
34 | def tohex(s):
35 | r = []
36 | for c in s:
37 | r.append(hexmap[ord(c)])
38 | return ''.join(r)
39 |
40 | def make_readable(s):
41 | if not s:
42 | return ''
43 | if quote(s).find('%') >= 0:
44 | return tohex(s)
45 | return '"'+s+'"'
46 |
47 | def toint(s):
48 | return long(b2a_hex(s), 16)
49 |
50 | # header, reserved, download id, my id, [length, message]
51 |
52 | streamno = 0
53 |
54 |
55 | class StreamCheck:
56 | def __init__(self):
57 | global streamno
58 | self.no = streamno
59 | streamno += 1
60 | self.buffer = StringIO()
61 | self.next_len, self.next_func = 1, self.read_header_len
62 |
63 | def read_header_len(self, s):
64 | if ord(s) != len(protocol_name):
65 | print self.no, 'BAD HEADER LENGTH'
66 | return len(protocol_name), self.read_header
67 |
68 | def read_header(self, s):
69 | if s != protocol_name:
70 | print self.no, 'BAD HEADER'
71 | return 8, self.read_reserved
72 |
73 | def read_reserved(self, s):
74 | return 20, self.read_download_id
75 |
76 | def read_download_id(self, s):
77 | if DEBUG:
78 | print self.no, 'download ID ' + tohex(s)
79 | return 20, self.read_peer_id
80 |
81 | def read_peer_id(self, s):
82 | if DEBUG:
83 | print self.no, 'peer ID' + make_readable(s)
84 | return 4, self.read_len
85 |
86 | def read_len(self, s):
87 | l = toint(s)
88 | if l > 2 ** 23:
89 | print self.no, 'BAD LENGTH: '+str(l)+' ('+s+')'
90 | return l, self.read_message
91 |
92 | def read_message(self, s):
93 | if not s:
94 | return 4, self.read_len
95 | m = s[0]
96 | if ord(m) > 8:
97 | print self.no, 'BAD MESSAGE: '+str(ord(m))
98 | if m == Connecter.REQUEST:
99 | if len(s) != 13:
100 | print self.no, 'BAD REQUEST SIZE: '+str(len(s))
101 | return 4, self.read_len
102 | index = toint(s[1:5])
103 | begin = toint(s[5:9])
104 | length = toint(s[9:])
105 | print self.no, 'Request: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)
106 | elif m == Connecter.CANCEL:
107 | if len(s) != 13:
108 | print self.no, 'BAD CANCEL SIZE: '+str(len(s))
109 | return 4, self.read_len
110 | index = toint(s[1:5])
111 | begin = toint(s[5:9])
112 | length = toint(s[9:])
113 | print self.no, 'Cancel: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)
114 | elif m == Connecter.PIECE:
115 | index = toint(s[1:5])
116 | begin = toint(s[5:9])
117 | length = len(s)-9
118 | print self.no, 'Piece: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)
119 | else:
120 | print self.no, 'Message '+str(ord(m))+' (length '+str(len(s))+')'
121 | return 4, self.read_len
122 |
123 | def write(self, s):
124 | while True:
125 | i = self.next_len - self.buffer.tell()
126 | if i > len(s):
127 | self.buffer.write(s)
128 | return
129 | self.buffer.write(s[:i])
130 | s = s[i:]
131 | m = self.buffer.getvalue()
132 | self.buffer.reset()
133 | self.buffer.truncate()
134 | x = self.next_func(m)
135 | self.next_len, self.next_func = x
136 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/Uploader.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from BitTornado.CurrentRateMeasure import Measure
5 |
6 | try:
7 | True
8 | except:
9 | True = 1
10 | False = 0
11 |
12 | class Upload:
13 | def __init__(self, connection, ratelimiter, totalup, choker, storage,
14 | picker, config):
15 | self.connection = connection
16 | self.ratelimiter = ratelimiter
17 | self.totalup = totalup
18 | self.choker = choker
19 | self.storage = storage
20 | self.picker = picker
21 | self.config = config
22 | self.max_slice_length = config['max_slice_length']
23 | self.choked = True
24 | self.cleared = True
25 | self.interested = False
26 | self.super_seeding = False
27 | self.buffer = []
28 | self.measure = Measure(config['max_rate_period'], config['upload_rate_fudge'])
29 | self.was_ever_interested = False
30 | if storage.get_amount_left() == 0:
31 | if choker.super_seed:
32 | self.super_seeding = True # flag, and don't send bitfield
33 | self.seed_have_list = [] # set from piecepicker
34 | self.skipped_count = 0
35 | else:
36 | if config['breakup_seed_bitfield']:
37 | bitfield, msgs = storage.get_have_list_cloaked()
38 | connection.send_bitfield(bitfield)
39 | for have in msgs:
40 | connection.send_have(have)
41 | else:
42 | connection.send_bitfield(storage.get_have_list())
43 | else:
44 | if storage.do_I_have_anything():
45 | connection.send_bitfield(storage.get_have_list())
46 | self.piecedl = None
47 | self.piecebuf = None
48 |
49 | def got_not_interested(self):
50 | if self.interested:
51 | self.interested = False
52 | del self.buffer[:]
53 | self.piecedl = None
54 | if self.piecebuf:
55 | self.piecebuf.release()
56 | self.piecebuf = None
57 | self.choker.not_interested(self.connection)
58 |
59 | def got_interested(self):
60 | if not self.interested:
61 | self.interested = True
62 | self.was_ever_interested = True
63 | self.choker.interested(self.connection)
64 |
65 | def get_upload_chunk(self):
66 | if self.choked or not self.buffer:
67 | return None
68 | index, begin, length = self.buffer.pop(0)
69 | if self.config['buffer_reads']:
70 | if index != self.piecedl:
71 | if self.piecebuf:
72 | self.piecebuf.release()
73 | self.piecedl = index
74 | self.piecebuf = self.storage.get_piece(index, 0, -1)
75 | try:
76 | piece = self.piecebuf[begin:begin+length]
77 | assert len(piece) == length
78 | except: # fails if storage.get_piece returns None or if out of range
79 | self.connection.close()
80 | return None
81 | else:
82 | if self.piecebuf:
83 | self.piecebuf.release()
84 | self.piecedl = None
85 | piece = self.storage.get_piece(index, begin, length)
86 | if piece is None:
87 | self.connection.close()
88 | return None
89 | self.measure.update_rate(len(piece))
90 | self.totalup.update_rate(len(piece))
91 | return (index, begin, piece)
92 |
93 | def got_request(self, index, begin, length):
94 | if ( (self.super_seeding and not index in self.seed_have_list)
95 | or not self.interested or length > self.max_slice_length ):
96 | self.connection.close()
97 | return
98 | if not self.cleared:
99 | self.buffer.append((index, begin, length))
100 | if not self.choked and self.connection.next_upload is None:
101 | self.ratelimiter.queue(self.connection)
102 |
103 |
104 | def got_cancel(self, index, begin, length):
105 | try:
106 | self.buffer.remove((index, begin, length))
107 | except ValueError:
108 | pass
109 |
110 | def choke(self):
111 | if not self.choked:
112 | self.choked = True
113 | self.connection.send_choke()
114 | self.piecedl = None
115 | if self.piecebuf:
116 | self.piecebuf.release()
117 | self.piecebuf = None
118 |
119 | def choke_sent(self):
120 | del self.buffer[:]
121 | self.cleared = True
122 |
123 | def unchoke(self):
124 | if self.choked:
125 | self.choked = False
126 | self.cleared = False
127 | self.connection.send_unchoke()
128 |
129 | def disconnected(self):
130 | if self.piecebuf:
131 | self.piecebuf.release()
132 | self.piecebuf = None
133 |
134 | def is_choked(self):
135 | return self.choked
136 |
137 | def is_interested(self):
138 | return self.interested
139 |
140 | def has_queries(self):
141 | return not self.choked and len(self.buffer) > 0
142 |
143 | def get_rate(self):
144 | return self.measure.get_rate()
145 |
146 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/__init__.py:
--------------------------------------------------------------------------------
1 | # placeholder
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/btformats.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from types import StringType, LongType, IntType, ListType, DictType
5 | from re import compile
6 |
7 | reg = compile(r'^[^/\\.~][^/\\]*$')
8 |
9 | ints = (LongType, IntType)
10 |
11 | def check_info(info):
12 | if type(info) != DictType:
13 | raise ValueError, 'bad metainfo - not a dictionary'
14 | pieces = info.get('pieces')
15 | if type(pieces) != StringType or len(pieces) % 20 != 0:
16 | raise ValueError, 'bad metainfo - bad pieces key'
17 | piecelength = info.get('piece length')
18 | if type(piecelength) not in ints or piecelength <= 0:
19 | raise ValueError, 'bad metainfo - illegal piece length'
20 | name = info.get('name')
21 | if type(name) != StringType:
22 | raise ValueError, 'bad metainfo - bad name'
23 | if not reg.match(name):
24 | raise ValueError, 'name %s disallowed for security reasons' % name
25 | if info.has_key('files') == info.has_key('length'):
26 | raise ValueError, 'single/multiple file mix'
27 | if info.has_key('length'):
28 | length = info.get('length')
29 | if type(length) not in ints or length < 0:
30 | raise ValueError, 'bad metainfo - bad length'
31 | else:
32 | files = info.get('files')
33 | if type(files) != ListType:
34 | raise ValueError
35 | for f in files:
36 | if type(f) != DictType:
37 | raise ValueError, 'bad metainfo - bad file value'
38 | length = f.get('length')
39 | if type(length) not in ints or length < 0:
40 | raise ValueError, 'bad metainfo - bad length'
41 | path = f.get('path')
42 | if type(path) != ListType or path == []:
43 | raise ValueError, 'bad metainfo - bad path'
44 | for p in path:
45 | if type(p) != StringType:
46 | raise ValueError, 'bad metainfo - bad path dir'
47 | if not reg.match(p):
48 | raise ValueError, 'path %s disallowed for security reasons' % p
49 | for i in xrange(len(files)):
50 | for j in xrange(i):
51 | if files[i]['path'] == files[j]['path']:
52 | raise ValueError, 'bad metainfo - duplicate path'
53 |
54 | def check_message(message):
55 | if type(message) != DictType:
56 | raise ValueError
57 | check_info(message.get('info'))
58 | if type(message.get('announce')) != StringType:
59 | raise ValueError
60 |
61 | def check_peers(message):
62 | if type(message) != DictType:
63 | raise ValueError
64 | if message.has_key('failure reason'):
65 | if type(message['failure reason']) != StringType:
66 | raise ValueError
67 | return
68 | peers = message.get('peers')
69 | if type(peers) == ListType:
70 | for p in peers:
71 | if type(p) != DictType:
72 | raise ValueError
73 | if type(p.get('ip')) != StringType:
74 | raise ValueError
75 | port = p.get('port')
76 | if type(port) not in ints or p <= 0:
77 | raise ValueError
78 | if p.has_key('peer id'):
79 | id = p['peer id']
80 | if type(id) != StringType or len(id) != 20:
81 | raise ValueError
82 | elif type(peers) != StringType or len(peers) % 6 != 0:
83 | raise ValueError
84 | interval = message.get('interval', 1)
85 | if type(interval) not in ints or interval <= 0:
86 | raise ValueError
87 | minint = message.get('min interval', 1)
88 | if type(minint) not in ints or minint <= 0:
89 | raise ValueError
90 | if type(message.get('tracker id', '')) != StringType:
91 | raise ValueError
92 | npeers = message.get('num peers', 0)
93 | if type(npeers) not in ints or npeers < 0:
94 | raise ValueError
95 | dpeers = message.get('done peers', 0)
96 | if type(dpeers) not in ints or dpeers < 0:
97 | raise ValueError
98 | last = message.get('last', 0)
99 | if type(last) not in ints or last < 0:
100 | raise ValueError
101 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BT1/fakeopen.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from string import join
5 |
6 | class FakeHandle:
7 | def __init__(self, name, fakeopen):
8 | self.name = name
9 | self.fakeopen = fakeopen
10 | self.pos = 0
11 |
12 | def flush(self):
13 | pass
14 |
15 | def close(self):
16 | pass
17 |
18 | def seek(self, pos):
19 | self.pos = pos
20 |
21 | def read(self, amount = None):
22 | old = self.pos
23 | f = self.fakeopen.files[self.name]
24 | if self.pos >= len(f):
25 | return ''
26 | if amount is None:
27 | self.pos = len(f)
28 | return join(f[old:], '')
29 | else:
30 | self.pos = min(len(f), old + amount)
31 | return join(f[old:self.pos], '')
32 |
33 | def write(self, s):
34 | f = self.fakeopen.files[self.name]
35 | while len(f) < self.pos:
36 | f.append(chr(0))
37 | self.fakeopen.files[self.name][self.pos : self.pos + len(s)] = list(s)
38 | self.pos += len(s)
39 |
40 | class FakeOpen:
41 | def __init__(self, initial = {}):
42 | self.files = {}
43 | for key, value in initial.items():
44 | self.files[key] = list(value)
45 |
46 | def open(self, filename, mode):
47 | """currently treats everything as rw - doesn't support append"""
48 | self.files.setdefault(filename, [])
49 | return FakeHandle(filename, self)
50 |
51 | def exists(self, file):
52 | return self.files.has_key(file)
53 |
54 | def getsize(self, file):
55 | return len(self.files[file])
56 |
57 | def test_normal():
58 | f = FakeOpen({'f1': 'abcde'})
59 | assert f.exists('f1')
60 | assert not f.exists('f2')
61 | assert f.getsize('f1') == 5
62 | h = f.open('f1', 'rw')
63 | assert h.read(3) == 'abc'
64 | assert h.read(1) == 'd'
65 | assert h.read() == 'e'
66 | assert h.read(2) == ''
67 | h.write('fpq')
68 | h.seek(4)
69 | assert h.read(2) == 'ef'
70 | h.write('ghij')
71 | h.seek(0)
72 | assert h.read() == 'abcdefghij'
73 | h.seek(2)
74 | h.write('p')
75 | h.write('q')
76 | assert h.read(1) == 'e'
77 | h.seek(1)
78 | assert h.read(5) == 'bpqef'
79 |
80 | h2 = f.open('f2', 'rw')
81 | assert h2.read() == ''
82 | h2.write('mnop')
83 | h2.seek(1)
84 | assert h2.read() == 'nop'
85 |
86 | assert f.exists('f1')
87 | assert f.exists('f2')
88 | assert f.getsize('f1') == 10
89 | assert f.getsize('f2') == 4
90 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/BTcrypto.py:
--------------------------------------------------------------------------------
1 | # Written by John Hoffman
2 | # based on code by Uoti Urpala
3 | # see LICENSE.txt for license information
4 |
5 | from __future__ import generators # for python 2.2
6 | from random import randrange,randint,seed
7 | try:
8 | from os import urandom
9 | except:
10 | seed()
11 | urandom = lambda x: ''.join([chr(randint(0,255)) for i in xrange(x)])
12 | from hashlib import sha1
13 |
14 | try:
15 | True
16 | except:
17 | True = 1
18 | False = 0
19 |
20 | try:
21 | from Crypto.Cipher import ARC4
22 | CRYPTO_OK = True
23 | except:
24 | CRYPTO_OK = False
25 |
26 | KEY_LENGTH = 160
27 | DH_PRIME = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563
28 | PAD_MAX = 200 # less than protocol maximum, and later assumed to be < 256
29 | DH_BYTES = 96
30 |
31 | def bytetonum(x):
32 | return long(x.encode('hex'), 16)
33 |
34 | def numtobyte(x):
35 | x = hex(x).lstrip('0x').rstrip('Ll')
36 | x = '0'*(192 - len(x)) + x
37 | return x.decode('hex')
38 |
39 | class Crypto:
40 | def __init__(self, initiator, disable_crypto = False):
41 | self.initiator = initiator
42 | self.disable_crypto = disable_crypto
43 | if not disable_crypto and not CRYPTO_OK:
44 | raise NotImplementedError, "attempt to run encryption w/ none installed"
45 | self.privkey = bytetonum(urandom(KEY_LENGTH/8))
46 | self.pubkey = numtobyte(pow(2, self.privkey, DH_PRIME))
47 | self.keylength = DH_BYTES
48 | self._VC_pattern = None
49 |
50 | def received_key(self, k):
51 | self.S = numtobyte(pow(bytetonum(k), self.privkey, DH_PRIME))
52 | self.block3a = sha1('req1'+self.S).digest()
53 | self.block3bkey = sha1('req3'+self.S).digest()
54 | self.block3b = None
55 |
56 | def _gen_block3b(self, SKEY):
57 | a = sha1('req2'+SKEY).digest()
58 | return ''.join([ chr(ord(a[i])^ord(self.block3bkey[i]))
59 | for i in xrange(20) ])
60 |
61 | def test_skey(self, s, SKEY):
62 | block3b = self._gen_block3b(SKEY)
63 | if block3b != s:
64 | return False
65 | self.block3b = block3b
66 | if not self.disable_crypto:
67 | self.set_skey(SKEY)
68 | return True
69 |
70 | def set_skey(self, SKEY):
71 | if not self.block3b:
72 | self.block3b = self._gen_block3b(SKEY)
73 | crypta = ARC4.new(sha1('keyA'+self.S+SKEY).digest())
74 | cryptb = ARC4.new(sha1('keyB'+self.S+SKEY).digest())
75 | if self.initiator:
76 | self.encrypt = crypta.encrypt
77 | self.decrypt = cryptb.decrypt
78 | else:
79 | self.encrypt = cryptb.encrypt
80 | self.decrypt = crypta.decrypt
81 | self.encrypt('x'*1024) # discard first 1024 bytes
82 | self.decrypt('x'*1024)
83 |
84 | def VC_pattern(self):
85 | if not self._VC_pattern:
86 | self._VC_pattern = self.decrypt('\x00'*8)
87 | return self._VC_pattern
88 |
89 |
90 | def read(self, s):
91 | self._read(self.decrypt(s))
92 |
93 | def write(self, s):
94 | self._write(self.encrypt(s))
95 |
96 | def setrawaccess(self, _read, _write):
97 | self._read = _read
98 | self._write = _write
99 |
100 | def padding(self):
101 | return urandom(randrange(PAD_MAX-16)+16)
102 |
103 |
104 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/ConnChoice.py:
--------------------------------------------------------------------------------
1 | connChoices=(
2 | {'name':'automatic',
3 | 'rate':{'min':0, 'max':5000, 'def': 0},
4 | 'conn':{'min':0, 'max':100, 'def': 0},
5 | 'automatic':1},
6 | {'name':'unlimited',
7 | 'rate':{'min':0, 'max':5000, 'def': 0, 'div': 50},
8 | 'conn':{'min':4, 'max':100, 'def': 4}},
9 | {'name':'dialup/isdn',
10 | 'rate':{'min':3, 'max': 8, 'def': 5},
11 | 'conn':{'min':2, 'max': 3, 'def': 2},
12 | 'initiate': 12},
13 | {'name':'dsl/cable slow',
14 | 'rate':{'min':10, 'max': 48, 'def': 13},
15 | 'conn':{'min':4, 'max': 20, 'def': 4}},
16 | {'name':'dsl/cable fast',
17 | 'rate':{'min':20, 'max': 100, 'def': 40},
18 | 'conn':{'min':4, 'max': 30, 'def': 6}},
19 | {'name':'T1',
20 | 'rate':{'min':100, 'max': 300, 'def':150},
21 | 'conn':{'min':4, 'max': 40, 'def':10}},
22 | {'name':'T3+',
23 | 'rate':{'min':400, 'max':2000, 'def':500},
24 | 'conn':{'min':4, 'max':100, 'def':20}},
25 | {'name':'seeder',
26 | 'rate':{'min':0, 'max':5000, 'def':0, 'div': 50},
27 | 'conn':{'min':1, 'max':100, 'def':1}},
28 | {'name':'SUPER-SEED', 'super-seed':1}
29 | )
30 |
31 | connChoiceList = map(lambda x:x['name'], connChoices)
32 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/CreateIcons.py:
--------------------------------------------------------------------------------
1 | # Generated from bt_MakeCreateIcons - 05/10/04 22:15:33
2 | # T-0.3.0 (BitTornado)
3 |
4 | from binascii import a2b_base64
5 | from zlib import decompress
6 | from os.path import join
7 |
8 | icons = {
9 | "icon_bt.ico":
10 | "eJyt1K+OFEEQx/FaQTh5GDRZhSQpiUHwCrxCBYXFrjyJLXeXEARPsZqUPMm+" +
11 | "AlmP+PGtngoLDji69zMz2zt/qqtr1mxHv7621d4+MnvK/jl66Bl2drV+e7Wz" +
12 | "S/v12A7rY4fDtuvOwfF4tOPXo52/fLLz+WwpWd6nqRXHKXux39sTrtnjNd7g" +
13 | "PW7wGSd860f880kffjvJ2QYS1Zcw4AjcoaA5yRFIFDQXOgKJguZmjkCioB4T" +
14 | "Y2CqxpTXA7sHEgVNEC8RSBQ0gfk7xtknCupgk3EEEgXlNgFHIFHQTMoRSBQ0" +
15 | "E+1ouicKmsk7AomCJiGOQKKgSZIjkChoEucIJAqaZDoCiYImwb4iydULmqQ7" +
16 | "AomC1kLcEQ/jSBQ0i+MIJAqaBXMEElVdi9siOgKJgmZhfWWlVjTddXW/FtsR" +
17 | "SBQ0BeAIJAqaonAEEgVNoTgCiYKmeByBREHaqiVWRtSRrAJzBBIFTdE5AomC" +
18 | "phBPpxPP57dVkDfrTl063nUVnWe383fZx9tb3uN+o7U+BLDtuvcQm8d/27Y/" +
19 | "jO3o5/ay+YPv/+f6y30e1OyB7QcsGWFj",
20 | "icon_done.ico":
21 | "eJyt1K2OVEEQhuEaQbJyMWgyCklSEoPgFvYWKigsduRKbLndhCC4itGk5Erm" +
22 | "Fsh4xMdbfSoMOGDpnuf89Jyf6uqaMdvRr69ttbdPzJ6xf4Eeeo6dXa3vXu/s" +
23 | "0n49tsP62OGw7bpzcDwe7fj1aOcvn+x8PltKlg9pasVxyl7u9/aUe/Z4gxu8" +
24 | "xy0+44Rv/Yp/vujDbxc520Ci+hYGHIF7FDQXOQKJguZGRyBR0DzMEUgU1GNi" +
25 | "DEzVmPJ6YfdAoqAJ4hUCiYImMH/HOPtEQR1sMo5AoqDcJuAIJAqaSTkCiYJm" +
26 | "oh1N90RBM3lHIFHQJMQRSBQ0SXIEEgVN4hyBREGTTEcgUdAk2FckuXpBk3RH" +
27 | "IFHQWoh74mEciYJmcRyBREGzYI5AoqprcVtERyBR0Cysr6zUiqa7rh7WYjsC" +
28 | "iYKmAByBREFTFI5AoqApFEcgUdAUjyOQKEhbtcTKiDqSVWCOQKKgKTpHIFHQ" +
29 | "FOLpdOL9fLcK8nY9qUvHu66i8+x2/i77eHfH77h/0VofAth23Xuoz/+2bX8Y" +
30 | "29HP7WXzB+f/5/7Lcx7V7JHtB9dPG3I=",
31 | "black.ico":
32 | "eJzt1zsOgkAYReFLLCztjJ2UlpLY485kOS7DpbgESwqTcQZDghjxZwAfyfl0" +
33 | "LIieGzUWSom/pan840rHnbSUtPHHX9Je9+tAh2ybNe8TZZ/vk8ajJ4zl6JVJ" +
34 | "+xFx+0R03Djx1/2B8bcT9L/bt0+4Wq+4se8e/VTfMvGqb4n3nYiIGz+lvt9s" +
35 | "9EpE2T4xJN4xNFYWU6t+JWXuXDFzTom7SodSyi/S+iwtwjlJ80KaNY/C34rW" +
36 | "aT8nvK5uhF7ohn7Yqfb87kffLAAAAAAAAAAAAAAAAAAAGMUNy7dADg==",
37 | "blue.ico":
38 | "eJzt10EOwUAYhuGv6cLSTux06QD2dTM9jmM4iiNYdiEZ81cIFTWddtDkfbQW" +
39 | "De8XogtS5h9FIf+81H4jLSSt/ekvaavrdaCDez4SZV+PpPHoicBy9ErSfkQ8" +
40 | "fCI6Hjgx6f7A+McJ+r/t95i46xMP7bf8Uz9o4k0/XMT338voP5shK0MkjXcM" +
41 | "YSqam6Qunatyf7Nk7iztaqk8SaujNLfzIM0qKX88ZX8rWmf7Nfa+W8N61rW+" +
42 | "7TR7fverHxYAAAAAAAAAAAAAAAAAAIziApVZ444=",
43 | "green.ico":
44 | "eJzt1zEOgjAAheFHGBzdjJuMHsAdbybxNB7Do3gERwaT2mJIBCOWlqok/yc4" +
45 | "EP1fNDIoZfZRFLLPa5120krS1p72kvZ6XAeGHLtHouzrkTQePOFZDl5J2g+I" +
46 | "+08Exz0nZt2PjH+coP/bvveEaY2L+/VN13/1PSbe9v0FfP+jTP6ziVmJkTQ+" +
47 | "MISZaO6SujSmyu3dkpmbdKil8iptLtLSnWdpUUn58yn3t6J39l/j3tc2XM91" +
48 | "Xd/tNHt296sfFgAAAAAAAAAAAAAAAAAATOIOVLEoDg==",
49 | "red.ico":
50 | "eJzt10EOwUAYhuGv6cLSTux06QD2dTOO4xiO4giWXUjG/BVCRTuddtDkfbQW" +
51 | "De8XogtS5h9FIf+81GEjLSSt/ekvaavbdaCVez0SZd+PpPHoicBy9ErSfkQ8" +
52 | "fCI6Hjgx6f7AeOcE/d/2QyceesaD+g1/1u+e+NwPF/H99zL6z2bIyhBJ4y1D" +
53 | "mIb6LqlK5/a5v1syd5F2lVSepdVJmtt5lGZ7KX8+ZX8rGmfzNfa+e8N61rW+" +
54 | "7dR7fverHxYAAAAAAAAAAAAAAAAAAIziCpgs444=",
55 | "white.ico":
56 | "eJzt1zsOgkAYReFLKCztjJ2ULsAed6bLcRnuwYTaJVhSmIwzGBLEiD8D+EjO" +
57 | "p2NB9NyosVBK/C3L5B+XOmykhaS1P/6StrpfBzoUp6J5nyj7fJ80Hj1hLEev" +
58 | "TNqPiNsnouPGib/uD4y/naD/3b59wtV6xY199+in+paJV31LvO9ERNz4KfX9" +
59 | "ZqNXIsr2iSHxjqGxspha9Sspc+f2qXNK3FXalVJ+kVZnaR7OUZrtpbR5FP5W" +
60 | "tE77OeF1dSP0Qjf0w06153c/+mYBAAAAAAAAAAAAAAAAAMAobj//I7s=",
61 | "yellow.ico":
62 | "eJzt1zsOgkAYReFLKCztjJ2ULsAedybLcRkuxSVYUpiM82M0ihGHgVFJzidY" +
63 | "ED03vgqlzN+KQv5+qf1GWkha+9Nf0lbX60AX556ORNnXI2k8eiKwHL2StB8R" +
64 | "D5+IjgdOTLo/MP5xgv5v+8ETd/3iYf2W/+oHTLzth4t4/3sZ/WszZGWIpPGO" +
65 | "IUxE8yupS+eq3H9smTtLu1oqT9LqKM3tPEizSsofT9nfitbZfow979awnnWt" +
66 | "bzvNnt/96osFAAAAAAAAAAAAAAAAAACjuABhjmIs",
67 | "black1.ico":
68 | "eJzt0zEOgkAUANEhFpZSGTstTWzkVt5Cj8ZROAIHMNGPWBCFDYgxMZkHn2Iz" +
69 | "G5YCyOLKc+K54XSANbCPiSV2tOt/qjgW3XtSnN41FH/Qv29Jx/P7qefp7W8P" +
70 | "4z85HQ+9JRG/7BpTft31DPUKyiVcFjEZzQ/TTtdzrWnKmCr6evv780qSJEmS" +
71 | "JEmSJEmSJEmSpPnunVFDcA==",
72 | "green1.ico":
73 | "eJzt0zEKwkAQRuEXLCyTSuy0DHgxb6F4shzFI+QAgpkkFoombowIwvt2Z4vh" +
74 | "X5gtFrJYRUGca/Y7WAFlVLTY0vf/1elxTwqP3xoKf5B/vjIenp+fOs+r/LWT" +
75 | "/uQ34aGpUqQnv+1ygDqHagnHRVRG+2H6unfrtZkq6hz5evP7eSVJkiRJkiRJ" +
76 | "kiRJkiRJ0nwNoWQ+AA==",
77 | "yellow1.ico":
78 | "eJzt0zEKwkAQRuEXLCxNJXZaCl7MW8Sj5SgeIQcQ4oS1UDTJxkhAeN/ubDH8" +
79 | "C7PFQhGrLIlzx/kEW+AYFS0OpP6/atuXPSk8fKsv/EX+/cpweH5+6jyf8kn+" +
80 | "k0fCfVPlyE/+2q2CZgP1Gi6rqILuw6R69uh1mTrqGvlmv/y8kiRJkiRJkiRJ" +
81 | "kiRJkiRpvjsp9L8k",
82 | "alloc.gif":
83 | "eJxz93SzsEw0YRBh+M4ABi0MS3ue///P8H8UjIIRBhR/sjAyMDAx6IAyAihP" +
84 | "MHAcYWDlkPHYsOBgM4ewVsyJDQsPNzEoebF8CHjo0smjH3dmRsDjI33C7Dw3" +
85 | "MiYuOtjNyDShRSNwyemJguJJKhaGS32nGka61Vg2NJyYKRd+bY+nwtMzjbqV" +
86 | "Qh84gxMCJgnlL4vJuqJyaa5NfFLNLsNVV2a7syacfVWkHd4bv7RN1ltM7ejm" +
87 | "tMtNZ19Oyb02p8C3aqr3dr2GbXl/7fZyOej5rW653WZ7MzzHZV+v7O2/EZM+" +
88 | "Pt45kbX6ScWHNWfOilo3n5thucXv8org1XF3DRQYrAEWiVY3"
89 | }
90 |
91 | def GetIcons():
92 | return icons.keys()
93 |
94 | def CreateIcon(icon, savedir):
95 | try:
96 | f = open(join(savedir,icon),"wb")
97 | f.write(decompress(a2b_base64(icons[icon])))
98 | success = 1
99 | except:
100 | success = 0
101 | try:
102 | f.close()
103 | except:
104 | pass
105 | return success
106 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/CurrentRateMeasure.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from clock import clock
5 |
6 | class Measure:
7 | def __init__(self, max_rate_period, fudge = 1):
8 | self.max_rate_period = max_rate_period
9 | self.ratesince = clock() - fudge
10 | self.last = self.ratesince
11 | self.rate = 0.0
12 | self.total = 0l
13 |
14 | def update_rate(self, amount):
15 | self.total += amount
16 | t = clock()
17 | self.rate = (self.rate * (self.last - self.ratesince) +
18 | amount) / (t - self.ratesince + 0.0001)
19 | self.last = t
20 | if self.ratesince < t - self.max_rate_period:
21 | self.ratesince = t - self.max_rate_period
22 |
23 | def get_rate(self):
24 | self.update_rate(0)
25 | return self.rate
26 |
27 | def get_rate_noupdate(self):
28 | return self.rate
29 |
30 | def time_until_rate(self, newrate):
31 | if self.rate <= newrate:
32 | return 0
33 | t = clock() - self.ratesince
34 | return ((self.rate * t) / newrate) - t
35 |
36 | def get_total(self):
37 | return self.total
--------------------------------------------------------------------------------
/src/tornado/BitTornado/PSYCO.py:
--------------------------------------------------------------------------------
1 | # edit this file to enable/disable Psyco
2 | # psyco = 1 -- enabled
3 | # psyco = 0 -- disabled
4 |
5 | psyco = 0
6 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/RateLimiter.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from traceback import print_exc
5 | from binascii import b2a_hex
6 | from clock import clock
7 | from CurrentRateMeasure import Measure
8 | from cStringIO import StringIO
9 | from math import sqrt
10 |
11 | try:
12 | True
13 | except:
14 | True = 1
15 | False = 0
16 | try:
17 | sum([1])
18 | except:
19 | sum = lambda a: reduce(lambda x,y: x+y, a, 0)
20 |
21 | DEBUG = False
22 |
23 | MAX_RATE_PERIOD = 20.0
24 | MAX_RATE = 10e10
25 | PING_BOUNDARY = 1.2
26 | PING_SAMPLES = 7
27 | PING_DISCARDS = 1
28 | PING_THRESHHOLD = 5
29 | PING_DELAY = 5 # cycles 'til first upward adjustment
30 | PING_DELAY_NEXT = 2 # 'til next
31 | ADJUST_UP = 1.05
32 | ADJUST_DOWN = 0.95
33 | UP_DELAY_FIRST = 5
34 | UP_DELAY_NEXT = 2
35 | SLOTS_STARTING = 6
36 | SLOTS_FACTOR = 1.66/1000
37 |
38 | class RateLimiter:
39 | def __init__(self, sched, unitsize, slotsfunc = lambda x: None):
40 | self.sched = sched
41 | self.last = None
42 | self.unitsize = unitsize
43 | self.slotsfunc = slotsfunc
44 | self.measure = Measure(MAX_RATE_PERIOD)
45 | self.autoadjust = False
46 | self.upload_rate = MAX_RATE * 1000
47 | self.slots = SLOTS_STARTING # garbage if not automatic
48 |
49 | def set_upload_rate(self, rate):
50 | # rate = -1 # test automatic
51 | if rate < 0:
52 | if self.autoadjust:
53 | return
54 | self.autoadjust = True
55 | self.autoadjustup = 0
56 | self.pings = []
57 | rate = MAX_RATE
58 | self.slots = SLOTS_STARTING
59 | self.slotsfunc(self.slots)
60 | else:
61 | self.autoadjust = False
62 | if not rate:
63 | rate = MAX_RATE
64 | self.upload_rate = rate * 1000
65 | self.lasttime = clock()
66 | self.bytes_sent = 0
67 |
68 | def queue(self, conn):
69 | assert conn.next_upload is None
70 | if self.last is None:
71 | self.last = conn
72 | conn.next_upload = conn
73 | self.try_send(True)
74 | else:
75 | conn.next_upload = self.last.next_upload
76 | self.last.next_upload = conn
77 | self.last = conn
78 |
79 | def try_send(self, check_time = False):
80 | t = clock()
81 | self.bytes_sent -= (t - self.lasttime) * self.upload_rate
82 | self.lasttime = t
83 | if check_time:
84 | self.bytes_sent = max(self.bytes_sent, 0)
85 | cur = self.last.next_upload
86 | while self.bytes_sent <= 0:
87 | bytes = cur.send_partial(self.unitsize)
88 | self.bytes_sent += bytes
89 | self.measure.update_rate(bytes)
90 | if bytes == 0 or cur.backlogged():
91 | if self.last is cur:
92 | self.last = None
93 | cur.next_upload = None
94 | break
95 | else:
96 | self.last.next_upload = cur.next_upload
97 | cur.next_upload = None
98 | cur = self.last.next_upload
99 | else:
100 | self.last = cur
101 | cur = cur.next_upload
102 | else:
103 | self.sched(self.try_send, self.bytes_sent / self.upload_rate)
104 |
105 | def adjust_sent(self, bytes):
106 | self.bytes_sent = min(self.bytes_sent+bytes, self.upload_rate*3)
107 | self.measure.update_rate(bytes)
108 |
109 |
110 | def ping(self, delay):
111 | if DEBUG:
112 | print delay
113 | if not self.autoadjust:
114 | return
115 | self.pings.append(delay > PING_BOUNDARY)
116 | if len(self.pings) < PING_SAMPLES+PING_DISCARDS:
117 | return
118 | if DEBUG:
119 | print 'cycle'
120 | pings = sum(self.pings[PING_DISCARDS:])
121 | del self.pings[:]
122 | if pings >= PING_THRESHHOLD: # assume flooded
123 | if self.upload_rate == MAX_RATE:
124 | self.upload_rate = self.measure.get_rate()*ADJUST_DOWN
125 | else:
126 | self.upload_rate = min(self.upload_rate,
127 | self.measure.get_rate()*1.1)
128 | self.upload_rate = max(int(self.upload_rate*ADJUST_DOWN),2)
129 | self.slots = int(sqrt(self.upload_rate*SLOTS_FACTOR))
130 | self.slotsfunc(self.slots)
131 | if DEBUG:
132 | print 'adjust down to '+str(self.upload_rate)
133 | self.lasttime = clock()
134 | self.bytes_sent = 0
135 | self.autoadjustup = UP_DELAY_FIRST
136 | else: # not flooded
137 | if self.upload_rate == MAX_RATE:
138 | return
139 | self.autoadjustup -= 1
140 | if self.autoadjustup:
141 | return
142 | self.upload_rate = int(self.upload_rate*ADJUST_UP)
143 | self.slots = int(sqrt(self.upload_rate*SLOTS_FACTOR))
144 | self.slotsfunc(self.slots)
145 | if DEBUG:
146 | print 'adjust up to '+str(self.upload_rate)
147 | self.lasttime = clock()
148 | self.bytes_sent = 0
149 | self.autoadjustup = UP_DELAY_NEXT
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/RateMeasure.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from clock import clock
5 | try:
6 | True
7 | except:
8 | True = 1
9 | False = 0
10 |
11 | FACTOR = 0.999
12 |
13 | class RateMeasure:
14 | def __init__(self):
15 | self.last = None
16 | self.time = 1.0
17 | self.got = 0.0
18 | self.remaining = None
19 | self.broke = False
20 | self.got_anything = False
21 | self.last_checked = None
22 | self.rate = 0
23 | self.lastten = False
24 |
25 | def data_came_in(self, amount):
26 | if not self.got_anything:
27 | self.got_anything = True
28 | self.last = clock()
29 | return
30 | self.update(amount)
31 |
32 | def data_rejected(self, amount):
33 | pass
34 |
35 | def get_time_left(self, left):
36 | t = clock()
37 | if not self.got_anything:
38 | return None
39 | if t - self.last > 15:
40 | self.update(0)
41 | try:
42 | remaining = left/self.rate
43 | if not self.lastten and remaining <= 10:
44 | self.lastten = True
45 | if self.lastten:
46 | return remaining
47 | delta = max(remaining/20,2)
48 | if self.remaining is None:
49 | self.remaining = remaining
50 | elif abs(self.remaining-remaining) > delta:
51 | self.remaining = remaining
52 | else:
53 | self.remaining -= t - self.last_checked
54 | except ZeroDivisionError:
55 | self.remaining = None
56 | if self.remaining is not None and self.remaining < 0.1:
57 | self.remaining = 0.1
58 | self.last_checked = t
59 | return self.remaining
60 |
61 | def update(self, amount):
62 | t = clock()
63 | t1 = int(t)
64 | l1 = int(self.last)
65 | for i in xrange(l1,t1):
66 | self.time *= FACTOR
67 | self.got *= FACTOR
68 | self.got += amount
69 | if t - self.last < 20:
70 | self.time += t - self.last
71 | self.last = t
72 | try:
73 | self.rate = self.got / self.time
74 | except ZeroDivisionError:
75 | pass
76 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/__init__.py:
--------------------------------------------------------------------------------
1 | product_name = 'BitTornado'
2 | version_short = 'T-0.3.18'
3 |
4 | version = version_short+' ('+product_name+')'
5 | report_email = version_short+'@degreez.net'
6 |
7 | from types import StringType
8 | from hashlib import sha1
9 | from time import time, clock
10 | try:
11 | from os import getpid
12 | except ImportError:
13 | def getpid():
14 | return 1
15 |
16 | mapbase64 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-'
17 |
18 | _idprefix = version_short[0]
19 | for subver in version_short[2:].split('.'):
20 | try:
21 | subver = int(subver)
22 | except:
23 | subver = 0
24 | _idprefix += mapbase64[subver]
25 | _idprefix += ('-' * (6-len(_idprefix)))
26 | _idrandom = [None]
27 |
28 | def resetPeerIDs():
29 | try:
30 | f = open('/dev/urandom','rb')
31 | x = f.read(20)
32 | f.close()
33 | except:
34 | x = ''
35 |
36 | l1 = 0
37 | t = clock()
38 | while t == clock():
39 | l1 += 1
40 | l2 = 0
41 | t = long(time()*100)
42 | while t == long(time()*100):
43 | l2 += 1
44 | l3 = 0
45 | if l2 < 1000:
46 | t = long(time()*10)
47 | while t == long(clock()*10):
48 | l3 += 1
49 | x += ( repr(time()) + '/' + str(time()) + '/'
50 | + str(l1) + '/' + str(l2) + '/' + str(l3) + '/'
51 | + str(getpid()) )
52 |
53 | s = ''
54 | for i in sha1(x).digest()[-11:]:
55 | s += mapbase64[ord(i) & 0x3F]
56 | _idrandom[0] = s
57 |
58 | resetPeerIDs()
59 |
60 | def createPeerID(ins = '---'):
61 | assert type(ins) is StringType
62 | assert len(ins) == 3
63 | return _idprefix + ins + _idrandom[0]
64 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/bitfield.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen, Uoti Urpala, and John Hoffman
2 | # see LICENSE.txt for license information
3 |
4 | try:
5 | True
6 | except:
7 | True = 1
8 | False = 0
9 | bool = lambda x: not not x
10 |
11 | try:
12 | sum([1])
13 | negsum = lambda a: len(a)-sum(a)
14 | except:
15 | negsum = lambda a: reduce(lambda x,y: x+(not y), a, 0)
16 |
17 | def _int_to_booleans(x):
18 | r = []
19 | for i in range(8):
20 | r.append(bool(x & 0x80))
21 | x <<= 1
22 | return tuple(r)
23 |
24 | lookup_table = []
25 | reverse_lookup_table = {}
26 | for i in xrange(256):
27 | x = _int_to_booleans(i)
28 | lookup_table.append(x)
29 | reverse_lookup_table[x] = chr(i)
30 |
31 |
32 | class Bitfield:
33 | def __init__(self, length = None, bitstring = None, copyfrom = None):
34 | if copyfrom is not None:
35 | self.length = copyfrom.length
36 | self.array = copyfrom.array[:]
37 | self.numfalse = copyfrom.numfalse
38 | return
39 | if length is None:
40 | raise ValueError, "length must be provided unless copying from another array"
41 | self.length = length
42 | if bitstring is not None:
43 | extra = len(bitstring) * 8 - length
44 | if extra < 0 or extra >= 8:
45 | raise ValueError
46 | t = lookup_table
47 | r = []
48 | for c in bitstring:
49 | r.extend(t[ord(c)])
50 | if extra > 0:
51 | if r[-extra:] != [0] * extra:
52 | raise ValueError
53 | del r[-extra:]
54 | self.array = r
55 | self.numfalse = negsum(r)
56 | else:
57 | self.array = [False] * length
58 | self.numfalse = length
59 |
60 | def __setitem__(self, index, val):
61 | val = bool(val)
62 | self.numfalse += self.array[index]-val
63 | self.array[index] = val
64 |
65 | def __getitem__(self, index):
66 | return self.array[index]
67 |
68 | def __len__(self):
69 | return self.length
70 |
71 | def tostring(self):
72 | booleans = self.array
73 | t = reverse_lookup_table
74 | s = len(booleans) % 8
75 | r = [ t[tuple(booleans[x:x+8])] for x in xrange(0, len(booleans)-s, 8) ]
76 | if s:
77 | r += t[tuple(booleans[-s:] + ([0] * (8-s)))]
78 | return ''.join(r)
79 |
80 | def complete(self):
81 | return not self.numfalse
82 |
83 |
84 | def test_bitfield():
85 | try:
86 | x = Bitfield(7, 'ab')
87 | assert False
88 | except ValueError:
89 | pass
90 | try:
91 | x = Bitfield(7, 'ab')
92 | assert False
93 | except ValueError:
94 | pass
95 | try:
96 | x = Bitfield(9, 'abc')
97 | assert False
98 | except ValueError:
99 | pass
100 | try:
101 | x = Bitfield(0, 'a')
102 | assert False
103 | except ValueError:
104 | pass
105 | try:
106 | x = Bitfield(1, '')
107 | assert False
108 | except ValueError:
109 | pass
110 | try:
111 | x = Bitfield(7, '')
112 | assert False
113 | except ValueError:
114 | pass
115 | try:
116 | x = Bitfield(8, '')
117 | assert False
118 | except ValueError:
119 | pass
120 | try:
121 | x = Bitfield(9, 'a')
122 | assert False
123 | except ValueError:
124 | pass
125 | try:
126 | x = Bitfield(7, chr(1))
127 | assert False
128 | except ValueError:
129 | pass
130 | try:
131 | x = Bitfield(9, chr(0) + chr(0x40))
132 | assert False
133 | except ValueError:
134 | pass
135 | assert Bitfield(0, '').tostring() == ''
136 | assert Bitfield(1, chr(0x80)).tostring() == chr(0x80)
137 | assert Bitfield(7, chr(0x02)).tostring() == chr(0x02)
138 | assert Bitfield(8, chr(0xFF)).tostring() == chr(0xFF)
139 | assert Bitfield(9, chr(0) + chr(0x80)).tostring() == chr(0) + chr(0x80)
140 | x = Bitfield(1)
141 | assert x.numfalse == 1
142 | x[0] = 1
143 | assert x.numfalse == 0
144 | x[0] = 1
145 | assert x.numfalse == 0
146 | assert x.tostring() == chr(0x80)
147 | x = Bitfield(7)
148 | assert len(x) == 7
149 | x[6] = 1
150 | assert x.numfalse == 6
151 | assert x.tostring() == chr(0x02)
152 | x = Bitfield(8)
153 | x[7] = 1
154 | assert x.tostring() == chr(1)
155 | x = Bitfield(9)
156 | x[8] = 1
157 | assert x.numfalse == 8
158 | assert x.tostring() == chr(0) + chr(0x80)
159 | x = Bitfield(8, chr(0xC4))
160 | assert len(x) == 8
161 | assert x.numfalse == 5
162 | assert x.tostring() == chr(0xC4)
163 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/clock.py:
--------------------------------------------------------------------------------
1 | # Written by John Hoffman
2 | # see LICENSE.txt for license information
3 |
4 | from time import *
5 | import sys
6 |
7 | _MAXFORWARD = 100
8 | _FUDGE = 1
9 |
10 | class RelativeTime:
11 | def __init__(self):
12 | self.time = time()
13 | self.offset = 0
14 |
15 | def get_time(self):
16 | t = time() + self.offset
17 | if t < self.time or t > self.time + _MAXFORWARD:
18 | self.time += _FUDGE
19 | self.offset += self.time - t
20 | return self.time
21 | self.time = t
22 | return t
23 |
24 | if sys.platform != 'win32':
25 | _RTIME = RelativeTime()
26 | def clock():
27 | return _RTIME.get_time()
--------------------------------------------------------------------------------
/src/tornado/BitTornado/inifile.py:
--------------------------------------------------------------------------------
1 | # Written by John Hoffman
2 | # see LICENSE.txt for license information
3 |
4 | '''
5 | reads/writes a Windows-style INI file
6 | format:
7 |
8 | aa = "bb"
9 | cc = 11
10 |
11 | [eee]
12 | ff = "gg"
13 |
14 | decodes to:
15 | d = { '': {'aa':'bb','cc':'11'}, 'eee': {'ff':'gg'} }
16 |
17 | the encoder can also take this as input:
18 |
19 | d = { 'aa': 'bb, 'cc': 11, 'eee': {'ff':'gg'} }
20 |
21 | though it will only decode in the above format. Keywords must be strings.
22 | Values that are strings are written surrounded by quotes, and the decoding
23 | routine automatically strips any.
24 | Booleans are written as integers. Anything else aside from string/int/float
25 | may have unpredictable results.
26 | '''
27 |
28 | from cStringIO import StringIO
29 | from traceback import print_exc
30 | from types import DictType, StringType
31 | try:
32 | from types import BooleanType
33 | except ImportError:
34 | BooleanType = None
35 |
36 | try:
37 | True
38 | except:
39 | True = 1
40 | False = 0
41 |
42 | DEBUG = False
43 |
44 | def ini_write(f, d, comment=''):
45 | try:
46 | a = {'':{}}
47 | for k,v in d.items():
48 | assert type(k) == StringType
49 | k = k.lower()
50 | if type(v) == DictType:
51 | if DEBUG:
52 | print 'new section:' +k
53 | if k:
54 | assert not a.has_key(k)
55 | a[k] = {}
56 | aa = a[k]
57 | for kk,vv in v:
58 | assert type(kk) == StringType
59 | kk = kk.lower()
60 | assert not aa.has_key(kk)
61 | if type(vv) == BooleanType:
62 | vv = int(vv)
63 | if type(vv) == StringType:
64 | vv = '"'+vv+'"'
65 | aa[kk] = str(vv)
66 | if DEBUG:
67 | print 'a['+k+']['+kk+'] = '+str(vv)
68 | else:
69 | aa = a['']
70 | assert not aa.has_key(k)
71 | if type(v) == BooleanType:
72 | v = int(v)
73 | if type(v) == StringType:
74 | v = '"'+v+'"'
75 | aa[k] = str(v)
76 | if DEBUG:
77 | print 'a[\'\']['+k+'] = '+str(v)
78 | r = open(f,'w')
79 | if comment:
80 | for c in comment.split('\n'):
81 | r.write('# '+c+'\n')
82 | r.write('\n')
83 | l = a.keys()
84 | l.sort()
85 | for k in l:
86 | if k:
87 | r.write('\n['+k+']\n')
88 | aa = a[k]
89 | ll = aa.keys()
90 | ll.sort()
91 | for kk in ll:
92 | r.write(kk+' = '+aa[kk]+'\n')
93 | success = True
94 | except:
95 | if DEBUG:
96 | print_exc()
97 | success = False
98 | try:
99 | r.close()
100 | except:
101 | pass
102 | return success
103 |
104 |
105 | if DEBUG:
106 | def errfunc(lineno, line, err):
107 | print '('+str(lineno)+') '+err+': '+line
108 | else:
109 | errfunc = lambda lineno, line, err: None
110 |
111 | def ini_read(f, errfunc = errfunc):
112 | try:
113 | r = open(f,'r')
114 | ll = r.readlines()
115 | d = {}
116 | dd = {'':d}
117 | for i in xrange(len(ll)):
118 | l = ll[i]
119 | l = l.strip()
120 | if not l:
121 | continue
122 | if l[0] == '#':
123 | continue
124 | if l[0] == '[':
125 | if l[-1] != ']':
126 | errfunc(i,l,'syntax error')
127 | continue
128 | l1 = l[1:-1].strip().lower()
129 | if not l1:
130 | errfunc(i,l,'syntax error')
131 | continue
132 | if dd.has_key(l1):
133 | errfunc(i,l,'duplicate section')
134 | d = dd[l1]
135 | continue
136 | d = {}
137 | dd[l1] = d
138 | continue
139 | try:
140 | k,v = l.split('=',1)
141 | except:
142 | try:
143 | k,v = l.split(':',1)
144 | except:
145 | errfunc(i,l,'syntax error')
146 | continue
147 | k = k.strip().lower()
148 | v = v.strip()
149 | if len(v) > 1 and ( (v[0] == '"' and v[-1] == '"') or
150 | (v[0] == "'" and v[-1] == "'") ):
151 | v = v[1:-1]
152 | if not k:
153 | errfunc(i,l,'syntax error')
154 | continue
155 | if d.has_key(k):
156 | errfunc(i,l,'duplicate entry')
157 | continue
158 | d[k] = v
159 | if DEBUG:
160 | print dd
161 | except:
162 | if DEBUG:
163 | print_exc()
164 | dd = None
165 | try:
166 | r.close()
167 | except:
168 | pass
169 | return dd
170 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/parseargs.py:
--------------------------------------------------------------------------------
1 | # Written by Bill Bumgarner and Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from types import *
5 | from cStringIO import StringIO
6 |
7 |
8 | def splitLine(line, COLS=80, indent=10):
9 | indent = " " * indent
10 | width = COLS - (len(indent) + 1)
11 | if indent and width < 15:
12 | width = COLS - 2
13 | indent = " "
14 | s = StringIO()
15 | i = 0
16 | for word in line.split():
17 | if i == 0:
18 | s.write(indent+word)
19 | i = len(word)
20 | continue
21 | if i + len(word) >= width:
22 | s.write('\n'+indent+word)
23 | i = len(word)
24 | continue
25 | s.write(' '+word)
26 | i += len(word) + 1
27 | return s.getvalue()
28 |
29 | def formatDefinitions(options, COLS, presets = {}):
30 | s = StringIO()
31 | for (longname, default, doc) in options:
32 | s.write('--' + longname + ' \n')
33 | default = presets.get(longname, default)
34 | if type(default) in (IntType, LongType):
35 | try:
36 | default = int(default)
37 | except:
38 | pass
39 | if default is not None:
40 | doc += ' (defaults to ' + repr(default) + ')'
41 | s.write(splitLine(doc,COLS,10))
42 | s.write('\n\n')
43 | return s.getvalue()
44 |
45 |
46 | def usage(str):
47 | raise ValueError(str)
48 |
49 |
50 | def defaultargs(options):
51 | l = {}
52 | for (longname, default, doc) in options:
53 | if default is not None:
54 | l[longname] = default
55 | return l
56 |
57 |
58 | def parseargs(argv, options, minargs = None, maxargs = None, presets = {}):
59 | config = {}
60 | longkeyed = {}
61 | for option in options:
62 | longname, default, doc = option
63 | longkeyed[longname] = option
64 | config[longname] = default
65 | for longname in presets.keys(): # presets after defaults but before arguments
66 | config[longname] = presets[longname]
67 | options = []
68 | args = []
69 | pos = 0
70 | while pos < len(argv):
71 | if argv[pos][:2] != '--':
72 | args.append(argv[pos])
73 | pos += 1
74 | else:
75 | if pos == len(argv) - 1:
76 | usage('parameter passed in at end with no value')
77 | key, value = argv[pos][2:], argv[pos+1]
78 | pos += 2
79 | if not longkeyed.has_key(key):
80 | usage('unknown key --' + key)
81 | longname, default, doc = longkeyed[key]
82 | try:
83 | t = type(config[longname])
84 | if t is NoneType or t is StringType:
85 | config[longname] = value
86 | elif t in (IntType, LongType):
87 | config[longname] = long(value)
88 | elif t is FloatType:
89 | config[longname] = float(value)
90 | else:
91 | assert 0
92 | except ValueError, e:
93 | usage('wrong format of --%s - %s' % (key, str(e)))
94 | for key, value in config.items():
95 | if value is None:
96 | usage("Option --%s is required." % key)
97 | if minargs is not None and len(args) < minargs:
98 | usage("Must supply at least %d args." % minargs)
99 | if maxargs is not None and len(args) > maxargs:
100 | usage("Too many args - %d max." % maxargs)
101 | return (config, args)
102 |
103 | def test_parseargs():
104 | assert parseargs(('d', '--a', 'pq', 'e', '--b', '3', '--c', '4.5', 'f'), (('a', 'x', ''), ('b', 1, ''), ('c', 2.3, ''))) == ({'a': 'pq', 'b': 3, 'c': 4.5}, ['d', 'e', 'f'])
105 | assert parseargs([], [('a', 'x', '')]) == ({'a': 'x'}, [])
106 | assert parseargs(['--a', 'x', '--a', 'y'], [('a', '', '')]) == ({'a': 'y'}, [])
107 | try:
108 | parseargs([], [('a', 'x', '')])
109 | except ValueError:
110 | pass
111 | try:
112 | parseargs(['--a', 'x'], [])
113 | except ValueError:
114 | pass
115 | try:
116 | parseargs(['--a'], [('a', 'x', '')])
117 | except ValueError:
118 | pass
119 | try:
120 | parseargs([], [], 1, 2)
121 | except ValueError:
122 | pass
123 | assert parseargs(['x'], [], 1, 2) == ({}, ['x'])
124 | assert parseargs(['x', 'y'], [], 1, 2) == ({}, ['x', 'y'])
125 | try:
126 | parseargs(['x', 'y', 'z'], [], 1, 2)
127 | except ValueError:
128 | pass
129 | try:
130 | parseargs(['--a', '2.0'], [('a', 3, '')])
131 | except ValueError:
132 | pass
133 | try:
134 | parseargs(['--a', 'z'], [('a', 2.1, '')])
135 | except ValueError:
136 | pass
137 |
138 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/parsedir.py:
--------------------------------------------------------------------------------
1 | # Written by John Hoffman and Uoti Urpala
2 | # see LICENSE.txt for license information
3 | from bencode import bencode, bdecode
4 | from BT1.btformats import check_info
5 | from os.path import exists, isfile
6 | from hashlib import sha1
7 | import sys, os
8 |
9 | try:
10 | True
11 | except:
12 | True = 1
13 | False = 0
14 |
15 | NOISY = False
16 |
17 | def _errfunc(x):
18 | print ":: "+x
19 |
20 | def parsedir(directory, parsed, files, blocked,
21 | exts = ['.torrent'], return_metainfo = False, errfunc = _errfunc):
22 | if NOISY:
23 | errfunc('checking dir')
24 | dirs_to_check = [directory]
25 | new_files = {}
26 | new_blocked = {}
27 | torrent_type = {}
28 | while dirs_to_check: # first, recurse directories and gather torrents
29 | directory = dirs_to_check.pop()
30 | newtorrents = False
31 | for f in os.listdir(directory):
32 | newtorrent = None
33 | for ext in exts:
34 | if f.endswith(ext):
35 | newtorrent = ext[1:]
36 | break
37 | if newtorrent:
38 | newtorrents = True
39 | p = os.path.join(directory, f)
40 | new_files[p] = [(os.path.getmtime(p), os.path.getsize(p)), 0]
41 | torrent_type[p] = newtorrent
42 | if not newtorrents:
43 | for f in os.listdir(directory):
44 | p = os.path.join(directory, f)
45 | if os.path.isdir(p):
46 | dirs_to_check.append(p)
47 |
48 | new_parsed = {}
49 | to_add = []
50 | added = {}
51 | removed = {}
52 | # files[path] = [(modification_time, size), hash], hash is 0 if the file
53 | # has not been successfully parsed
54 | for p,v in new_files.items(): # re-add old items and check for changes
55 | oldval = files.get(p)
56 | if not oldval: # new file
57 | to_add.append(p)
58 | continue
59 | h = oldval[1]
60 | if oldval[0] == v[0]: # file is unchanged from last parse
61 | if h:
62 | if blocked.has_key(p): # parseable + blocked means duplicate
63 | to_add.append(p) # other duplicate may have gone away
64 | else:
65 | new_parsed[h] = parsed[h]
66 | new_files[p] = oldval
67 | else:
68 | new_blocked[p] = 1 # same broken unparseable file
69 | continue
70 | if parsed.has_key(h) and not blocked.has_key(p):
71 | if NOISY:
72 | errfunc('removing '+p+' (will re-add)')
73 | removed[h] = parsed[h]
74 | to_add.append(p)
75 |
76 | to_add.sort()
77 | for p in to_add: # then, parse new and changed torrents
78 | new_file = new_files[p]
79 | v,h = new_file
80 | if new_parsed.has_key(h): # duplicate
81 | if not blocked.has_key(p) or files[p][0] != v:
82 | errfunc('**warning** '+
83 | p +' is a duplicate torrent for '+new_parsed[h]['path'])
84 | new_blocked[p] = 1
85 | continue
86 |
87 | if NOISY:
88 | errfunc('adding '+p)
89 | try:
90 | ff = open(p, 'rb')
91 | d = bdecode(ff.read())
92 | check_info(d['info'])
93 | h = sha1(bencode(d['info'])).digest()
94 | new_file[1] = h
95 | if new_parsed.has_key(h):
96 | errfunc('**warning** '+
97 | p +' is a duplicate torrent for '+new_parsed[h]['path'])
98 | new_blocked[p] = 1
99 | continue
100 |
101 | a = {}
102 | a['path'] = p
103 | f = os.path.basename(p)
104 | a['file'] = f
105 | a['type'] = torrent_type[p]
106 | i = d['info']
107 | l = 0
108 | nf = 0
109 | if i.has_key('length'):
110 | l = i.get('length',0)
111 | nf = 1
112 | elif i.has_key('files'):
113 | for li in i['files']:
114 | nf += 1
115 | if li.has_key('length'):
116 | l += li['length']
117 | a['numfiles'] = nf
118 | a['length'] = l
119 | a['name'] = i.get('name', f)
120 | def setkey(k, d = d, a = a):
121 | if d.has_key(k):
122 | a[k] = d[k]
123 | setkey('failure reason')
124 | setkey('warning message')
125 | setkey('announce-list')
126 | if return_metainfo:
127 | a['metainfo'] = d
128 | except:
129 | errfunc('**warning** '+p+' has errors')
130 | new_blocked[p] = 1
131 | continue
132 | try:
133 | ff.close()
134 | except:
135 | pass
136 | if NOISY:
137 | errfunc('... successful')
138 | new_parsed[h] = a
139 | added[h] = a
140 |
141 | for p,v in files.items(): # and finally, mark removed torrents
142 | if not new_files.has_key(p) and not blocked.has_key(p):
143 | if NOISY:
144 | errfunc('removing '+p)
145 | removed[v[1]] = parsed[v[1]]
146 |
147 | if NOISY:
148 | errfunc('done checking')
149 | return (new_parsed, new_files, new_blocked, added, removed)
150 |
151 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/piecebuffer.py:
--------------------------------------------------------------------------------
1 | # Written by John Hoffman
2 | # see LICENSE.txt for license information
3 |
4 | from array import array
5 | from threading import Lock
6 | # import inspect
7 | try:
8 | True
9 | except:
10 | True = 1
11 | False = 0
12 |
13 | DEBUG = False
14 |
15 | class SingleBuffer:
16 | def __init__(self, pool):
17 | self.pool = pool
18 | self.buf = array('c')
19 |
20 | def init(self):
21 | if DEBUG:
22 | print self.count
23 | '''
24 | for x in xrange(6,1,-1):
25 | try:
26 | f = inspect.currentframe(x).f_code
27 | print (f.co_filename,f.co_firstlineno,f.co_name)
28 | del f
29 | except:
30 | pass
31 | print ''
32 | '''
33 | self.length = 0
34 |
35 | def append(self, s):
36 | l = self.length+len(s)
37 | self.buf[self.length:l] = array('c',s)
38 | self.length = l
39 |
40 | def __len__(self):
41 | return self.length
42 |
43 | def __getslice__(self, a, b):
44 | if b > self.length:
45 | b = self.length
46 | if b < 0:
47 | b += self.length
48 | if a == 0 and b == self.length and len(self.buf) == b:
49 | return self.buf # optimization
50 | return self.buf[a:b]
51 |
52 | def getarray(self):
53 | return self.buf[:self.length]
54 |
55 | def release(self):
56 | if DEBUG:
57 | print -self.count
58 | self.pool.release(self)
59 |
60 |
61 | class BufferPool:
62 | def __init__(self):
63 | self.pool = []
64 | self.lock = Lock()
65 | if DEBUG:
66 | self.count = 0
67 |
68 | def new(self):
69 | self.lock.acquire()
70 | if self.pool:
71 | x = self.pool.pop()
72 | else:
73 | x = SingleBuffer(self)
74 | if DEBUG:
75 | self.count += 1
76 | x.count = self.count
77 | x.init()
78 | self.lock.release()
79 | return x
80 |
81 | def release(self, x):
82 | self.pool.append(x)
83 |
84 |
85 | _pool = BufferPool()
86 | PieceBuffer = _pool.new
87 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/selectpoll.py:
--------------------------------------------------------------------------------
1 | # Written by Bram Cohen
2 | # see LICENSE.txt for license information
3 |
4 | from select import select, error
5 | from time import sleep
6 | from types import IntType
7 | from bisect import bisect
8 | POLLIN = 1
9 | POLLOUT = 2
10 | POLLERR = 8
11 | POLLHUP = 16
12 |
13 | class poll:
14 | def __init__(self):
15 | self.rlist = []
16 | self.wlist = []
17 |
18 | def register(self, f, t):
19 | if type(f) != IntType:
20 | f = f.fileno()
21 | if (t & POLLIN):
22 | insert(self.rlist, f)
23 | else:
24 | remove(self.rlist, f)
25 | if (t & POLLOUT):
26 | insert(self.wlist, f)
27 | else:
28 | remove(self.wlist, f)
29 |
30 | def unregister(self, f):
31 | if type(f) != IntType:
32 | f = f.fileno()
33 | remove(self.rlist, f)
34 | remove(self.wlist, f)
35 |
36 | def poll(self, timeout = None):
37 | if self.rlist or self.wlist:
38 | try:
39 | r, w, e = select(self.rlist, self.wlist, [], timeout)
40 | except ValueError:
41 | return None
42 | else:
43 | sleep(timeout)
44 | return []
45 | result = []
46 | for s in r:
47 | result.append((s, POLLIN))
48 | for s in w:
49 | result.append((s, POLLOUT))
50 | return result
51 |
52 | def remove(list, item):
53 | i = bisect(list, item)
54 | if i > 0 and list[i-1] == item:
55 | del list[i-1]
56 |
57 | def insert(list, item):
58 | i = bisect(list, item)
59 | if i == 0 or list[i-1] != item:
60 | list.insert(i, item)
61 |
62 | def test_remove():
63 | x = [2, 4, 6]
64 | remove(x, 2)
65 | assert x == [4, 6]
66 | x = [2, 4, 6]
67 | remove(x, 4)
68 | assert x == [2, 6]
69 | x = [2, 4, 6]
70 | remove(x, 6)
71 | assert x == [2, 4]
72 | x = [2, 4, 6]
73 | remove(x, 5)
74 | assert x == [2, 4, 6]
75 | x = [2, 4, 6]
76 | remove(x, 1)
77 | assert x == [2, 4, 6]
78 | x = [2, 4, 6]
79 | remove(x, 7)
80 | assert x == [2, 4, 6]
81 | x = [2, 4, 6]
82 | remove(x, 5)
83 | assert x == [2, 4, 6]
84 | x = []
85 | remove(x, 3)
86 | assert x == []
87 |
88 | def test_insert():
89 | x = [2, 4]
90 | insert(x, 1)
91 | assert x == [1, 2, 4]
92 | x = [2, 4]
93 | insert(x, 3)
94 | assert x == [2, 3, 4]
95 | x = [2, 4]
96 | insert(x, 5)
97 | assert x == [2, 4, 5]
98 | x = [2, 4]
99 | insert(x, 2)
100 | assert x == [2, 4]
101 | x = [2, 4]
102 | insert(x, 4)
103 | assert x == [2, 4]
104 | x = [2, 3, 4]
105 | insert(x, 3)
106 | assert x == [2, 3, 4]
107 | x = []
108 | insert(x, 3)
109 | assert x == [3]
110 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/torrentlistparse.py:
--------------------------------------------------------------------------------
1 | # Written by John Hoffman
2 | # see LICENSE.txt for license information
3 |
4 | from binascii import unhexlify
5 |
6 | try:
7 | True
8 | except:
9 | True = 1
10 | False = 0
11 |
12 |
13 | # parses a list of torrent hashes, in the format of one hash per line in hex format
14 |
15 | def parsetorrentlist(filename, parsed):
16 | new_parsed = {}
17 | added = {}
18 | removed = parsed
19 | f = open(filename, 'r')
20 | while True:
21 | l = f.readline()
22 | if not l:
23 | break
24 | l = l.strip()
25 | try:
26 | if len(l) != 40:
27 | raise ValueError, 'bad line'
28 | h = unhexlify(l)
29 | except:
30 | print '*** WARNING *** could not parse line in torrent list: '+l
31 | if parsed.has_key(h):
32 | del removed[h]
33 | else:
34 | added[h] = True
35 | new_parsed[h] = True
36 | f.close()
37 | return (new_parsed, added, removed)
38 |
39 |
--------------------------------------------------------------------------------
/src/tornado/BitTornado/zurllib.py:
--------------------------------------------------------------------------------
1 | # Written by John Hoffman
2 | # see LICENSE.txt for license information
3 |
4 | from httplib import HTTPConnection, HTTPSConnection, HTTPException
5 | from urlparse import urlparse
6 | from bencode import bdecode
7 | import socket
8 | from gzip import GzipFile
9 | from StringIO import StringIO
10 | from urllib import quote, unquote
11 | from __init__ import product_name, version_short
12 |
13 | VERSION = product_name+'/'+version_short
14 | MAX_REDIRECTS = 10
15 |
16 |
17 | class btHTTPcon(HTTPConnection): # attempt to add automatic connection timeout
18 | def connect(self):
19 |
20 | # proxy hack
21 | #self.host='127.0.0.1'
22 | #self.port=8888 #privoxy (def 8118)
23 |
24 | HTTPConnection.connect(self)
25 | try:
26 | self.sock.settimeout(30)
27 | except:
28 | pass
29 |
30 | class btHTTPScon(HTTPSConnection): # attempt to add automatic connection timeout
31 | def connect(self):
32 | HTTPSConnection.connect(self)
33 | try:
34 | self.sock.settimeout(30)
35 | except:
36 | pass
37 |
38 | class urlopen:
39 | def __init__(self, url):
40 | self.tries = 0
41 | self._open(url.strip())
42 | self.error_return = None
43 |
44 | def _open(self, url):
45 | self.tries += 1
46 | if self.tries > MAX_REDIRECTS:
47 | raise IOError, ('http error', 500,
48 | "Internal Server Error: Redirect Recursion")
49 | (scheme, netloc, path, pars, query, fragment) = urlparse(url)
50 | if scheme != 'http' and scheme != 'https':
51 | raise IOError, ('url error', 'unknown url type', scheme, url)
52 | url = path
53 | if pars:
54 | url += ';'+pars
55 | if query:
56 | url += '?'+query
57 | # if fragment:
58 | try:
59 | if scheme == 'http':
60 | self.connection = btHTTPcon(netloc)
61 | else:
62 | self.connection = btHTTPScon(netloc)
63 | self.connection.request('GET', url, None,
64 | # proxy hack
65 | #self.connection.request('GET', scheme + '://' + netloc + url, None,
66 | { 'User-Agent': VERSION,
67 | 'Accept-Encoding': 'gzip' } )
68 | self.response = self.connection.getresponse()
69 | except HTTPException, e:
70 | raise IOError, ('http error', str(e))
71 | status = self.response.status
72 | if status in (300,301,302,303,307):
73 | try:
74 | self.connection.close()
75 | except:
76 | pass
77 | self._open(self.response.getheader('Location'))
78 | return
79 | if status != 200:
80 | try:
81 | data = self._read()
82 | d = bdecode(data)
83 | if d.has_key('failure reason'):
84 | self.error_return = data
85 | return
86 | except:
87 | pass
88 | raise IOError, ('http error', status, self.response.reason + ' ' + netloc)
89 |
90 | def read(self):
91 | if self.error_return:
92 | return self.error_return
93 | return self._read()
94 |
95 | def _read(self):
96 | data = self.response.read()
97 | if self.response.getheader('Content-Encoding','').find('gzip') >= 0:
98 | try:
99 | compressed = StringIO(data)
100 | f = GzipFile(fileobj = compressed)
101 | data = f.read()
102 | except:
103 | raise IOError, ('http error', 'got corrupt response')
104 | return data
105 |
106 | def close(self):
107 | self.connection.close()
108 |
--------------------------------------------------------------------------------
/src/tornado/btmakemetafile.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Written by Bram Cohen
4 | # multitracker extensions by John Hoffman
5 | # see LICENSE.txt for license information
6 |
7 | # $Id$
8 |
9 | from BitTornado import PSYCO
10 | if PSYCO.psyco:
11 | try:
12 | import psyco
13 | assert psyco.__version__ >= 0x010100f0
14 | psyco.full()
15 | except:
16 | pass
17 |
18 | from sys import argv, version, exit
19 | from os.path import split
20 | assert version >= '2', "Install Python 2.0 or greater"
21 | from BitTornado.BT1.makemetafile import make_meta_file, defaults, print_announcelist_details
22 | from BitTornado.parseargs import parseargs, formatDefinitions
23 |
24 |
25 | def prog(amount):
26 | print '%.1f%% complete\r' % (amount * 100),
27 |
28 | if len(argv) < 3:
29 | a,b = split(argv[0])
30 | print 'Usage: ' + b + ' [file...] [params...]'
31 | print
32 | print formatDefinitions(defaults, 80)
33 | print_announcelist_details()
34 | print ('')
35 | exit(2)
36 |
37 | try:
38 | config, args = parseargs(argv[1:], defaults, 2, None)
39 | for file in args[1:]:
40 | make_meta_file(file, args[0], config, progress = prog)
41 | except ValueError, e:
42 | print 'error: ' + str(e)
43 | print 'run with no args for parameter explanations'
44 |
--------------------------------------------------------------------------------
/src/tornado/btshowmetainfo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Written by Henry 'Pi' James and Loring Holden
4 | # modified for multitracker display by John Hoffman
5 | # see LICENSE.txt for license information
6 |
7 | # $Id$
8 |
9 | from sys import *
10 | from os.path import *
11 | from hashlib import sha1
12 | from BitTornado.bencode import *
13 |
14 | NAME, EXT = splitext(basename(argv[0]))
15 | VERSION = '20030621'
16 |
17 | print '%s %s - decode BitTorrent metainfo files' % (NAME, VERSION)
18 | print
19 |
20 | if len(argv) == 1:
21 | print '%s file1.torrent file2.torrent file3.torrent ...' % argv[0]
22 | print
23 | exit(2) # common exit code for syntax error
24 |
25 | for metainfo_name in argv[1:]:
26 | metainfo_file = open(metainfo_name, 'rb')
27 | metainfo = bdecode(metainfo_file.read())
28 | # print metainfo
29 | info = metainfo['info']
30 | info_hash = sha1(bencode(info))
31 |
32 | print 'metainfo file.: %s' % basename(metainfo_name)
33 | print 'info hash.....: %s' % info_hash.hexdigest()
34 | piece_length = info['piece length']
35 | if info.has_key('length'):
36 | # let's assume we just have a file
37 | print 'file name.....: %s' % info['name']
38 | file_length = info['length']
39 | name ='file size.....:'
40 | else:
41 | # let's assume we have a directory structure
42 | print 'directory name: %s' % info['name']
43 | print 'files.........: '
44 | file_length = 0;
45 | for file in info['files']:
46 | path = ''
47 | for item in file['path']:
48 | if (path != ''):
49 | path = path + "/"
50 | path = path + item
51 | print ' %s (%d)' % (path, file['length'])
52 | file_length += file['length']
53 | name ='archive size..:'
54 | piece_number, last_piece_length = divmod(file_length, piece_length)
55 | print '%s %i (%i * %i + %i)' \
56 | % (name,file_length, piece_number, piece_length, last_piece_length)
57 | print 'announce url..: %s' % metainfo['announce']
58 | if metainfo.has_key('announce-list'):
59 | list = []
60 | for tier in metainfo['announce-list']:
61 | for tracker in tier:
62 | list+=[tracker,',']
63 | del list[-1]
64 | list+=['|']
65 | del list[-1]
66 | liststring = ''
67 | for i in list:
68 | liststring+=i
69 | print 'announce-list.: %s' % liststring
70 | if metainfo.has_key('httpseeds'):
71 | list = []
72 | for seed in metainfo['httpseeds']:
73 | list += [seed,'|']
74 | del list[-1]
75 | liststring = ''
76 | for i in list:
77 | liststring+=i
78 | print 'http seeds....: %s' % liststring
79 | if metainfo.has_key('comment'):
80 | print 'comment.......: %s' % metainfo['comment']
81 |
--------------------------------------------------------------------------------
/src/uploadify/uploadify.css:
--------------------------------------------------------------------------------
1 | /*
2 | Uploadify
3 | Copyright (c) 2012 Reactive Apps, Ronnie Garcia
4 | Released under the MIT License
5 | */
6 |
7 | .uploadify-queue {
8 | margin-bottom: 1em;
9 | }
10 | .uploadify-queue-item {
11 | background-color: #F5F5F5;
12 | -webkit-border-radius: 3px;
13 | -moz-border-radius: 3px;
14 | border-radius: 3px;
15 | font: 11px Verdana, Geneva, sans-serif;
16 | margin-top: 5px;
17 | max-width: 350px;
18 | padding: 10px;
19 | color:black;
20 | }
21 | .uploadify-error {
22 | background-color: #FDE5DD !important;
23 | }
24 | .uploadify-queue-item .cancel a {
25 | background: url('../img/uploadify-cancel.png') 0 0 no-repeat;
26 | float: right;
27 | height: 16px;
28 | text-indent: -9999px;
29 | width: 16px;
30 | }
31 | .uploadify-queue-item.completed {
32 | background-color: #E5E5E5;
33 | }
34 | .uploadify-progress {
35 | background-color: #E5E5E5;
36 | margin-top: 10px;
37 | width: 100%;
38 | }
39 | .uploadify-progress-bar {
40 | background-color: #0099FF;
41 | height: 3px;
42 | width: 1px;
43 | }
--------------------------------------------------------------------------------
/src/uploadify/uploadify.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/uploadify/uploadify.swf
--------------------------------------------------------------------------------
/src/views/Admin/editUser.php:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Attention ! '.$error.'
7 | ';
8 | }
9 | ?>
10 |
11 |
--------------------------------------------------------------------------------
/src/views/Admin/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 | '.LANG_USER_EDITED.'
14 |
';
15 | }
16 |
17 | if($_GET['alert'] == 'adminUserFail'){
18 | echo '
19 |
20 | '.LANG_YOU_ARE_THE_LAST_ADMIN.'
21 |
';
22 | }
23 |
24 | if($_GET['alert'] == 'newUser'){
25 | echo '
26 |
27 | '.LANG_USER_CREATED.'
28 |
';
29 | }
30 | ?>
31 |
32 |
33 |
34 |
35 |
36 |
37 | |
38 | |
39 | |
40 | |
41 | |
42 |
43 |
44 |
45 | listPaiement() as $key => $rst){
53 | $paiements .= Tools::date_fr_texte($rst['time'])." : ".$rst['nbrJours']." jours [".$rst['price']." euros]";
54 | }*/
55 |
56 | try {
57 | $rpc = new Transmission($user->configRPC());
58 | } catch (Exception $e) {
59 | $rpc = false;
60 | }
61 |
62 |
63 | ($value['admin'] == 1)? $admin = LANG_YES : $admin = LANG_NO;
64 | ($value['admin'] == 1)? $adminBtn = '' : $adminBtn = '';
65 |
66 | echo '
67 | '.$value['login'].' |
68 | '.$value['mail'].' |
69 | '.$value['port'].' |
70 | '.$admin.' |
71 |
72 |
73 | '.$adminBtn;
74 | if (!$rpc)
75 | echo ' ';
76 | else if(!$rpc->isRunning())
77 | echo ' ';
78 | else
79 | echo ' ';
80 | echo '
81 | |
82 |
';
83 | }
84 | ?>
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/src/views/Admin/newUser.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 | Attention ! '.$error.'
9 | ';
10 | }
11 | ?>
12 |
13 |
43 |
--------------------------------------------------------------------------------
/src/views/Compte/index.php:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 | Attention ! '.$error.'
10 | ';
11 | }
12 | ?>
13 |
14 |
15 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/views/Connect/index.php:
--------------------------------------------------------------------------------
1 |
43 |
44 |
--------------------------------------------------------------------------------
/src/views/Downloads/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/Rss/index.php:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | |
14 | Statut |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
...
27 |
28 |
31 |
32 |
--------------------------------------------------------------------------------
/src/views/Torrents/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
...
22 |
23 |
24 |
25 |
32 |
33 |
--------------------------------------------------------------------------------
/src/views/layout/header.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cclleemm/FriendlyTorrent/3ad1adf5357b430a1fe89bfa1bf3a52dd10f8e45/src/views/layout/header.php
--------------------------------------------------------------------------------
/src/views/messagerie/chat.php:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
22 |
class="comment-item">
26 |
30 |
Il n\'y a encore aucun message !';
31 | }
32 | ?>
--------------------------------------------------------------------------------
/src/views/messagerie/index.php:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
11 |
12 | '.LANG_MESSAGE_SENDED.'
13 |
';
14 | }
15 | ?>
16 |
17 |
18 |
32 |
33 |
--------------------------------------------------------------------------------
/src/views/messagerie/message.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
<>
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------