Updated init script.
[dtbartle/bnbt.git] / tracker.cpp
1 /***\r
2 *\r
3 * BNBT Beta 8.0 - A C++ BitTorrent Tracker\r
4 * Copyright (C) 2003-2004 Trevor Hogan\r
5 *\r
6 * CBTT variations (C) 2003-2005 Harold Feit\r
7 *\r
8 * This library is free software; you can redistribute it and/or\r
9 * modify it under the terms of the GNU Lesser General Public\r
10 * License as published by the Free Software Foundation; either\r
11 * version 2.1 of the License, or (at your option) any later version.\r
12 *\r
13 * This library is distributed in the hope that it will be useful,\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
16 * Lesser General Public License for more details.\r
17 *\r
18 * You should have received a copy of the GNU Lesser General Public\r
19 * License along with this library; if not, write to the Free Software\r
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
21 *\r
22 ***/\r
23 \r
24 #ifndef WIN32\r
25  #include <sys/stat.h>\r
26  #include <dirent.h>\r
27 #endif\r
28 \r
29 #include "bnbt.h"\r
30 #include "bnbt_mysql.h"\r
31 #include "atom.h"\r
32 #include "bencode.h"\r
33 #include "config.h"\r
34 #include "md5.h"\r
35 #include "server.h"\r
36 #include "sort.h"\r
37 #include "tracker.h"\r
38 #include "util.h"\r
39 #include "link.h"\r
40 \r
41 map<string, string> gmapMime;\r
42 \r
43 CTracker :: CTracker( )\r
44 {\r
45         m_mtxQueued.Initialize( );\r
46 \r
47         m_strAllowedDir = CFG_GetString( "allowed_dir", string( ) );\r
48         m_strUploadDir = CFG_GetString( "bnbt_upload_dir", string( ) );\r
49         m_strExternalTorrentDir = CFG_GetString( "bnbt_external_torrent_dir", string( ) );\r
50         m_strArchiveDir = CFG_GetString( "bnbt_archive_dir", string( ) );\r
51         m_strFileDir = CFG_GetString( "bnbt_file_dir", string( ) );\r
52 \r
53         if( !m_strAllowedDir.empty( ) && m_strAllowedDir[m_strAllowedDir.size( ) - 1] != PATH_SEP )\r
54                 m_strAllowedDir += PATH_SEP;\r
55 \r
56         if( !m_strUploadDir.empty( ) && m_strUploadDir[m_strUploadDir.size( ) - 1] != PATH_SEP )\r
57                 m_strUploadDir += PATH_SEP;\r
58 \r
59         if( !m_strExternalTorrentDir.empty( ) && m_strExternalTorrentDir[m_strExternalTorrentDir.size( ) - 1] != '/' && m_strExternalTorrentDir[m_strExternalTorrentDir.size( ) - 1] != '=' )\r
60                         m_strExternalTorrentDir += '/';\r
61 \r
62         if( !m_strArchiveDir.empty( ) && m_strArchiveDir[m_strArchiveDir.size( ) - 1] != PATH_SEP )\r
63                 m_strArchiveDir += PATH_SEP;\r
64 \r
65         if( !m_strFileDir.empty( ) && m_strFileDir[m_strFileDir.size( ) - 1] != PATH_SEP )\r
66                 m_strFileDir += PATH_SEP;\r
67 \r
68         m_strDFile = CFG_GetString( "dfile", "dstate.bnbt" );\r
69         m_strCommentsFile = CFG_GetString( "bnbt_comments_file", string( ) );\r
70         m_strTagFile = CFG_GetString( "bnbt_tag_file", "tags.bnbt" );\r
71         m_strUsersFile = CFG_GetString( "bnbt_users_file", "users.bnbt" );\r
72         m_strStaticHeaderFile = CFG_GetString( "bnbt_static_header", string( ) );\r
73         m_strStaticFooterFile = CFG_GetString( "bnbt_static_footer", string( ) );\r
74         m_strRobotsFile = CFG_GetString( "bnbt_robots_txt", string( ) );\r
75         m_strDumpXMLFile = CFG_GetString( "bnbt_dump_xml_file", string( ) );\r
76         m_strImageBarFill = CFG_GetString( "image_bar_fill", string( ) );\r
77         m_strImageBarTrans = CFG_GetString( "image_bar_trans", string( ) );\r
78         m_strForceAnnounceURL = CFG_GetString( "bnbt_force_announce_url", string( ) );\r
79         m_bForceAnnounceOnDL = CFG_GetInt( "bnbt_force_announce_on_download", 0 ) == 0 ? false : true;\r
80         m_iParseAllowedInterval = CFG_GetInt( "parse_allowed_interval", 0 );\r
81         m_iSaveDFileInterval = CFG_GetInt( "save_dfile_interval", 300 );\r
82         m_iDownloaderTimeOutInterval = CFG_GetInt( "downloader_timeout_interval", 2700 );\r
83         m_iRefreshStaticInterval = CFG_GetInt( "bnbt_refresh_static_interval", 10 );\r
84         m_iDumpXMLInterval = CFG_GetInt( "bnbt_dump_xml_interval", 600 );\r
85         m_bDumpXMLPeers = CFG_GetInt( "bnbt_dump_xml_peers", 1 ) == 0 ? false : true;\r
86         m_iMySQLRefreshAllowedInterval = CFG_GetInt( "mysql_refresh_allowed_interval", 300 );\r
87         m_iMySQLRefreshStatsInterval = CFG_GetInt( "mysql_refresh_stats_interval", 600 );\r
88         m_iParseAllowedNext = GetTime( ) + m_iParseAllowedInterval * 60;\r
89         m_iSaveDFileNext = GetTime( ) + m_iSaveDFileInterval;\r
90         m_iPrevTime = 1;\r
91         m_iDownloaderTimeOutNext = GetTime( ) + m_iDownloaderTimeOutInterval;\r
92         m_iRefreshStaticNext = 0;\r
93         m_iDumpXMLNext = GetTime( ) + m_iDumpXMLInterval;\r
94         m_iMySQLRefreshAllowedNext = 0;\r
95         m_iMySQLRefreshStatsNext = 0;\r
96         m_iAnnounceInterval = CFG_GetInt( "announce_interval", 1800 );\r
97         m_iMinRequestInterval = CFG_GetInt( "min_request_interval", 18000 );\r
98         m_iResponseSize = CFG_GetInt( "response_size", 50 );\r
99         m_iMaxGive = CFG_GetInt( "max_give", 200 );\r
100         m_bKeepDead = CFG_GetInt( "keep_dead", 0 ) == 0 ? false : true;\r
101         m_bAllowScrape = CFG_GetInt( "bnbt_allow_scrape", 1 ) == 0 ? false : true;\r
102         m_bCountUniquePeers = CFG_GetInt( "bnbt_count_unique_peers", 1 ) == 0 ? false : true;\r
103         m_bDeleteInvalid = CFG_GetInt( "bnbt_delete_invalid", 0 ) == 0 ? false : true;\r
104         m_bParseOnUpload = CFG_GetInt( "bnbt_parse_on_upload", 1 ) == 0 ? false : true;\r
105         m_iMaxTorrents = CFG_GetInt( "bnbt_max_torrents", 0 );\r
106         m_bShowInfoHash = CFG_GetInt( "bnbt_show_info_hash", 0 ) == 0 ? false : true;\r
107         m_bShowNames = CFG_GetInt( "show_names", 1 ) == 0 ? false : true;\r
108         m_bShowStats = CFG_GetInt( "bnbt_show_stats", 1 ) == 0 ? false : true;\r
109         m_bAllowTorrentDownloads = CFG_GetInt( "bnbt_allow_torrent_downloads", 1 ) == 0 ? false : true;\r
110         m_bAllowComments = CFG_GetInt( "bnbt_allow_comments", 0 ) == 0 ? false : true;\r
111         m_bShowAdded = CFG_GetInt( "bnbt_show_added", 1 ) == 0 ? false : true;\r
112         m_bShowSize = CFG_GetInt( "bnbt_show_size", 1 ) == 0 ? false : true;\r
113         m_bShowNumFiles = CFG_GetInt( "bnbt_show_num_files", 1 ) == 0 ? false : true;\r
114         m_bShowCompleted = CFG_GetInt( "bnbt_show_completed", 0 ) == 0 ? false : true;\r
115         m_bShowTransferred = CFG_GetInt( "bnbt_show_transferred", 0 ) == 0 ? false : true;\r
116         m_bShowMinLeft = CFG_GetInt( "bnbt_show_min_left", 0 ) == 0 ? false : true;\r
117         m_bShowAverageLeft = CFG_GetInt( "bnbt_show_average_left", 0 ) == 0 ? false : true;\r
118         m_bShowMaxiLeft = CFG_GetInt( "bnbt_show_max_left", 0 ) == 0 ? false : true;\r
119         m_bShowLeftAsProgress = CFG_GetInt( "bnbt_show_left_as_progress", 1 ) == 0 ? false : true;\r
120         m_bShowUploader = CFG_GetInt( "bnbt_show_uploader", 0 ) == 0 ? false : true;\r
121         m_bAllowInfoLink = CFG_GetInt( "bnbt_allow_info_link", 0 ) == 0 ? false : true;\r
122         m_bSearch = CFG_GetInt( "bnbt_allow_search", 1 ) == 0 ? false : true;\r
123         m_bSort = CFG_GetInt( "bnbt_allow_sort", 1 ) == 0 ? false : true;\r
124         m_bShowFileComment = CFG_GetInt( "bnbt_show_file_comment", 1 ) == 0 ? false : true;\r
125         m_bShowFileContents = CFG_GetInt( "bnbt_show_file_contents", 0 ) == 0 ? false : true;\r
126         m_bShowShareRatios = CFG_GetInt( "bnbt_show_share_ratios", 1 ) == 0 ? false : true;\r
127         m_bShowAvgDLRate = CFG_GetInt( "bnbt_show_average_dl_rate", 0 ) == 0 ? false : true;\r
128         m_bShowAvgULRate = CFG_GetInt( "bnbt_show_average_ul_rate", 0 ) == 0 ? false : true;\r
129         m_bDeleteOwnTorrents = CFG_GetInt( "bnbt_delete_own_torrents", 1 ) == 0 ? false : true;\r
130         m_bGen = CFG_GetInt( "bnbt_show_gen_time", 1 ) == 0 ? false : true;\r
131         m_bMySQLOverrideDState = CFG_GetInt( "mysql_override_dstate", 0 ) == 0 ? false : true;\r
132         m_iPerPage = CFG_GetInt( "bnbt_per_page", 20 );\r
133         m_iUsersPerPage = CFG_GetInt( "bnbt_users_per_page", 50 );\r
134         m_iMaxPeersDisplay = CFG_GetInt( "bnbt_max_peers_display", 500 );\r
135         m_iGuestAccess = CFG_GetInt( "bnbt_guest_access", ACCESS_VIEW | ACCESS_DL | ACCESS_SIGNUP );\r
136         m_iMemberAccess = CFG_GetInt( "bnbt_member_access", ACCESS_VIEW | ACCESS_DL | ACCESS_COMMENTS | ACCESS_UPLOAD | ACCESS_SIGNUP );\r
137         m_iFileExpires = CFG_GetInt( "bnbt_file_expires", 180 );\r
138         m_iNameLength = CFG_GetInt( "bnbt_name_length", 32 );\r
139         m_iCommentLength = CFG_GetInt( "bnbt_comment_length", 800 );\r
140 \r
141         //DWMod Ban Code\r
142         i_intBanMode = CFG_GetInt( "cbtt_ban_mode", 0 );\r
143         i_intPeerSpoofRestrict = CFG_GetInt( "cbtt_restricted_peer_spoofing", 0 );\r
144         m_strClientBanFile = CFG_GetString( "cbtt_ban_file", "clientbans.bnbt" );\r
145 \r
146         // CBTT IP banning Mode\r
147         m_iIPBanMode = CFG_GetInt( "cbtt_ip_ban_mode", 0 );\r
148         m_strIPBanFile = CFG_GetString( "cbtt_ipban_file", "bans.bnbt" );\r
149 \r
150         // misc CBTT mod functions\r
151         m_iDontCompressTorrent = CFG_GetInt( "cbtt_dont_compress_torrents", 0 );\r
152         m_iRestrictOverflow = CFG_GetInt( "cbtt_restrict_overflow", 0 );\r
153         strOverFlowLimit = CFG_GetString( "cbtt_restrict_overflow_limit", "1099511627776" );\r
154         m_iBlockNATedIP = CFG_GetInt( "cbtt_block_private_ip", 0 );\r
155         m_iTorrentTraderCompatibility = CFG_GetInt( "mysql_cbtt_ttrader_support", 0 );\r
156         m_strIconFile = CFG_GetString( "favicon","");\r
157         m_iBlacklistP2PPorts = CFG_GetInt( "cbtt_blacklist_common_p2p_ports", 0 );\r
158         m_iBlackListServicePorts = CFG_GetInt( "cbtt_blacklist_below_1024" , 0);\r
159         m_bSwapTorrentLink = CFG_GetInt( "bnbt_swap_torrent_link", 0 ) == 0 ? false : true;\r
160         m_strDownloadLinkImage = CFG_GetString("cbtt_download_link_image","");\r
161         m_strStatsLinkImage = CFG_GetString("cbtt_stats_link_image","");\r
162         m_bAllowGlobalScrape = CFG_GetInt( "bnbt_allow_scrape_global", 1 ) == 0 ? false : true;\r
163         m_iRefreshFastCacheInterval = CFG_GetInt( "bnbt_refresh_fast_cache_interval", 30 );\r
164         m_iRefreshFastCacheNext = 0;\r
165         m_bDisableLogon = CFG_GetInt( "cbtt_hide_login_links", 0 ) == 0 ? false : true;\r
166 \r
167         // Announce 'key' support\r
168         m_bAnnounceKeySupport = CFG_GetInt( "bnbt_use_announce_key", 1 ) == 0 ? false : true;\r
169         m_bRequireKeySupport = CFG_GetInt( "bnbt_require_announce_key", 1 ) == 0 ? false : true;\r
170 \r
171         m_bDisableHTML = CFG_GetInt( "bnbt_disable_html", 0 ) == 0 ? false : true;\r
172 \r
173         // Abusive Announce Controls\r
174         m_bEnableAbuseBlock = CFG_GetInt( "cbtt_abuse_detection", 0 ) == 0 ? false : true;\r
175         m_iMinAnnounceInterval = CFG_GetInt( "min_announce_interval", 1500 );\r
176         m_iGlobalAbuseHammer = CFG_GetInt( "cbtt_abuse_hammer_limit", 10 );\r
177         m_iGlobalAbuseLimit = CFG_GetInt( "cbtt_abuse_limit", 5 );\r
178 \r
179 \r
180         // Tracker Custom Title\r
181         gstrTrackerTitle = CFG_GetString( "bnbt_tracker_title", string( ) );\r
182 \r
183     // adopted official tracker config valuse\r
184         m_iLocalOnly = CFG_GetInt( "only_local_override_ip", 0 );\r
185 \r
186         // Private Flag for announce replies\r
187         m_iPrivateTracker = CFG_GetInt( "bnbt_private_tracker_flag", 0 );\r
188 \r
189         // Compact and No_Peer_ID Requirement\r
190         m_bRequireCompact = CFG_GetInt( "cbtt_require_compact", 0 ) == 0 ? false : true;\r
191         m_bRequireNoPeerID = CFG_GetInt( "cbtt_require_no_peer_id", 0 ) == 0 ? false : true;\r
192 \r
193         // Scrape Interval\r
194         m_strSCFile = CFG_GetString( "cbtt_scrape_file", string( ) );\r
195         m_iSaveScrapeInterval = CFG_GetInt( "cbtt_scrape_save_interval", 0 );\r
196         m_iSaveScrapeNext = GetTime( ) + m_iSaveScrapeInterval;\r
197 \r
198         // Page Ranges\r
199         m_iPageRange = CFG_GetInt( "cbtt_page_number_count" , 3 );\r
200 \r
201         // External Command\r
202         m_bEnableExternal = false;\r
203         m_strECommand = CFG_GetString( "cbtt_external_command", string( ) );\r
204         m_iECommandCycle = CFG_GetInt( "cbtt_external_command_interval", 300 );\r
205         m_iNextCommandCycle = GetTime( ) + m_iECommandCycle;\r
206 \r
207         if( m_strECommand != string () )\r
208                 m_bEnableExternal = true;\r
209 \r
210         if( m_iECommandCycle == 0 )\r
211                 m_bEnableExternal = false;\r
212 \r
213         //RSS Support - Code by labarks\r
214         m_strDumpRSSFile = CFG_GetString( "bnbt_rss_file", string( ) );\r
215         m_strDumpRSSFileDir = CFG_GetString( "bnbt_rss_online_dir", string( ) );\r
216         m_strDumpRSSFileURL = CFG_GetString( "bnbt_rss_online_url", string( ) );\r
217         if( !m_strDumpRSSFileURL.empty( ) &&\r
218                 m_strDumpRSSFileURL[m_strDumpRSSFileURL.size( ) - 1] != '/' &&\r
219                 m_strDumpRSSFileURL[m_strDumpRSSFileURL.size( ) - 1] != '=' )\r
220                         m_strDumpRSSFileURL += '/';\r
221         m_iDumpRSSFileMode = CFG_GetInt( "bnbt_rss_file_mode", 0 );\r
222         m_strDumpRSSTitle = CFG_GetString( "bnbt_rss_channel_title", "My BNBT RSS Feed" );\r
223         m_strDumpRSSLink = CFG_GetString( "bnbt_rss_channel_link", "http://localhost:26213/" );\r
224         m_strDumpRSSDescription = CFG_GetString( "bnbt_rss_channel_description", "BitTorrent RSS Feed for BNBT" );\r
225         m_iDumpRSS_TTL = CFG_GetInt( "bnbt_rss_channel_ttl", 60 );\r
226         m_strDumpRSSLanguage = CFG_GetString( "bnbt_rss_channel_language", "en-us" );\r
227         m_strDumpRSSImageURL = CFG_GetString( "bnbt_rss_channel_image_url", string( ) );\r
228         m_iDumpRSSImageWidth = CFG_GetInt( "bnbt_rss_channel_image_width", 0 );\r
229         m_iDumpRSSImageHeight = CFG_GetInt( "bnbt_rss_channel_image_height", 0 );\r
230         m_strDumpRSSCopyright = CFG_GetString( "bnbt_rss_channel_copyright", string( ) );\r
231         m_iDumpRSSLimit = CFG_GetInt( "bnbt_rss_limit", 25 );\r
232         m_iDumpRSSInterval = CFG_GetInt( "bnbt_rss_interval", 30 );\r
233         //end addition\r
234 \r
235         // tags\r
236 \r
237         int iTag = 1;\r
238 \r
239         string strName = "bnbt_tag" + CAtomInt( iTag ).toString( );\r
240         string strTag;\r
241 \r
242         while( !( strTag = CFG_GetString( strName, string( ) ) ).empty( ) )\r
243         {\r
244                 string :: size_type iSplit = strTag.find( "|" );\r
245 \r
246                 strName = "bnbt_tag" + CAtomInt( ++iTag ).toString( );\r
247 \r
248                 if( iSplit == string :: npos )\r
249                         m_vecTags.push_back( pair<string, string>( strTag, string( ) ) );\r
250                 else\r
251                         m_vecTags.push_back( pair<string, string>( strTag.substr( 0, iSplit ), strTag.substr( iSplit + 1 ) ) );\r
252         }\r
253 \r
254         m_pAllowed = NULL;\r
255         m_pTimeDicti = new CAtomDicti( );\r
256         m_pCached = new CAtomDicti( );\r
257         m_pIPs = new CAtomDicti( );\r
258 \r
259         // decode dfile\r
260 \r
261         CAtom *pState = DecodeFile( m_strDFile.c_str( ) );\r
262 \r
263         if( pState && pState->isDicti( ) )\r
264         {\r
265                 m_pState = (CAtomDicti *)pState;\r
266 \r
267                 // Get Peerlist\r
268                 if( m_pState->getItem( "peers" ) )\r
269                 {\r
270                         CAtom *pDFile = m_pState->getItem( "peers" );\r
271 \r
272                         if( pDFile && pDFile->isDicti( ) )\r
273                                 m_pDFile = (CAtomDicti *)pDFile;\r
274                         else\r
275                         {\r
276                                 m_pDFile = new CAtomDicti ( );\r
277                 m_pState->setItem( "peers", m_pDFile );\r
278                         }\r
279                 }\r
280                 else\r
281                 {\r
282                         m_pDFile = new CAtomDicti( );\r
283                         m_pState->setItem( "peers", m_pDFile );\r
284                 }\r
285 \r
286                 // Get Completed Totals\r
287                 if( m_pState->getItem( "completed" ) )\r
288                 {\r
289                         CAtom *pCompleted = m_pState->getItem( "completed" );\r
290 \r
291                         if( pCompleted && pCompleted->isDicti( ) )\r
292                                 m_pCompleted = (CAtomDicti *)pCompleted;\r
293                         else\r
294                         {\r
295                                 m_pCompleted = new CAtomDicti( );\r
296                 m_pState->setItem( "completed", m_pCompleted );\r
297                         }\r
298                 }\r
299                 else\r
300                 {\r
301                         m_pCompleted = new CAtomDicti( );\r
302                         m_pState->setItem( "completed", m_pCompleted );\r
303         }\r
304 \r
305                 // Get IP Abuse Logs\r
306                 if( m_bEnableAbuseBlock ){\r
307             if( m_pState->getItem( "abuselog" ) )\r
308                         {\r
309                                 CAtom *pAbuse = m_pState->getItem( "abuselog" );\r
310 \r
311                                 if( pAbuse && pAbuse->isDicti( ) )\r
312                                         m_pAbuse = (CAtomDicti *)pAbuse;\r
313                                 else\r
314                                 {\r
315                                         m_pAbuse = new CAtomDicti( );\r
316                                 m_pState->setItem( "abuselog", m_pAbuse );\r
317                                 }\r
318                         }\r
319                         else\r
320                         {\r
321                                 m_pAbuse = new CAtomDicti( );\r
322                                 m_pState->setItem( "abuselog", m_pAbuse );\r
323                         }\r
324                 }\r
325                 else\r
326                 {\r
327                         m_pAbuse = NULL;\r
328                         delete m_pAbuse;\r
329                 }\r
330 \r
331                 // populate time dicti\r
332 \r
333                 map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
334 \r
335                 for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); i++ )\r
336                 {\r
337                         CAtomDicti *pTS = new CAtomDicti( );\r
338 \r
339                         if( (*i).second->isDicti( ) )\r
340                         {\r
341                                 CAtomDicti *pPeersDicti = (CAtomDicti *)(*i).second;\r
342 \r
343                                 map<string, CAtom *> *pmapPeersDicti = pPeersDicti->getValuePtr( );\r
344 \r
345                                 for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); j++ )\r
346                                         pTS->setItem( (*j).first, new CAtomLong( 0 ) );\r
347 \r
348                                 // reset connected times\r
349 \r
350                                 for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); j++ )\r
351                                 {\r
352                                         if( (*j).second->isDicti( ) )\r
353                                         {\r
354                                                 CAtomDicti *pPeerDicti = (CAtomDicti *)(*j).second;\r
355 \r
356                                                 if( pPeerDicti )\r
357                                                         pPeerDicti->setItem( "connected", new CAtomLong( 0 ) );\r
358                                         }\r
359                                 }\r
360                         }\r
361 \r
362                         m_pTimeDicti->setItem( (*i).first, pTS );\r
363                 }\r
364         }\r
365         else\r
366         {\r
367                 if( pState )\r
368                         delete pState;\r
369 \r
370                 m_pState = new CAtomDicti( );\r
371                 m_pDFile = new CAtomDicti( );\r
372                 m_pCompleted = new CAtomDicti( );\r
373                 m_pAbuse = new CAtomDicti( );\r
374 \r
375                 m_pState->setItem( "peers", m_pDFile );\r
376                 m_pState->setItem( "completed", m_pCompleted );\r
377                 m_pState->setItem( "abuselog", m_pAbuse );\r
378         }\r
379 \r
380         // decode comments file\r
381 \r
382         if( m_strCommentsFile.empty( ) )\r
383                 m_pComments = new CAtomDicti( );\r
384         else\r
385         {\r
386                 CAtom *pComments = DecodeFile( m_strCommentsFile.c_str( ) );\r
387 \r
388                 if( pComments && pComments->isDicti( ) )\r
389                         m_pComments = (CAtomDicti *)pComments;\r
390                 else\r
391                 {\r
392                         if( pComments )\r
393                                 delete pComments;\r
394 \r
395                         m_pComments = new CAtomDicti( );\r
396                 }\r
397         }\r
398 \r
399         // decode tag file\r
400 \r
401         if( m_strTagFile.empty( ) )\r
402                 m_pTags = new CAtomDicti( );\r
403         else\r
404         {\r
405                 CAtom *pTags = DecodeFile( m_strTagFile.c_str( ) );\r
406 \r
407                 if( pTags && pTags->isDicti( ) )\r
408                         m_pTags = (CAtomDicti *)pTags;\r
409                 else\r
410                 {\r
411                         if( pTags )\r
412                                 delete pTags;\r
413 \r
414                         m_pTags = new CAtomDicti( );\r
415                 }\r
416         }\r
417 \r
418         // decode users file\r
419 \r
420         if( m_strUsersFile.empty( ) )\r
421                 m_pUsers = new CAtomDicti( );\r
422         else\r
423         {\r
424                 CAtom *pUsers = DecodeFile( m_strUsersFile.c_str( ) );\r
425 \r
426                 if( pUsers && pUsers->isDicti( ) )\r
427                         m_pUsers = (CAtomDicti *)pUsers;\r
428                 else\r
429                 {\r
430                         if( pUsers )\r
431                                 delete pUsers;\r
432 \r
433                         m_pUsers = new CAtomDicti( );\r
434                 }\r
435         }\r
436 \r
437         if( m_bCountUniquePeers )\r
438                 CountUniquePeers( );\r
439 \r
440         m_pFastCache = new CAtomDicti( );\r
441 \r
442         // parse allowed dir\r
443 \r
444         if( !m_strAllowedDir.empty( ) )\r
445                 parseTorrents( m_strAllowedDir.c_str( ) );\r
446 \r
447 \r
448         // DWKMod Ban Stuff\r
449         m_pClientBannedList = new CAtomList();\r
450         parseClientBanList();\r
451         UTIL_LogPrint( "Client Banlist parse called\n" );\r
452 \r
453         m_pIPBannedList = new CAtomList();\r
454         parseIPBanList();\r
455         UTIL_LogPrint( "IP Banlist parse called\n" );\r
456         \r
457 \r
458         // mime\r
459 \r
460         gmapMime[".hqx"]        = "application/mac-binhex40";\r
461         gmapMime[".exe"]        = "application/octet-stream";\r
462         gmapMime[".pdf"]        = "application/pdf";\r
463         gmapMime[".gtar"]       = "application/x-gtar";\r
464         gmapMime[".gz"]         = "application/x-gzip";\r
465         gmapMime[".js"]         = "application/x-javascript";\r
466         gmapMime[".swf"]        = "application/x-shockwave-flash";\r
467         gmapMime[".sit"]        = "application/x-stuffit";\r
468         gmapMime[".tar"]        = "application/x-tar";\r
469         gmapMime[".zip"]        = "application/zip";\r
470         gmapMime[".bmp"]        = "image/bmp";\r
471         gmapMime[".gif"]        = "image/gif";\r
472         gmapMime[".jpg"]        = "image/jpeg";\r
473         gmapMime[".jpeg"]       = "image/jpeg";\r
474         gmapMime[".jpe"]        = "image/jpeg";\r
475         gmapMime[".png"]        = "image/png";\r
476         gmapMime[".tiff"]       = "image/tiff";\r
477         gmapMime[".tif"]        = "image/tiff";\r
478         gmapMime[".css"]        = "text/css";\r
479         gmapMime[".html"]       = "text/html";\r
480         gmapMime[".htm"]        = "text/html";\r
481         gmapMime[".txt"]        = "text/plain";\r
482         gmapMime[".rtf"]        = "text/rtf";\r
483         gmapMime[".xml"]        = "application/xml";\r
484         //addition by labarks\r
485         gmapMime[".rss"]        = "application/rss+xml";\r
486         gmapMime[".torrent"] = "application/x-bittorrent";\r
487 \r
488         runSaveRSS( );\r
489         //end addition\r
490 }\r
491 \r
492 CTracker :: ~CTracker( )\r
493 {\r
494         saveDFile();\r
495         saveComments();\r
496         saveTags();\r
497         delete m_pAllowed;\r
498         delete m_pState;\r
499         delete m_pTimeDicti;\r
500         delete m_pCached;\r
501         delete m_pComments;\r
502         delete m_pTags;\r
503         delete m_pUsers;\r
504         delete m_pIPs;\r
505         delete m_pFastCache;\r
506 \r
507         m_pAllowed = NULL;\r
508         m_pState = NULL;\r
509         m_pDFile = NULL;\r
510         m_pCompleted = NULL;\r
511         m_pAbuse = NULL;\r
512         m_pTimeDicti = NULL;\r
513         m_pCached = NULL;\r
514         m_pComments = NULL;\r
515         m_pTags = NULL;\r
516         m_pUsers = NULL;\r
517         m_pIPs = NULL;\r
518         m_pFastCache = NULL;\r
519 \r
520         m_mtxQueued.Destroy( );\r
521 }\r
522 \r
523 void CTracker :: saveDFile( )\r
524 {\r
525         string strData = Encode( m_pState );\r
526 \r
527         FILE *pFile = NULL;\r
528 \r
529         if( ( pFile = fopen( m_strDFile.c_str( ), "wb" ) ) == NULL )\r
530         {\r
531                 UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", m_strDFile.c_str( ) );\r
532 \r
533                 return;\r
534         }\r
535 \r
536         fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
537         fclose( pFile );\r
538 }\r
539 \r
540 void CTracker :: saveScrapeFile( )\r
541 {\r
542         CAtomDicti *pScrape = new CAtomDicti( );\r
543         CAtomDicti *pFiles = new CAtomDicti( );\r
544 \r
545         pScrape->setItem( "files", pFiles );\r
546 \r
547 \r
548         pScrape->setItem("version", new CAtomString( string( BNBT_VER ) ) );\r
549         CAtomDicti *pFeatures = new CAtomDicti( );\r
550         pFeatures->setItem("linking", new CAtomString( "ka" ) );\r
551         pFeatures->setItem("banning", new CAtomString( "cih" ) );\r
552         CAtomList *pStatistics = new CAtomList();\r
553         if( m_strDumpXMLFile != string() )\r
554                 pStatistics->addItem( new CAtomString( "XML Dump" ));\r
555     pScrape->setItem("features", pFeatures);\r
556 \r
557 #ifdef BNBT_MYSQL\r
558         pStatistics->addItem( new CAtomString( "MySQL" ));\r
559         if ( m_bMySQLOverrideDState == true )\r
560                 pScrape->setItem("database", new CAtomString( "MySQL Overriding DState" ) );\r
561         else\r
562         {\r
563                 pScrape->setItem("database", new CAtomString( "MySQL Statistics Dump with Flatfile dstate" ) );\r
564                 pStatistics->addItem( new CAtomString( "Dstate Dfile" ));\r
565         }\r
566 #else\r
567         pScrape->setItem("database", new CAtomString( "Flatfile Dstate" ) );\r
568         pStatistics->addItem( new CAtomString( "Dstate Dfile" ));\r
569 #endif\r
570         if( m_iSaveScrapeInterval > 0 )\r
571                 pStatistics->addItem( new CAtomString( "Timed scrape save" ) );\r
572 \r
573         pFeatures->setItem("statistics", pStatistics);\r
574 \r
575         if( gpLinkServer )\r
576         {\r
577                 long m_lTrackers;\r
578                 long m_lInactiveTrackers;\r
579                 m_lTrackers = 0;\r
580                 m_lInactiveTrackers = 0;\r
581                 gpLinkServer->m_mtxLinks.Claim( );\r
582                 for( vector<CLinkClient *> :: iterator i = gpLinkServer->m_vecLinks.begin( ); i != gpLinkServer->m_vecLinks.end( ); i++ )\r
583                 {\r
584                         if( (*i)->m_bActive )\r
585                                 m_lTrackers++;\r
586                         else\r
587                                 m_lInactiveTrackers++;\r
588                 }\r
589                 gpLinkServer->m_mtxLinks.Release( );\r
590                 CAtomDicti *pTrackers = new CAtomDicti( );\r
591                 if( m_lTrackers > 0 )\r
592                         pTrackers->setItem("active", new CAtomLong(m_lTrackers) );\r
593                 if( m_lInactiveTrackers > 0 )\r
594             pTrackers->setItem("inactive", new CAtomLong(m_lInactiveTrackers) );\r
595                 if( m_lTrackers + m_lInactiveTrackers > 0 )\r
596             pTrackers->setItem("total", new CAtomLong(m_lTrackers + m_lInactiveTrackers) );\r
597                 pScrape->setItem("links", pTrackers);\r
598         }\r
599         if( gpLink )\r
600         {\r
601                 CAtomDicti *pTrackers = new CAtomDicti( );\r
602                 pTrackers->setItem("active", new CAtomLong( 1 ) );\r
603                 pTrackers->setItem("total", new CAtomLong( 1 ) );\r
604                 pScrape->setItem("links", pTrackers);\r
605         }\r
606 \r
607         if( m_pDFile )\r
608         {\r
609                 pScrape->setItem("filecount", new CAtomLong( m_pDFile->getValuePtr( )->size( ) ) );\r
610                 unsigned long iPeers = 0;\r
611 \r
612                 map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
613 \r
614                 for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); i++ )\r
615                 {\r
616                         if( (*i).second->isDicti( ) )\r
617                                 iPeers += ( (CAtomDicti *)(*i).second )->getValuePtr( )->size( );\r
618                 }\r
619 \r
620                 pScrape->setItem("peers", new CAtomLong( iPeers ) );\r
621 \r
622                 if( m_bCountUniquePeers )\r
623                         pScrape->setItem("unique", new CAtomLong( m_pIPs->getValuePtr( )->size( ) ) );\r
624         }\r
625 \r
626 #ifdef BNBT_MYSQL\r
627    if( m_bMySQLOverrideDState && m_iMySQLRefreshStatsInterval > 0 )\r
628    {\r
629       // Modified by =Xotic=\r
630       string strQuery;\r
631       strQuery = "SELECT bseeders,bleechers,bcompleted,bhash FROM torrents";\r
632 \r
633       CMySQLQuery *pQuery = new CMySQLQuery( strQuery );\r
634 \r
635       vector<string> vecQuery;\r
636          // full\r
637       while( ( vecQuery = pQuery->nextRow( ) ).size( ) == 4 )\r
638       {\r
639             CAtomDicti *pHuh = new CAtomDicti( );\r
640 \r
641             pHuh->setItem( "complete", new CAtomInt( atoi( vecQuery[0].c_str( ) ) ) );\r
642             pHuh->setItem( "incomplete", new CAtomInt( atoi( vecQuery[1].c_str( ) ) ) );\r
643             pHuh->setItem( "downloaded", new CAtomInt( atoi( vecQuery[2].c_str( ) ) ) );\r
644 \r
645             if( m_pAllowed )\r
646             {\r
647                CAtom *pList = m_pAllowed->getItem( vecQuery[3] );\r
648 \r
649                if( pList && dynamic_cast<CAtomList *>( pList ) )\r
650                {\r
651                   vector<CAtom *> vecTorrent = dynamic_cast<CAtomList *>( pList )->getValue( );\r
652 \r
653                   if( vecTorrent.size( ) == 6 )\r
654                   {\r
655                      CAtom *pName = vecTorrent[1];\r
656 \r
657                      if( pName )\r
658                         pHuh->setItem( "name", new CAtomString( pName->toString( ) ) );\r
659                   }\r
660                }\r
661             }\r
662 \r
663             pFiles->setItem( vecQuery[3], pHuh );\r
664                 delete pQuery;\r
665                 string p_sOutput;\r
666                 FILE *pFile = NULL;\r
667                 string strData = Encode( pScrape );\r
668                 if( ( pFile = fopen( m_strSCFile.c_str( ), "wb" ) ) == NULL )\r
669                 {\r
670                         UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", m_strSCFile.c_str( ) );\r
671                         return;\r
672                 }\r
673                 fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
674                 fclose( pFile );\r
675         }\r
676         delete pScrape;\r
677         return;\r
678    }\r
679 #endif\r
680         if( m_pDFile )\r
681         {\r
682                 map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
683 \r
684                 for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); i++ )\r
685                 {\r
686                         if( (*i).second->isDicti( ) )\r
687                         {\r
688                                 CAtomDicti *pHuh = new CAtomDicti( );\r
689 \r
690                                 map<string, CAtom *> *pmapPeersDicti = ( (CAtomDicti *)(*i).second )->getValuePtr( );\r
691 \r
692                                 unsigned long iSeeders = 0;\r
693                                 unsigned long iLeechers = 0;\r
694 \r
695                                 for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); j++ )\r
696                                 {\r
697                                         if( (*j).second->isDicti( ) )\r
698                                         {\r
699                                                 CAtom *pLeft = ( (CAtomDicti *)(*j).second )->getItem( "left" );\r
700 \r
701                                                 if( pLeft && pLeft->isLong( ) )\r
702                                                 {\r
703                                                         if( ( (CAtomLong *)pLeft )->getValue( ) == 0 )\r
704                                                                 iSeeders++;\r
705                                                         else\r
706                                                                 iLeechers++;\r
707                                                 }\r
708                                         }\r
709                                 }\r
710 \r
711                                 pHuh->setItem( "complete", new CAtomInt( iSeeders ) );\r
712                                 pHuh->setItem( "incomplete", new CAtomInt( iLeechers ) );\r
713 \r
714                                 if( m_pAllowed )\r
715                                 {\r
716                                         CAtom *pList = m_pAllowed->getItem( (*i).first );\r
717 \r
718                                         if( pList && pList->isList( ) )\r
719                                         {\r
720                                                 vector<CAtom *> vecTorrent = ( (CAtomList *)pList )->getValue( );\r
721 \r
722                                                 if( vecTorrent.size( ) == 6 )\r
723                                                 {\r
724                                                         CAtom *pName = vecTorrent[1];\r
725 \r
726                                                         if( pName )\r
727                                                                 pHuh->setItem( "name", new CAtomString( pName->toString( ) ) );\r
728                                                 }\r
729                                         }\r
730                                 }\r
731 \r
732                                 if( m_pCompleted )\r
733                                 {\r
734                                         CAtom *pCompleted = m_pCompleted->getItem( (*i).first );\r
735 \r
736                                         if( pCompleted && pCompleted->isLong( ) )\r
737                                                 pHuh->setItem( "downloaded", new CAtomLong( ( (CAtomLong *)pCompleted )->getValue( ) ) );\r
738                                 }\r
739 \r
740                                 pFiles->setItem( (*i).first, pHuh );\r
741                                 }\r
742                         }\r
743                 FILE *pFile = NULL;\r
744                 string strData = Encode( pScrape );\r
745                 if( ( pFile = fopen( m_strSCFile.c_str( ), "wb" ) ) == NULL )\r
746                 {\r
747                         UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", m_strSCFile.c_str( ) );\r
748                         return;\r
749                 }\r
750                 fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
751                 fclose( pFile );\r
752                 delete pScrape;\r
753                 return;\r
754         }\r
755 }\r
756 \r
757 void CTracker :: saveComments( )\r
758 {\r
759         if( m_strCommentsFile.empty( ) )\r
760                 return;\r
761 \r
762         string strData = Encode( m_pComments );\r
763 \r
764         FILE *pFile = NULL;\r
765 \r
766         if( ( pFile = fopen( m_strCommentsFile.c_str( ), "wb" ) ) == NULL )\r
767         {\r
768                 UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", m_strCommentsFile.c_str( ) );\r
769 \r
770                 return;\r
771         }\r
772 \r
773         fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
774         fclose( pFile );\r
775 }\r
776 \r
777 void CTracker :: saveTags( )\r
778 {\r
779         string strData = Encode( m_pTags );\r
780 \r
781         FILE *pFile = NULL;\r
782 \r
783         if( ( pFile = fopen( m_strTagFile.c_str( ), "wb" ) ) == NULL )\r
784         {\r
785                 UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", m_strTagFile.c_str( ) );\r
786 \r
787                 return;\r
788         }\r
789 \r
790         fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
791         fclose( pFile );\r
792 }\r
793 \r
794 void CTracker :: saveUsers( )\r
795 {\r
796         string strData = Encode( m_pUsers );\r
797 \r
798         FILE *pFile = NULL;\r
799 \r
800         if( ( pFile = fopen( m_strUsersFile.c_str( ), "wb" ) ) == NULL )\r
801         {\r
802                 UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", m_strUsersFile.c_str( ) );\r
803 \r
804                 return;\r
805         }\r
806 \r
807         fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
808         fclose( pFile );\r
809 }\r
810 \r
811 void CTracker :: saveXML( )\r
812 {\r
813         string strData;\r
814         string tmpData;\r
815         int iDL;\r
816         int iComplete;\r
817         int iCompleted;\r
818 \r
819 //addition by labarks\r
820         strData += "<?xml version=\"1.0\" encoding=\"" + gstrCharSet + "\"?>\n";\r
821         /* Original Source Code:\r
822         strData += "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";\r
823         */\r
824 \r
825         strData += "<torrents>\n";\r
826 \r
827         if( m_pDFile )\r
828         {\r
829                 map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
830 \r
831                 for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); i++ )\r
832                 {\r
833                         strData += "<torrent hash=\"";\r
834                         strData += UTIL_HashToString( (*i).first );\r
835                         strData += "\"";\r
836 \r
837                         if( m_pAllowed )\r
838                         {\r
839                                 CAtom *pList = m_pAllowed->getItem( (*i).first );\r
840 \r
841                                 if( pList && pList->isList( ) )\r
842                                 {\r
843                                         vector<CAtom *> vecTorrent = ( (CAtomList *)pList )->getValue( );\r
844 \r
845                                         if( vecTorrent.size( ) == 6 )\r
846                                         {\r
847                                                 CAtom *pFileName = vecTorrent[0];\r
848                                                 CAtom *pName = vecTorrent[1];\r
849                                                 CAtom *pAdded = vecTorrent[2];\r
850                                                 CAtom *pSize = vecTorrent[3];\r
851                                                 CAtom *pFiles = vecTorrent[4];\r
852 \r
853                                                 if( pFileName )\r
854                                                         strData += " filename=\"" + UTIL_RemoveHTML( pFileName->toString( ) ) + "\"";\r
855 \r
856                                                 if( pName )\r
857                                                         strData += " name=\"" + UTIL_RemoveHTML( pName->toString( ) ) + "\"";\r
858 \r
859                                                 if( pAdded )\r
860                                                         strData += " added=\"" + pAdded->toString( ) + "\"";\r
861 \r
862                                                 if( pSize )\r
863                                                         strData += " size=\"" + pSize->toString( ) + "\"";\r
864 \r
865                                                 if( pFiles )\r
866                                                         strData += " files=\"" + pFiles->toString( ) + "\"";\r
867                                         }\r
868                                 }\r
869                         }\r
870 \r
871                         iCompleted = 0;\r
872 \r
873                         if( m_pCompleted )\r
874                         {\r
875                                 CAtom *pCompleted = m_pCompleted->getItem( (*i).first );\r
876 \r
877                                 if( pCompleted && pCompleted->isLong( ) )\r
878                                         iCompleted = (int)( (CAtomLong *)pCompleted )->getValue( );\r
879                         }\r
880                         strData += " completed=\"" + CAtomInt( iCompleted ).toString( ) + "\"";\r
881 \r
882                         if( m_pTags )\r
883                         {\r
884                                 CAtom *pDicti = m_pTags->getItem( (*i).first );\r
885 \r
886                                 if( pDicti && pDicti->isDicti( ) )\r
887                                 {\r
888                                         CAtom *pTag = ( (CAtomDicti *)pDicti )->getItem( "tag" );\r
889                                         CAtom *pName = ( (CAtomDicti *)pDicti )->getItem( "name" );\r
890                                         CAtom *pUploader = ( (CAtomDicti *)pDicti )->getItem( "uploader" );\r
891 \r
892                                         if( pTag )\r
893                                                 strData += " tag=\"" + UTIL_RemoveHTML( pTag->toString( ) ) + "\"";\r
894 \r
895                                         if( pName )\r
896                                                 strData += " uploadname=\"" + UTIL_RemoveHTML( pName->toString( ) ) + "\"";\r
897 \r
898                                         if( pUploader )\r
899                                                 strData += " uploader=\"" + UTIL_RemoveHTML( pUploader->toString( ) ) + "\"";\r
900                                 }\r
901                         }\r
902 \r
903                         tmpData = "";\r
904                         iDL = 0;\r
905                         iComplete = 0;\r
906 \r
907                         if( (*i).second->isDicti( ) )\r
908                         {\r
909                                 map<string, CAtom *> *pmapPeersDicti = ( (CAtomDicti *)(*i).second )->getValuePtr( );\r
910 \r
911                                 if( pmapPeersDicti->empty( ) )\r
912                                         tmpData += "<peers />\n";\r
913                                 else\r
914                                 {\r
915                                         tmpData += "<peers>\n";\r
916 \r
917                                         for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); j++ )\r
918                                         {\r
919                                                 if( (*j).second->isDicti( ) )\r
920                                                 {\r
921                                                         CAtomDicti *pPeerDicti = (CAtomDicti *)(*j).second;\r
922 \r
923                                                         CAtom *pIP = pPeerDicti->getItem( "ip" );\r
924                                                         CAtom *pUpped = pPeerDicti->getItem( "uploaded" );\r
925                                                         CAtom *pDowned = pPeerDicti->getItem( "downloaded" );\r
926                                                         CAtom *pLef = pPeerDicti->getItem( "left" );\r
927                                                         CAtom *pConn = pPeerDicti->getItem( "connected" );\r
928 \r
929                                                         if( ( (CAtomLong *)pLef )->getValue( ) == 0 )\r
930                                                                 iComplete++;\r
931                                                         else\r
932                                                                 iDL++;\r
933 \r
934                                                         tmpData += "<peer id=\"";\r
935                                                         tmpData += UTIL_HashToString( (*j).first );\r
936                                                         tmpData += "\"";\r
937 \r
938                                                         if( pIP )\r
939                                                                 tmpData += " ip=\"" + pIP->toString( ) + "\"";\r
940 \r
941                                                         if( pUpped )\r
942                                                                 tmpData += " uploaded=\"" + pUpped->toString( ) + "\"";\r
943 \r
944                                                         if( pDowned )\r
945                                                                 tmpData += " downloaded=\"" + pDowned->toString( ) + "\"";\r
946 \r
947                                                         if( pLef && pLef->isLong( ) )\r
948                                                                 tmpData += " left=\"" + pLef->toString( ) + "\"";\r
949 \r
950                                                         if( pConn && pConn->isLong( ) )\r
951                                                                 tmpData += " connected=\"" + CAtomLong( GetTime( ) - (unsigned long)( (CAtomLong *)pConn )->getValue( ) ).toString( ) + "\"";\r
952 \r
953                                                         tmpData += " />\n";\r
954                                                 }\r
955                                         }\r
956 \r
957                                         tmpData += "</peers>\n";\r
958                                 }\r
959                         }\r
960 \r
961                         strData += " leecher=\""+ CAtomInt( iDL ).toString( ) + "\"";\r
962                         strData += " seeder=\""+ CAtomInt( iComplete ).toString( ) + "\"";\r
963                         strData += ">\n";\r
964                         if( m_bDumpXMLPeers )\r
965                                 strData += tmpData;\r
966                         else\r
967                                 strData += "<peers />\n";\r
968                         strData += "</torrent>\n";\r
969                 }\r
970         }\r
971 \r
972         strData += "</torrents>\n";\r
973 \r
974         FILE *pFile = NULL;\r
975 \r
976         if( ( pFile = fopen( m_strDumpXMLFile.c_str( ), "wb" ) ) == NULL )\r
977         {\r
978                 UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", m_strDumpXMLFile.c_str( ) );\r
979 \r
980                 return;\r
981         }\r
982 \r
983         fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
984         fclose( pFile );\r
985 }\r
986 \r
987 //RSS Support - code by labarks\r
988 void CTracker :: saveRSS( string strChannelTag )\r
989 {\r
990         string strData;\r
991         string strLink = m_strDumpRSSLink;\r
992         int intLimit;\r
993 \r
994         strData += "<?xml version=\"1.0\" encoding=\"" + gstrCharSet + "\" ?>\n";\r
995         strData += "<rss version=\"2.0\">\n";\r
996         strData += "<channel>\n";\r
997         strData += "<title>" + m_strDumpRSSTitle + ( strChannelTag != "" ? " - " + strChannelTag : "" ) + "</title>\n";\r
998         strData += "<link>" + m_strDumpRSSLink + "</link>\n";\r
999         strData += "<description>" + m_strDumpRSSDescription + "</description>\n";\r
1000         if( strChannelTag != "" )\r
1001                 strData += "<category domain=\"" + strLink + "index.html?filter=" + UTIL_StringToEscaped( strChannelTag ) + "\">" + strChannelTag + "</category>\n";\r
1002 \r
1003         if( !m_strDumpRSSImageURL.empty( ) )\r
1004         {\r
1005                 string strImageURL = ( m_strDumpRSSImageURL.substr( 0, 7 ) == "/files/" ? strLink + m_strDumpRSSImageURL.substr( 1 ) : m_strDumpRSSImageURL );\r
1006 \r
1007                 strData +=      "<image>\n<url>" + strImageURL + "</url>\n" +\r
1008                                         "<title>" + m_strDumpRSSTitle + "</title>\n" +\r
1009                                         "<description>" + m_strDumpRSSDescription + "</description>\n" +\r
1010                                         "<link>" + m_strDumpRSSLink + "</link>\n";\r
1011                 if( m_iDumpRSSImageWidth != 0 )\r
1012                         strData += "<width>" + UTIL_IntToString( m_iDumpRSSImageWidth ) + "</width>\n";\r
1013 \r
1014                 if( m_iDumpRSSImageHeight != 0 )\r
1015                         strData += "<height>" + UTIL_IntToString( m_iDumpRSSImageHeight ) + "</height>\n";\r
1016 \r
1017                 strData += "</image>\n";\r
1018         }\r
1019 \r
1020         if( !m_strDumpRSSCopyright.empty() )\r
1021                 strData += "<copyright>" + m_strDumpRSSCopyright + "</copyright>\n";\r
1022 \r
1023         strData += "<pubDate>" + UTIL_Date( ) + "</pubDate>\n";\r
1024         strData += "<language>" + m_strDumpRSSLanguage + "</language>\n";\r
1025         strData += "<ttl>" + UTIL_IntToString( m_iDumpRSS_TTL ) + "</ttl>\n";\r
1026         strData += "<generator>" + string( BNBT_VER ) + "</generator>\n";\r
1027 \r
1028         if( m_pDFile )\r
1029         {\r
1030                 map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
1031                 \r
1032                 unsigned long iKeySize = pmapDicti->size( );\r
1033 \r
1034                 // add the torrents into this structure one by one and sort it afterwards\r
1035 \r
1036                 struct torrent_t *pTorrents = new struct torrent_t[iKeySize];\r
1037 \r
1038                 if( m_iDumpRSSLimit == 0 || m_iDumpRSSLimit > iKeySize )\r
1039                         intLimit = iKeySize;\r
1040                 else\r
1041                         intLimit = m_iDumpRSSLimit;\r
1042 \r
1043                 unsigned long i = 0;\r
1044 \r
1045                 for( map<string, CAtom *> :: iterator it = pmapDicti->begin( ); it != pmapDicti->end( ); it++ )\r
1046                 {\r
1047                         if( m_pAllowed )\r
1048                         {\r
1049                                 CAtom *pList = m_pAllowed->getItem( (*it).first );\r
1050 \r
1051                                 if( pList && pList->isList( ) )\r
1052                                 {\r
1053                                         vector<CAtom *> vecTorrent = ( (CAtomList *)pList )->getValue( );\r
1054 \r
1055                                         if( vecTorrent.size( ) == 6 )\r
1056                                         {\r
1057                                                 CAtom *pFileName = vecTorrent[0];\r
1058                                                 CAtom *pName = vecTorrent[1];\r
1059                                                 CAtom *pAdded = vecTorrent[2];\r
1060                                                 CAtom *pSize = vecTorrent[3];\r
1061                                                 CAtom *pFiles = vecTorrent[4];\r
1062                                                 \r
1063                                                 pTorrents[i].strInfoHash = UTIL_HashToString( (*it).first );\r
1064 \r
1065                                                 if( pFileName )\r
1066                                                         pTorrents[i].strFileName = UTIL_RemoveHTML( pFileName->toString( ) );\r
1067 \r
1068                                                 if( pName )\r
1069                                                         pTorrents[i].strName = UTIL_RemoveHTML( pName->toString( ) );\r
1070 \r
1071                                                 if( pAdded )\r
1072                                                         pTorrents[i].strAdded = pAdded->toString( );\r
1073 \r
1074 \r
1075                                                 if( pSize )\r
1076                                                         pTorrents[i].iSize = ( (CAtomLong *)pSize )->getValue( );\r
1077                                                 \r
1078                                                 if( pFiles )\r
1079                                                         pTorrents[i].iFiles = ( (CAtomInt *)pFiles )->getValue( );\r
1080                                         }\r
1081                                 }\r
1082                         }\r
1083 \r
1084                         if( m_pTags )\r
1085                         {\r
1086                                 CAtom *pDicti = m_pTags->getItem( (*it).first );\r
1087 \r
1088                                 if( pDicti && pDicti->isDicti( ) )\r
1089                                 {\r
1090                                         CAtom *pTag = ( (CAtomDicti *)pDicti )->getItem( "tag" );\r
1091                                         CAtom *pName = ( (CAtomDicti *)pDicti )->getItem( "name" );\r
1092                                         CAtom *pUploader = ( (CAtomDicti *)pDicti )->getItem( "uploader" );\r
1093                                         //added\r
1094                                         CAtom *pInfoLink = ( (CAtomDicti *)pDicti )->getItem( "infolink" );\r
1095 \r
1096                                         if( pTag )\r
1097                                                 pTorrents[i].strTag = UTIL_RemoveHTML( pTag->toString( ) );\r
1098 \r
1099                                         if( pName )\r
1100                                                 pTorrents[i].strName = UTIL_RemoveHTML( pName->toString( ) );\r
1101 \r
1102                                         if( pUploader )\r
1103                                                 pTorrents[i].strUploader = UTIL_RemoveHTML( pUploader->toString( ) );\r
1104                                         //added\r
1105                                         if( pInfoLink )\r
1106                                                 pTorrents[i].strInfoLink = pInfoLink->toString( );\r
1107                                         else\r
1108                                                 pTorrents[i].strInfoLink = string();\r
1109                                 }\r
1110                         }\r
1111                         i++;\r
1112                 }\r
1113 \r
1114                 qsort( pTorrents, iKeySize, sizeof( struct torrent_t ), dsortByAdded );\r
1115                 \r
1116                 unsigned long j = 0;\r
1117                 \r
1118                 for( unsigned long i = 0; j < intLimit && i != iKeySize; i++ )\r
1119                 {\r
1120                         if( strChannelTag == "" || strChannelTag == pTorrents[i].strTag )\r
1121                         {\r
1122                                 string strTorrentLink = string( );\r
1123                                 string strName = pTorrents[i].strName;\r
1124                                 string strSize = UTIL_BytesToString( pTorrents[i].iSize );\r
1125                                 string strFiles = UTIL_IntToString( pTorrents[i].iFiles );\r
1126                                 string strInfoHash = pTorrents[i].strInfoHash;\r
1127                                 string strFileName = pTorrents[i].strFileName;\r
1128                                 string strAdded = pTorrents[i].strAdded;\r
1129                                 string strTag = pTorrents[i].strTag;\r
1130                                 string strUploader = pTorrents[i].strUploader;\r
1131                                 string strInfoLink = pTorrents[i].strInfoLink;\r
1132                                 string strFileSize = string( );\r
1133 \r
1134                                 if( m_strExternalTorrentDir.empty( ) )\r
1135                                         strTorrentLink = UTIL_URLEncode( strLink + "torrents/" + strFileName + "?info_hash=" + strInfoHash );\r
1136                                         //strTorrentLink = UTIL_URLEncode( strLink + "/torrent.html?info_hash=" + UTIL_HashToString( strInfoHash ) );\r
1137                                 else\r
1138                                         strTorrentLink = UTIL_URLEncode( m_strExternalTorrentDir + strFileName );\r
1139 \r
1140                                 strFileSize = UTIL_FileSizeToString( string( m_strAllowedDir + strFileName ).c_str() );\r
1141 \r
1142                                 if( !strInfoLink.empty() )\r
1143                                         strInfoLink = "<br/>\nInfo: <a href=\"" + strInfoLink + "\">" + strInfoLink + "</a>";\r
1144 \r
1145                                 strData += "<item>\n";\r
1146                                 strData += "<title>" + strName + "</title>\n";\r
1147                                 strData += "<link>" + strTorrentLink + "</link>\n";\r
1148                                 strData +=      "<description><![CDATA[Name: " + strName +\r
1149                                                         "<br/>\nInfo_hash: " + strInfoHash + \r
1150                                                         "<br/>\nTorrent: <a href=\"" + strTorrentLink + "\">" + strTorrentLink + "</a>" +\r
1151                                                     ( !strUploader.empty( ) && m_bShowUploader ? "<br/>\nUploader: " + strUploader : "" ) + \r
1152                                                         ( !strTag.empty( ) ? "<br/>\nTag: " + strTag : "" ) +\r
1153                                                         "<br/>\nSize: " + strSize +\r
1154                                                         "<br/>\nFiles: " + strFiles +\r
1155                                                         strInfoLink + "]]></description>\n";\r
1156                                 if( m_bAllowComments )\r
1157                                         strData += "<comments>" + strLink + "comments.html?info_hash=" + strInfoHash + "</comments>\n";\r
1158 \r
1159                                 if( !strTag.empty( ) )\r
1160                                         strData += "<category domain=\"" + strLink + "index.html?filter=" + UTIL_StringToEscaped( strTag ) + "\">" + strTag + "</category>\n";\r
1161 \r
1162                                 strData += "<enclosure url=\""+ strTorrentLink + "\" type=\"application/x-bittorrent\" length=\"" + strFileSize + "\" />\n";\r
1163                                 strData += "<guid isPermaLink=\"true\">" + strLink + "stats.html?info_hash=" + strInfoHash + "</guid>\n";\r
1164                                 strData += "<pubDate>" + UTIL_AddedToDate( strAdded ) + "</pubDate>\n";\r
1165                                 strData += "</item>\n";\r
1166                                 \r
1167                                 j++;\r
1168                         }\r
1169                 }\r
1170 \r
1171                 delete [] pTorrents;\r
1172         }\r
1173         strData += "</channel>\n";\r
1174         strData += "</rss>";\r
1175 \r
1176         FILE *pFile = NULL;\r
1177 \r
1178         string strRSSFile = m_strDumpRSSFile;\r
1179 \r
1180         if( strChannelTag != "" )\r
1181         {\r
1182                 string :: size_type iExt = m_strDumpRSSFile.rfind( "." );\r
1183 \r
1184                 string strExt;\r
1185                 \r
1186                 if( iExt != string :: npos )\r
1187                         strExt = m_strDumpRSSFile.substr( iExt );\r
1188                 strRSSFile = m_strDumpRSSFile.substr( 0, m_strDumpRSSFile.length() - strExt.length() ) + "-" + strChannelTag + strExt;\r
1189         }\r
1190         \r
1191         //UTIL_LogPrint( "tracker warning - RSS file: %s\n", strRSSFile.c_str( ) );\r
1192 \r
1193         if( ( pFile = fopen( strRSSFile.c_str( ), "wb" ) ) == NULL )\r
1194         {\r
1195                 UTIL_LogPrint( "tracker warning - unable to open %s for writing\n", strRSSFile.c_str( ) );\r
1196 \r
1197                 return;\r
1198         }\r
1199 \r
1200         fwrite( (void *)strData.c_str( ), sizeof( char ), strData.size( ), pFile );\r
1201         fclose( pFile );\r
1202 }\r
1203 void CTracker :: runSaveRSS( )\r
1204 {\r
1205         if( !m_strDumpRSSFile.empty( ) )\r
1206         {\r
1207 \r
1208                 if( m_iDumpRSSFileMode == 0 || m_iDumpRSSFileMode == 2 )\r
1209                 {\r
1210                         if( gbDebug )\r
1211                                 UTIL_LogPrint( "tracker - dumping RSS\n" );\r
1212                         saveRSS( );\r
1213                 }\r
1214 \r
1215                 if( m_iDumpRSSFileMode == 1 || m_iDumpRSSFileMode == 2 )\r
1216                 {\r
1217                         for( vector< pair<string, string> > :: iterator i = m_vecTags.begin( ); i != m_vecTags.end( ); i++ )\r
1218                         {\r
1219                                 string strTag = (string) (*i).first;\r
1220                                 if( gbDebug )\r
1221                                         UTIL_LogPrint( "tracker - dumping RSS for %s\n", strTag.c_str() );\r
1222                                 saveRSS( strTag );\r
1223                         }\r
1224                         if( !m_vecTags.size( ) && m_iDumpRSSFileMode == 1 )\r
1225                                 UTIL_LogPrint( "warning - no tags to dump RSS files per category, try changing to mode 0 or 2\n" );\r
1226                 }\r
1227 \r
1228                 m_iDumpRSSNext = GetTime( ) + m_iDumpRSSInterval * 60;\r
1229         }\r
1230 }\r
1231 //end addition\r
1232 \r
1233 \r
1234 void CTracker :: expireDownloaders( )\r
1235 {\r
1236 #ifdef BNBT_MYSQL\r
1237         if( m_bMySQLOverrideDState )\r
1238         {\r
1239                 string strQuery;\r
1240 \r
1241                 strQuery += "DELETE FROM dstate WHERE btime<NOW()-INTERVAL ";\r
1242                 strQuery += CAtomInt( m_iDownloaderTimeOutInterval ).toString( );\r
1243                 strQuery += " SECOND";\r
1244 \r
1245                 CMySQLQuery mq01( strQuery );\r
1246 \r
1247                 return;\r
1248         }\r
1249 #endif\r
1250 \r
1251         if( m_pTimeDicti )\r
1252         {\r
1253                 map<string, CAtom *> *pmapTimeDicti = m_pTimeDicti->getValuePtr( );\r
1254 \r
1255                 for( map<string, CAtom *> :: iterator i = pmapTimeDicti->begin( ); i != pmapTimeDicti->end( ); i++ )\r
1256                 {\r
1257                         if( (*i).second->isDicti( ) )\r
1258                         {\r
1259                                 map<string, CAtom *> *pmapPeersDicti = ( (CAtomDicti *)(*i).second )->getValuePtr( );\r
1260 \r
1261                                 for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); )\r
1262                                 {\r
1263                                         if( (*j).second->isLong( ) && ( (CAtomLong *)(*j).second )->getValue( ) < m_iPrevTime )\r
1264                                         {\r
1265                                                 if( m_pDFile )\r
1266                                                 {\r
1267                                                         CAtom *pPeers = m_pDFile->getItem( (*i).first );\r
1268 \r
1269                                                         if( pPeers && pPeers->isDicti( ) )\r
1270                                                                 ( (CAtomDicti *)pPeers )->delItem( (*j).first );\r
1271                                                 }\r
1272 \r
1273                                                 delete (*j).second;\r
1274 \r
1275                                                 pmapPeersDicti->erase( j++ );\r
1276                                         }\r
1277                                         else\r
1278                                                 j++;\r
1279                                 }\r
1280                         }\r
1281                 }\r
1282 \r
1283                 CountUniquePeers( );\r
1284 \r
1285                 m_iPrevTime = GetTime( );\r
1286 \r
1287                 if( m_bKeepDead )\r
1288                         return;\r
1289 \r
1290                 // delete empty hashes\r
1291 \r
1292                 if( m_pDFile )\r
1293                 {\r
1294                         map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
1295 \r
1296                         for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); )\r
1297                         {\r
1298                                 if( (*i).second->isDicti( ) && ( (CAtomDicti *)(*i).second )->isEmpty( ) )\r
1299                                 {\r
1300                                         m_pTimeDicti->delItem( (*i).first );\r
1301 \r
1302                                         delete (*i).second;\r
1303 \r
1304                                         pmapDicti->erase( i++ );\r
1305                                 }\r
1306                                 else\r
1307                                         i++;\r
1308                         }\r
1309                 }\r
1310         }\r
1311 }\r
1312 \r
1313 void CTracker :: parseTorrents( const char *szDir )\r
1314 {\r
1315         CAtomDicti *pAllowed = new CAtomDicti( );\r
1316 \r
1317 #ifdef WIN32\r
1318         char szMatch[1024];\r
1319         memset( szMatch, 0, sizeof( char ) * 1024 );\r
1320         strcpy( szMatch, szDir );\r
1321         strcat( szMatch, "*.torrent" );\r
1322 \r
1323         WIN32_FIND_DATA fdt;\r
1324 \r
1325         HANDLE hFind = FindFirstFile( szMatch, &fdt );\r
1326 \r
1327         if( hFind != INVALID_HANDLE_VALUE )\r
1328         {\r
1329                 do\r
1330 #else\r
1331         DIR *pDir = opendir( szDir );\r
1332 \r
1333         struct dirent *dp;\r
1334 \r
1335         if( pDir )\r
1336         {\r
1337                 while( ( dp = readdir( pDir ) ) )\r
1338 #endif\r
1339                 {\r
1340                         // let the server accept new connections while parsing\r
1341 \r
1342                         if( gpServer )\r
1343                                 gpServer->Update( false );\r
1344 \r
1345                         char szFile[1024];\r
1346                         memset( szFile, 0, sizeof( char ) * 1024 );\r
1347                         strcpy( szFile, szDir );\r
1348 \r
1349 #ifdef WIN32\r
1350                         string strFileName = fdt.cFileName;\r
1351 #else\r
1352                         string strFileName = dp->d_name;\r
1353 #endif\r
1354 \r
1355                         strcat( szFile, strFileName.c_str( ) );\r
1356 \r
1357 #ifndef WIN32\r
1358                         if( strlen( szFile ) > strlen( ".torrent" ) )\r
1359                         {\r
1360                                 if( strcmp( szFile + strlen( szFile ) - strlen( ".torrent" ), ".torrent" ) )\r
1361                                         continue;\r
1362                         }\r
1363                         else\r
1364                                 continue;\r
1365 #endif\r
1366 \r
1367                         CAtom *pFile = DecodeFile( szFile );\r
1368 \r
1369                         if( pFile && pFile->isDicti( ) )\r
1370                         {\r
1371                                 CAtom *pInfo = ( (CAtomDicti *)pFile )->getItem( "info" );\r
1372 \r
1373                                 if( pInfo && pInfo->isDicti( ) )\r
1374                                 {\r
1375                                         CAtomDicti *pInfoDicti = (CAtomDicti *)pInfo;\r
1376 \r
1377                                         string strHash = UTIL_InfoHash( pFile );\r
1378 \r
1379                                         CAtom *pName = pInfoDicti->getItem( "name" );\r
1380                                         CAtom *pLen = pInfoDicti->getItem( "length" );\r
1381                                         CAtom *pFiles = pInfoDicti->getItem( "files" );\r
1382 \r
1383                                         if( pName && ( pLen && pLen->isLong( ) || ( pFiles && pFiles->isList( ) ) ) )\r
1384                                         {\r
1385                                                 CAtomList *pList = new CAtomList( );\r
1386 \r
1387                                                 //\r
1388                                                 // filename\r
1389                                                 //\r
1390 \r
1391                                                 pList->addItem( new CAtomString( strFileName ) );\r
1392 \r
1393                                                 //\r
1394                                                 // name\r
1395                                                 //\r
1396 \r
1397                                                 pList->addItem( new CAtomString( pName->toString( ) ) );\r
1398 \r
1399                                                 //\r
1400                                                 // added time (i.e. modification time)\r
1401                                                 //\r
1402 \r
1403                                                 char pTime[256];\r
1404                                                 memset( pTime, 0, sizeof( char ) * 256 );\r
1405 \r
1406 #ifdef WIN32\r
1407                                                 FILETIME ft;\r
1408                                                 SYSTEMTIME st;\r
1409 \r
1410                                                 FileTimeToLocalFileTime( &fdt.ftLastWriteTime, &ft );\r
1411                                                 FileTimeToSystemTime( &ft, &st );\r
1412 \r
1413                                                 sprintf( pTime, "%04d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );\r
1414 #else\r
1415                                                 struct stat info;\r
1416 \r
1417                                                 stat( szFile, &info );\r
1418 \r
1419                                                 strftime( pTime, sizeof( char ) * 256, "%Y-%m-%d %H:%M:%S", localtime( &info.st_mtime ) );\r
1420 #endif\r
1421 \r
1422                                                 pList->addItem( new CAtomString( pTime ) );\r
1423 \r
1424                                                 //\r
1425                                                 // file size\r
1426                                                 //\r
1427 \r
1428                                                 if( pLen )\r
1429                                                         pList->addItem( new CAtomLong( *(CAtomLong *)pLen ) );\r
1430                                                 else\r
1431                                                 {\r
1432                                                         int64 iSize = 0;\r
1433 \r
1434                                                         vector<CAtom *> *pvecFiles = ( (CAtomList *)pFiles )->getValuePtr( );\r
1435 \r
1436                                                         for( vector<CAtom *> :: iterator j = pvecFiles->begin( ); j != pvecFiles->end( ); j++ )\r
1437                                                         {\r
1438                                                                 if( (*j)->isDicti( ) )\r
1439                                                                 {\r
1440                                                                         CAtom *pSubLength = ( (CAtomDicti *)(*j) )->getItem( "length" );\r
1441 \r
1442                                                                         if( pSubLength && pSubLength->isLong( ) )\r
1443                                                                                 iSize += ( (CAtomLong *)pSubLength )->getValue( );\r
1444                                                                 }\r
1445                                                         }\r
1446 \r
1447                                                         pList->addItem( new CAtomLong( iSize ) );\r
1448                                                 }\r
1449 \r
1450                                                 //\r
1451                                                 // number of files\r
1452                                                 //\r
1453 \r
1454                                                 if( pLen )\r
1455                                                         pList->addItem( new CAtomInt( 1 ) );\r
1456                                                 else\r
1457                                                         pList->addItem( new CAtomInt( ( (CAtomList *)pFiles )->getValuePtr( )->size( ) ) );\r
1458 \r
1459                                                 //\r
1460                                                 // file comment\r
1461                                                 //\r
1462 \r
1463                                                 CAtom *pComment = ( (CAtomDicti *)pFile )->getItem( "comment" );\r
1464 \r
1465                                                 if( pComment )\r
1466                                                         pList->addItem( new CAtomString( pComment->toString( ) ) );\r
1467                                                 else\r
1468                                                         pList->addItem( new CAtomString( ) );\r
1469 \r
1470                                                 pAllowed->setItem( strHash, pList );\r
1471 \r
1472                                                 if( m_pDFile && m_bKeepDead )\r
1473                                                 {\r
1474                                                         if( !m_pDFile->getItem( strHash ) )\r
1475                                                                 m_pDFile->setItem( strHash, new CAtomDicti( ) );\r
1476                                                 }\r
1477                                         }\r
1478                                         else\r
1479                                         {\r
1480                                                 UTIL_LogPrint( "error parsing torrents - %s has an incomplete or invalid info key, skipping\n", strFileName.c_str( ) );\r
1481 \r
1482                                                 if( m_bDeleteInvalid )\r
1483                                                 {\r
1484                                                         if( m_strArchiveDir.empty( ) )\r
1485                                                                 UTIL_DeleteFile( szFile );\r
1486                                                         else\r
1487                                                                 UTIL_MoveFile( szFile, ( m_strArchiveDir + strFileName ).c_str( ) );\r
1488                                                 }\r
1489                                         }\r
1490                                 }\r
1491                                 else\r
1492                                 {\r
1493                                         UTIL_LogPrint( "error parsing torrents - %s doesn't have an info key or info is not a valid bencoded dictionary, skipping\n", strFileName.c_str( ) );\r
1494 \r
1495                                         if( m_bDeleteInvalid )\r
1496                                         {\r
1497                                                 if( m_strArchiveDir.empty( ) )\r
1498                                                         UTIL_DeleteFile( szFile );\r
1499                                                 else\r
1500                                                         UTIL_MoveFile( szFile, ( m_strArchiveDir + strFileName ).c_str( ) );\r
1501                                         }\r
1502                                 }\r
1503                         }\r
1504                         else\r
1505                         {\r
1506                                 UTIL_LogPrint( "error parsing torrents - %s is not a valid bencoded dictionary or unable to decode, skipping\n", strFileName.c_str( ) );\r
1507 \r
1508                                 if( m_bDeleteInvalid )\r
1509                                 {\r
1510                                         if( m_strArchiveDir.empty( ) )\r
1511                                                 UTIL_DeleteFile( szFile );\r
1512                                         else\r
1513                                                 UTIL_MoveFile( szFile, ( m_strArchiveDir + strFileName ).c_str( ) );\r
1514                                 }\r
1515                         }\r
1516 \r
1517                         delete pFile;\r
1518 \r
1519                         pFile = NULL;\r
1520 \r
1521 #ifdef WIN32\r
1522                 } while( FindNextFile( hFind, &fdt ) );\r
1523 \r
1524                 FindClose( hFind );\r
1525 #else\r
1526                 }\r
1527 \r
1528                 closedir( pDir );\r
1529 #endif\r
1530         }\r
1531         else\r
1532                 UTIL_LogPrint( "error parsing torrents - unable to open %s or no torrents found\n", szDir );\r
1533 \r
1534         if( m_pAllowed )\r
1535                 delete m_pAllowed;\r
1536 \r
1537         m_pAllowed = pAllowed;\r
1538 }\r
1539 \r
1540 void CTracker :: parseTorrent( const char *szFile )\r
1541 {\r
1542 #ifdef WIN32\r
1543         HANDLE hFile = CreateFile( szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
1544 \r
1545         if( hFile == INVALID_HANDLE_VALUE )\r
1546         {\r
1547                 UTIL_LogPrint( "error parsing torrent - unable to open %s for reading\n", szFile );\r
1548 \r
1549                 return;\r
1550         }\r
1551 #endif\r
1552 \r
1553         CAtom *pTorrent = DecodeFile( szFile );\r
1554 \r
1555         if( pTorrent && pTorrent->isDicti( ) )\r
1556         {\r
1557                 CAtom *pInfo = ( (CAtomDicti *)pTorrent )->getItem( "info" );\r
1558 \r
1559                 if( pInfo && pInfo->isDicti( ) )\r
1560                 {\r
1561                         CAtomDicti *pInfoDicti = (CAtomDicti *)pInfo;\r
1562 \r
1563                         string strHash = UTIL_InfoHash( pTorrent );\r
1564 \r
1565                         CAtom *pName = pInfoDicti->getItem( "name" );\r
1566                         CAtom *pLen = pInfoDicti->getItem( "length" );\r
1567                         CAtom *pFiles = pInfoDicti->getItem( "files" );\r
1568 \r
1569                         if( pName && ( pLen && pLen->isLong( ) || ( pFiles && pFiles->isList( ) ) ) )\r
1570                         {\r
1571                                 CAtomList *pList = new CAtomList( );\r
1572 \r
1573                                 //\r
1574                                 // filename\r
1575                                 //\r
1576 \r
1577                                 pList->addItem( new CAtomString( UTIL_StripPath( szFile ).c_str( ) ) );\r
1578 \r
1579                                 //\r
1580                                 // name\r
1581                                 //\r
1582 \r
1583                                 pList->addItem( new CAtomString( pName->toString( ) ) );\r
1584 \r
1585                                 //\r
1586                                 // added time (i.e. modification time)\r
1587                                 //\r
1588 \r
1589                                 char pTime[256];\r
1590                                 memset( pTime, 0, sizeof( char ) * 256 );\r
1591 \r
1592 #ifdef WIN32\r
1593                                 FILETIME ft;\r
1594                                 SYSTEMTIME st;\r
1595 \r
1596                                 GetFileTime( hFile, NULL, NULL, &ft );\r
1597 \r
1598                                 FileTimeToLocalFileTime( &ft, &ft );\r
1599                                 FileTimeToSystemTime( &ft, &st );\r
1600 \r
1601                                 sprintf( pTime, "%04d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );\r
1602 #else\r
1603                                 struct stat info;\r
1604 \r
1605                                 stat( szFile, &info );\r
1606 \r
1607                                 strftime( pTime, sizeof( char ) * 256, "%Y-%m-%d %H:%M:%S", localtime( &info.st_mtime ) );\r
1608 #endif\r
1609 \r
1610                                 pList->addItem( new CAtomString( pTime ) );\r
1611 \r
1612                                 //\r
1613                                 // file size\r
1614                                 //\r
1615 \r
1616                                 if( pLen )\r
1617                                         pList->addItem( new CAtomLong( *(CAtomLong *)pLen ) );\r
1618                                 else\r
1619                                 {\r
1620                                         int64 iSize = 0;\r
1621 \r
1622                                         vector<CAtom *> *pvecFiles = ( (CAtomList *)pFiles )->getValuePtr( );\r
1623 \r
1624                                         for( vector<CAtom *> :: iterator j = pvecFiles->begin( ); j != pvecFiles->end( ); j++ )\r
1625                                         {\r
1626                                                 if( (*j)->isDicti( ) )\r
1627                                                 {\r
1628                                                         CAtom *pSubLength = ( (CAtomDicti *)(*j) )->getItem( "length" );\r
1629 \r
1630                                                         if( pSubLength && pSubLength->isLong( ) )\r
1631                                                                 iSize += ( (CAtomLong *)pSubLength )->getValue( );\r
1632                                                 }\r
1633                                         }\r
1634 \r
1635                                         pList->addItem( new CAtomLong( iSize ) );\r
1636                                 }\r
1637 \r
1638                                 //\r
1639                                 // number of files\r
1640                                 //\r
1641 \r
1642                                 if( pLen )\r
1643                                         pList->addItem( new CAtomInt( 1 ) );\r
1644                                 else\r
1645                                         pList->addItem( new CAtomInt( ( (CAtomList *)pFiles )->getValuePtr( )->size( ) ) );\r
1646 \r
1647                                 //\r
1648                                 // file comment\r
1649                                 //\r
1650 \r
1651                                 CAtom *pComment = ( (CAtomDicti *)pTorrent )->getItem( "comment" );\r
1652 \r
1653                                 if( pComment )\r
1654                                         pList->addItem( new CAtomString( pComment->toString( ) ) );\r
1655                                 else\r
1656                                         pList->addItem( new CAtomString( ) );\r
1657 \r
1658                                 m_pAllowed->setItem( strHash, pList );\r
1659 \r
1660                                 if( m_pDFile && m_bKeepDead )\r
1661                                 {\r
1662                                         if( !m_pDFile->getItem( strHash ) )\r
1663                                                 m_pDFile->setItem( strHash, new CAtomDicti( ) );\r
1664                                 }\r
1665                         }\r
1666                         else\r
1667                         {\r
1668                                 UTIL_LogPrint( "error parsing torrent - %s has an incomplete or invalid info key, skipping\n", szFile );\r
1669 \r
1670                                 if( m_bDeleteInvalid )\r
1671                                 {\r
1672                                         if( m_strArchiveDir.empty( ) )\r
1673                                                 UTIL_DeleteFile( szFile );\r
1674                                         else\r
1675                                                 UTIL_MoveFile( szFile, ( m_strArchiveDir + UTIL_StripPath( szFile ) ).c_str( ) );\r
1676                                 }\r
1677                         }\r
1678                 }\r
1679                 else\r
1680                 {\r
1681                         UTIL_LogPrint( "error parsing torrent - %s doesn't have an info key or info is not a valid bencoded dictionary, skipping\n", szFile );\r
1682 \r
1683                         if( m_bDeleteInvalid )\r
1684                         {\r
1685                                 if( m_strArchiveDir.empty( ) )\r
1686                                         UTIL_DeleteFile( szFile );\r
1687                                 else\r
1688                                         UTIL_MoveFile( szFile, ( m_strArchiveDir + UTIL_StripPath( szFile ) ).c_str( ) );\r
1689                         }\r
1690                 }\r
1691         }\r
1692         else\r
1693         {\r
1694                 UTIL_LogPrint( "error parsing torrent - %s is not a valid bencoded dictionary or unable to decode, skipping\n", szFile );\r
1695 \r
1696                 if( m_bDeleteInvalid )\r
1697                 {\r
1698                         if( m_strArchiveDir.empty( ) )\r
1699                                 UTIL_DeleteFile( szFile );\r
1700                         else\r
1701                                 UTIL_MoveFile( szFile, ( m_strArchiveDir + UTIL_StripPath( szFile ) ).c_str( ) );\r
1702                 }\r
1703         }\r
1704 \r
1705         delete pTorrent;\r
1706 \r
1707         pTorrent = NULL;\r
1708 \r
1709 #ifdef WIN32\r
1710         CloseHandle( hFile );\r
1711 #endif\r
1712 }\r
1713 \r
1714 // DWMOD ban stuff \r
1715 void CTracker :: parseClientBanList( void ) \r
1716\r
1717     m_pClientBannedList->clear(); \r
1718     string text = UTIL_ReadFile( m_strClientBanFile.c_str( ) ); \r
1719     string separators = "\n\r"; \r
1720     int n = text.length(); \r
1721     int start, stop; \r
1722  \r
1723     // loop through the ban file and add \r
1724     start = text.find_first_not_of(separators); \r
1725     while ((start >= 0) && (start < n)) { \r
1726     stop = text.find_first_of(separators, start); \r
1727     if ((stop < 0) || (stop > n)) \r
1728         stop = n; \r
1729   \r
1730     m_pClientBannedList->addItem(new CAtomString(text.substr(start, stop - start))); \r
1731     start = text.find_first_not_of(separators, stop + 1); \r
1732     } \r
1733\r
1734 \r
1735 void CTracker :: parseIPBanList( void ) \r
1736\r
1737     m_pIPBannedList->clear(); \r
1738     string text = UTIL_ReadFile( m_strIPBanFile.c_str( ) ); \r
1739     string separators = "\n\r "; \r
1740     int n = text.length(); \r
1741     int start, stop; \r
1742  \r
1743     // loop through the ban file and add shit \r
1744     start = text.find_first_not_of(separators); \r
1745     while ((start >= 0) && (start < n)) { \r
1746     stop = text.find_first_of(separators, start); \r
1747     if ((stop < 0) || (stop > n)) \r
1748         stop = n; \r
1749   \r
1750     m_pIPBannedList->addItem(new CAtomString(text.substr(start, stop - start))); \r
1751     start = text.find_first_not_of(separators, stop + 1); \r
1752     } \r
1753\r
1754 \r
1755 // Client Banlist check\r
1756 int CTracker :: isIPBanList( string strPeerIP )\r
1757 {\r
1758         vector<CAtom *>list = ( (CAtomList *)m_pIPBannedList )->getValue( ); \r
1759     for( unsigned long i = 0; i < list.size( ); i++ )\r
1760         { \r
1761                 CAtomString *str = (CAtomString *)list[i]; \r
1762                 string currentline = str->getValue();\r
1763                 if ( currentline == strPeerIP )\r
1764                         return 1;\r
1765         }\r
1766         return 0;\r
1767 }\r
1768 \r
1769 int CTracker :: isClientBanList( string strPeerID, bool isUserAgent ) \r
1770 {\r
1771         string tempPeerID;\r
1772         if( isUserAgent )\r
1773                 tempPeerID = strPeerID;\r
1774         else\r
1775         tempPeerID = UTIL_StringToEscaped(strPeerID);\r
1776     vector<CAtom *>list = ( (CAtomList *)m_pClientBannedList )->getValue( ); \r
1777     for( unsigned long i = 0; i < list.size( ); i++ ) \r
1778       { \r
1779       CAtomString *str = (CAtomString *)list[i]; \r
1780           string currentline;\r
1781       if( isUserAgent )\r
1782                   currentline = str->getValue();\r
1783           else\r
1784                   currentline = UTIL_StringToEscaped( UTIL_EscapedToString( str->getValue() )) ;\r
1785 \r
1786           if( gbDebug )\r
1787                   UTIL_LogPrint("Comparing %s to %s \n", tempPeerID.c_str(), currentline.c_str());\r
1788 \r
1789           if ( currentline == tempPeerID.substr(0,currentline.end()-currentline.begin()) && tempPeerID != "" ) {\r
1790         if( gbDebug )\r
1791                         UTIL_LogPrint("Peer ID/User Agent Matched: %s\n", tempPeerID.c_str());\r
1792                 return 1;\r
1793       } \r
1794           else if ( currentline == tempPeerID.c_str() ) {\r
1795         if( gbDebug )\r
1796                         UTIL_LogPrint("Peer ID/User Agent Matched: %s\n", tempPeerID.c_str());\r
1797          return 1;\r
1798       } \r
1799           else if ( tempPeerID.find(currentline) != string :: npos ){\r
1800         if( gbDebug )\r
1801                         UTIL_LogPrint("Peer ID/User Agent Matched: %s\n", tempPeerID.c_str());\r
1802          return 1;\r
1803       } \r
1804           }\r
1805       if( gbDebug )\r
1806                 UTIL_LogPrint("Peer ID/User Agent Did not match: %s\n", tempPeerID.c_str());\r
1807         return 0; \r
1808\r
1809 \r
1810 \r
1811 bool CTracker :: checkTag( string &strTag )\r
1812 {\r
1813         if( m_vecTags.empty( ) )\r
1814                 return true;\r
1815 \r
1816         for( vector< pair<string, string> > :: iterator i = m_vecTags.begin( ); i != m_vecTags.end( ); i++ )\r
1817         {\r
1818                 if( (*i).first == strTag )\r
1819                         return true;\r
1820         }\r
1821 \r
1822         return false;\r
1823 }\r
1824 \r
1825 void CTracker :: addTag( string strInfoHash, string strTag, string strName, string strUploader, string strInfoLink )\r
1826 {\r
1827         if( !m_pTags->getItem( strInfoHash ) )\r
1828                 m_pTags->setItem( strInfoHash, new CAtomDicti( ) );\r
1829 \r
1830         CAtom *pTag = m_pTags->getItem( strInfoHash );\r
1831 \r
1832         if( pTag && pTag->isDicti( ) )\r
1833         {\r
1834                 ( (CAtomDicti *)pTag )->setItem( "tag", new CAtomString( strTag ) );\r
1835 \r
1836                 if( !strName.empty( ) )\r
1837                         ( (CAtomDicti *)pTag )->setItem( "name", new CAtomString( strName ) );\r
1838 \r
1839                 if( !strUploader.empty( ) )\r
1840                         ( (CAtomDicti *)pTag )->setItem( "uploader", new CAtomString( strUploader ) );\r
1841 \r
1842                 if( !strInfoLink.empty( ) )\r
1843                         ( (CAtomDicti *)pTag )->setItem( "infolink", new CAtomString( strInfoLink ) );\r
1844         }\r
1845 \r
1846         saveTags( );\r
1847 }\r
1848 \r
1849 void CTracker :: deleteTag( string strInfoHash )\r
1850 {\r
1851         m_pTags->delItem( strInfoHash );\r
1852 \r
1853         saveTags( );\r
1854 }\r
1855 \r
1856 user_t CTracker :: checkUser( string strLogin, string strMD5 )\r
1857 {\r
1858         user_t user;\r
1859 \r
1860         user.iAccess = m_iGuestAccess;\r
1861 \r
1862         // if no users exist, grant full access\r
1863 \r
1864         if( m_pUsers->isEmpty( ) )\r
1865                 user.iAccess = ~0;\r
1866 \r
1867         CAtom *pUser = m_pUsers->getItem( strLogin );\r
1868 \r
1869         if( pUser && pUser->isDicti( ) )\r
1870         {\r
1871                 CAtom *pMD5 = ( (CAtomDicti *)pUser )->getItem( "md5" );\r
1872                 CAtom *pAccess = ( (CAtomDicti *)pUser )->getItem( "access" );\r
1873                 CAtom *pMail = ( (CAtomDicti *)pUser )->getItem( "email" );\r
1874                 CAtom *pCreated = ( (CAtomDicti *)pUser )->getItem( "created" );\r
1875 \r
1876                 if( pMD5 && pAccess && pAccess->isLong( ) && pMail )\r
1877                 {\r
1878                         // check hash\r
1879 \r
1880                         if( strMD5 == pMD5->toString( ) )\r
1881                         {\r
1882                                 user.strLogin = strLogin;\r
1883                                 user.strLowerLogin = UTIL_ToLower( user.strLogin );\r
1884                                 user.strMD5 = strMD5;\r
1885                                 user.strMail = pMail->toString( );\r
1886                                 user.strLowerMail = UTIL_ToLower( user.strMail );\r
1887                                 user.iAccess = (int)( (CAtomLong *)pAccess )->getValue( );\r
1888                                 user.strCreated = pCreated->toString( );\r
1889                         }\r
1890                 }\r
1891         }\r
1892 \r
1893         return user;\r
1894 }\r
1895 \r
1896 void CTracker :: addUser( string strLogin, string strPass, int iAccess, string strMail )\r
1897 {\r
1898         CAtomDicti *pUser = new CAtomDicti( );\r
1899 \r
1900         // calculate md5 hash of A1\r
1901 \r
1902         string strA1 = strLogin + ":" + gstrRealm + ":" + strPass;\r
1903 \r
1904         unsigned char szMD5[16];\r
1905 \r
1906         MD5_CTX md5;\r
1907 \r
1908         MD5Init( &md5 );\r
1909         MD5Update( &md5, (unsigned char *)strA1.c_str( ), strA1.size( ) );\r
1910         MD5Final( szMD5, &md5 );\r
1911 \r
1912         pUser->setItem( "md5", new CAtomString( string( (char *)szMD5, 16 ) ) );\r
1913         pUser->setItem( "access", new CAtomLong( iAccess ) );\r
1914         pUser->setItem( "email", new CAtomString( strMail ) );\r
1915 \r
1916         time_t tNow = time( NULL );\r
1917 \r
1918         char pTime[256];\r
1919         memset( pTime, 0, sizeof( char ) * 256 );\r
1920         strftime( pTime, sizeof( char ) * 256, "%Y %m/%d %H:%M:%S", localtime( &tNow ) );\r
1921 \r
1922         pUser->setItem( "created", new CAtomString( pTime ) );\r
1923 \r
1924         m_pUsers->setItem( strLogin, pUser );\r
1925 \r
1926         saveUsers( );\r
1927 }\r
1928 \r
1929 void CTracker :: deleteUser( string strLogin )\r
1930 {\r
1931         m_pUsers->delItem( strLogin );\r
1932 \r
1933         saveUsers( );\r
1934 }\r
1935 \r
1936 void CTracker :: CountUniquePeers( )\r
1937 {\r
1938         delete m_pIPs;\r
1939 \r
1940         m_pIPs = new CAtomDicti( );\r
1941 \r
1942         map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
1943 \r
1944         for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); i++ )\r
1945         {\r
1946                 if( (*i).second->isDicti( ) )\r
1947                 {\r
1948                         map<string, CAtom *> *pmapPeersDicti = ( (CAtomDicti *)(*i).second )->getValuePtr( );\r
1949 \r
1950                         for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); j++ )\r
1951                         {\r
1952                                 if( (*j).second->isDicti( ) )\r
1953                                 {\r
1954                                         CAtom *pIP = ( (CAtomDicti *)(*j).second )->getItem( "ip" );\r
1955 \r
1956                                         if( pIP )\r
1957                                                 AddUniquePeer( pIP->toString( ) );\r
1958                                 }\r
1959                         }\r
1960                 }\r
1961         }\r
1962 }\r
1963 \r
1964 void CTracker :: AddUniquePeer( string strIP )\r
1965 {\r
1966         // increment unique count for this ip\r
1967 \r
1968         CAtom *pNum = m_pIPs->getItem( strIP );\r
1969 \r
1970         int iNum = 1;\r
1971 \r
1972         if( pNum && dynamic_cast<CAtomInt *>( pNum ) )\r
1973                 iNum = dynamic_cast<CAtomInt *>( pNum )->getValue( ) + 1;\r
1974 \r
1975         m_pIPs->setItem( strIP, new CAtomInt( iNum ) );\r
1976 }\r
1977 \r
1978 void CTracker :: RemoveUniquePeer( string strIP )\r
1979 {\r
1980         // decrement unique count for this ip\r
1981 \r
1982         CAtom *pNum = m_pIPs->getItem( strIP );\r
1983 \r
1984         int iNum = 0;\r
1985 \r
1986         if( pNum && dynamic_cast<CAtomInt *>( pNum ) )\r
1987                 iNum = dynamic_cast<CAtomInt *>( pNum )->getValue( ) - 1;\r
1988 \r
1989         if( iNum > 0 )\r
1990                 m_pIPs->setItem( strIP, new CAtomInt( iNum ) );\r
1991         else\r
1992                 m_pIPs->delItem( strIP );\r
1993 }\r
1994 \r
1995 void CTracker :: QueueAnnounce( struct announce_t ann )\r
1996 {\r
1997         // normally called from link.cpp\r
1998 \r
1999         m_mtxQueued.Claim( );\r
2000         m_vecQueued.push_back( ann );\r
2001         m_mtxQueued.Release( );\r
2002 }\r
2003 \r
2004 void CTracker :: Announce( struct announce_t ann )\r
2005 {\r
2006 #ifdef BNBT_MYSQL\r
2007         if( m_bMySQLOverrideDState )\r
2008         {\r
2009                 if( ann.strEvent != "stopped" )\r
2010                 {\r
2011                         string strQuery;\r
2012 \r
2013                         strQuery = "REPLACE INTO dstate (bhash,bid,bkey,bip,bport,buploaded,bdownloaded,bleft,btime) VALUES(\'";\r
2014                         strQuery += UTIL_StringToMySQL( ann.strInfoHash );\r
2015                         strQuery += "\',\'";\r
2016                         strQuery += UTIL_StringToMySQL( ann.strPeerID );\r
2017                         strQuery += "\',\'";\r
2018                         strQuery += UTIL_StringToMySQL( ann.strKey );\r
2019                         strQuery += "\',\'";\r
2020                         strQuery += UTIL_StringToMySQL( ann.strIP.substr( 0, 15 ) );\r
2021                         strQuery += "\',";\r
2022                         strQuery += CAtomInt( ann.iPort ).toString( );\r
2023                         strQuery += ",";\r
2024                         strQuery += CAtomLong( ann.iUploaded ).toString( );\r
2025                         strQuery += ",";\r
2026                         strQuery += CAtomLong( ann.iDownloaded ).toString( );\r
2027                         strQuery += ",";\r
2028                         strQuery += CAtomLong( ann.iLeft ).toString( );\r
2029                         strQuery += ",NOW())";\r
2030 \r
2031                         CMySQLQuery mq01( strQuery );\r
2032 \r
2033                         if( ann.strEvent == "completed" )\r
2034                         {\r
2035                                 strQuery.erase( );\r
2036 \r
2037                                 strQuery += "INSERT INTO completed (bhash) VALUES(\'";\r
2038                                 strQuery += UTIL_StringToMySQL( ann.strInfoHash );\r
2039                                 strQuery += "\')";\r
2040 \r
2041                                 CMySQLQuery mq02( strQuery );\r
2042 \r
2043                                 strQuery.erase( );\r
2044 \r
2045                                 strQuery += "UPDATE completed SET bcompleted=bcompleted+1 WHERE bhash=\'";\r
2046                                 strQuery += UTIL_StringToMySQL( ann.strInfoHash );\r
2047                                 strQuery += "\'";\r
2048 \r
2049                                 CMySQLQuery mq03( strQuery );\r
2050                         }\r
2051                 }\r
2052                 else\r
2053                 {\r
2054                         // strEvent == "stopped"\r
2055 \r
2056                         string strQuery;\r
2057 \r
2058                         strQuery += "DELETE FROM dstate WHERE bhash=\'";\r
2059                         strQuery += UTIL_StringToMySQL( ann.strInfoHash );\r
2060                         strQuery += "\' AND bid=\'";\r
2061                         strQuery += UTIL_StringToMySQL( ann.strPeerID );\r
2062 \r
2063                         if( m_bAnnounceKeySupport && !ann.strKey.empty( ) )\r
2064                         {\r
2065                                 if( gbDebug )\r
2066                                         UTIL_LogPrint( "Announce: key support\n" );\r
2067 \r
2068                                 strQuery += "\' AND bkey=\'";\r
2069                                 strQuery += UTIL_StringToMySQL( ann.strKey );\r
2070                         }\r
2071                         else\r
2072                         {\r
2073                                 if( gbDebug  )\r
2074                                         UTIL_LogPrint( "Announce: no key support\n" );\r
2075 \r
2076                                 strQuery += "\' AND bip=\'";\r
2077                                 strQuery += UTIL_StringToMySQL( ann.strIP );\r
2078                         }\r
2079 \r
2080                         CMySQLQuery mq04( strQuery );\r
2081                 }\r
2082 \r
2083                 return;\r
2084         }\r
2085 #endif\r
2086 \r
2087         if( m_bEnableAbuseBlock == true && ann.bAbusive == true )\r
2088                 ann.strEvent = "stopped";\r
2089 \r
2090         if( m_bEnableAbuseBlock == true && m_pAbuse )\r
2091         {\r
2092                 if( m_pAbuse->getItem( ann.strIP ) )\r
2093                 {\r
2094                         CAtom *pPeerCIP = m_pAbuse->getItem( ann.strIP );\r
2095                         if( pPeerCIP && pPeerCIP->isDicti( ) )\r
2096                         {\r
2097                                 CAtom *pPeerAbuses = ((CAtomDicti *)pPeerCIP)->getItem( "totalabuses" , new CAtomLong ( 0 ) );\r
2098                 long m_pPeerAbuses = ((CAtomLong *)pPeerAbuses)->getValue( );\r
2099                                 ((CAtomDicti *)pPeerCIP)->setItem("lastannounce", new CAtomLong( GetRealTime( ) ) );\r
2100                                 ((CAtomDicti *)pPeerCIP)->setItem("lastinfohash", new CAtomString( ann.strInfoHash ) );\r
2101                                 ((CAtomDicti *)pPeerCIP)->setItem("lastpeerid", new CAtomString( ann.strPeerID ) );\r
2102 \r
2103                                 if( ann.bIncrement == true && ann.iLeft != 0 )\r
2104                     ((CAtomDicti *)pPeerCIP)->setItem( "totalabuses" , new CAtomLong( m_pPeerAbuses + 1 ));\r
2105 \r
2106                                 if( ann.bIncrement == false && ann.bAbusive == false ){\r
2107                                         ((CAtomDicti *)pPeerCIP)->delItem( "totalabuses" );\r
2108                                         ((CAtomDicti *)pPeerCIP)->setItem( "totalabuses", new CAtomLong( 0 ) );\r
2109                                 }\r
2110                         }\r
2111                 }\r
2112                 else\r
2113                 {\r
2114                         CAtomDicti *pPeerCIP = new CAtomDicti();\r
2115                         pPeerCIP->setItem( "lastannounce", new CAtomLong( GetRealTime( ) ) );\r
2116                         pPeerCIP->setItem( "lastinfohash", new CAtomString( ann.strInfoHash ) );\r
2117                         pPeerCIP->setItem("lastpeerid", new CAtomString( ann.strPeerID ) );\r
2118                         m_pAbuse->setItem( ann.strIP, pPeerCIP );\r
2119                 }\r
2120         }\r
2121 \r
2122         if( ann.strEvent != "stopped" )\r
2123         {\r
2124                 if( m_pDFile )\r
2125                 {\r
2126                         if( !m_pDFile->getItem( ann.strInfoHash ) )\r
2127                                 m_pDFile->setItem( ann.strInfoHash, new CAtomDicti( ) );\r
2128 \r
2129                         CAtom *pPeers = m_pDFile->getItem( ann.strInfoHash );\r
2130 \r
2131                         if( pPeers && pPeers->isDicti( ) )\r
2132                         {\r
2133                                 CAtom *pPeer = ( (CAtomDicti *)pPeers )->getItem( ann.strPeerID );\r
2134 \r
2135                                 if( pPeer && pPeer->isDicti( ) )\r
2136                                 {\r
2137                                         CAtom *pKey = ((CAtomDicti *)pPeer)->getItem( "key" , NULL );\r
2138 \r
2139                                         if( pKey && m_bAnnounceKeySupport )\r
2140                                         {\r
2141                                                 if( ((CAtomString *)pKey)->toString() == ann.strKey.c_str( ) )\r
2142                                                 {\r
2143                                                         ( (CAtomDicti *)pPeer )->setItem( "ip", new CAtomString( ann.strIP ) );\r
2144                                     ( (CAtomDicti *)pPeer )->setItem( "uploaded", new CAtomLong( ann.iUploaded ) );\r
2145                                                         ( (CAtomDicti *)pPeer )->setItem( "downloaded", new CAtomLong( ann.iDownloaded ) );\r
2146                                                         ( (CAtomDicti *)pPeer )->setItem( "left", new CAtomLong( ann.iLeft ) );\r
2147                                                 }\r
2148                                         }\r
2149                                         else\r
2150                                         {\r
2151                                                 ( (CAtomDicti *)pPeer )->setItem( "uploaded", new CAtomLong( ann.iUploaded ) );\r
2152                                                 ( (CAtomDicti *)pPeer )->setItem( "downloaded", new CAtomLong( ann.iDownloaded ) );\r
2153                                                 ( (CAtomDicti *)pPeer )->setItem( "left", new CAtomLong( ann.iLeft ) );\r
2154                                                 if( m_bAnnounceKeySupport )\r
2155                                                         ( (CAtomDicti *)pPeer )->setItem( "key", new CAtomString( ann.strKey ) );\r
2156                                         }\r
2157                                 \r
2158                                 }\r
2159                                 else\r
2160                                 {\r
2161                                         CAtomDicti *pPeerDicti = new CAtomDicti( );\r
2162 \r
2163                                         pPeerDicti->setItem( "ip", new CAtomString( ann.strIP ) );\r
2164                                         pPeerDicti->setItem( "port", new CAtomLong( ann.iPort ) );\r
2165                                         pPeerDicti->setItem( "uploaded", new CAtomLong( ann.iUploaded ) );\r
2166                                         pPeerDicti->setItem( "downloaded", new CAtomLong( ann.iDownloaded ) );\r
2167                                         pPeerDicti->setItem( "left", new CAtomLong( ann.iLeft ) );\r
2168                                         pPeerDicti->setItem( "connected", new CAtomLong( GetTime( ) ) );\r
2169                                         pPeerDicti->setItem( "key", new CAtomString( ann.strKey ) ); \r
2170 \r
2171                                         ( (CAtomDicti *)pPeers )->setItem( ann.strPeerID, pPeerDicti );\r
2172 \r
2173                                         if( m_bCountUniquePeers )\r
2174                                                 AddUniquePeer( ann.strIP );\r
2175                                 }\r
2176 \r
2177                                 if( m_pTimeDicti )\r
2178                                 {\r
2179                                         if( !m_pTimeDicti->getItem( ann.strInfoHash ) )\r
2180                                                 m_pTimeDicti->setItem( ann.strInfoHash, new CAtomDicti( ) );\r
2181 \r
2182                                         CAtom *pTS = m_pTimeDicti->getItem( ann.strInfoHash );\r
2183 \r
2184                                         if( pTS && pTS->isDicti( ) )\r
2185                                                 ( (CAtomDicti *)pTS )->setItem( ann.strPeerID, new CAtomLong( GetTime( ) ) );\r
2186                                 }\r
2187                         }\r
2188                 }\r
2189 \r
2190                 if( ann.strEvent == "completed" )\r
2191                 {\r
2192                         if( m_pCompleted )\r
2193                         {\r
2194                                 CAtom *pCompleted = m_pCompleted->getItem( ann.strInfoHash );\r
2195 \r
2196                                 int64 iCompleted = 0;\r
2197 \r
2198                                 if( pCompleted && pCompleted->isLong( ) )\r
2199                                         iCompleted = ( (CAtomLong *)pCompleted )->getValue( );\r
2200 \r
2201                                 m_pCompleted->setItem( ann.strInfoHash, new CAtomLong( iCompleted + 1 ) );\r
2202                         }\r
2203                 }\r
2204         }\r
2205         else\r
2206         {\r
2207                 // strEvent == "stopped"\r
2208 \r
2209                 if( m_pDFile )\r
2210                 {\r
2211                         if( !m_pDFile->getItem( ann.strInfoHash ) )\r
2212                                 m_pDFile->setItem( ann.strInfoHash, new CAtomDicti( ) );\r
2213 \r
2214                         CAtom *pPeers = m_pDFile->getItem( ann.strInfoHash );\r
2215 \r
2216                         if( pPeers && pPeers->isDicti( ) )\r
2217                         {\r
2218                                 CAtom *pPeer = ( (CAtomDicti *)pPeers )->getItem( ann.strPeerID );\r
2219 \r
2220                                 if( pPeer && pPeer->isDicti( ) )\r
2221                                 {\r
2222                                         CAtom *pPeerIP = ( (CAtomDicti *)pPeer )->getItem( "ip" );\r
2223 \r
2224                                         if( pPeerIP )\r
2225                                         {\r
2226                                                 CAtom *pKey = ((CAtomDicti *)pPeer)->getItem( "key" , NULL );\r
2227                                                 bool allowstop;\r
2228                                                 allowstop = true;\r
2229                                                 if( !( pKey && m_bAnnounceKeySupport && ((CAtomString *)pKey)->toString() == ann.strKey.c_str( ) ) )\r
2230                                                         allowstop = false;\r
2231                                                 if( !m_bAnnounceKeySupport && pPeerIP->toString( ) != ann.strIP )\r
2232                                                         allowstop = false;\r
2233 \r
2234                                                 if( allowstop == true )\r
2235                                                 {\r
2236                                                         ( (CAtomDicti *)pPeers )->delItem( ann.strPeerID );\r
2237 \r
2238                                                         if( m_pTimeDicti )\r
2239                                                         {\r
2240                                                                 if( !m_pTimeDicti->getItem( ann.strInfoHash ) )\r
2241                                                                         m_pTimeDicti->setItem( ann.strInfoHash, new CAtomDicti( ) );\r
2242 \r
2243                                                                 CAtom *pTS = m_pTimeDicti->getItem( ann.strInfoHash );\r
2244 \r
2245                                                                 if( pTS && pTS->isDicti( ) )\r
2246                                                                         ( (CAtomDicti *)pTS )->delItem( ann.strPeerID );\r
2247                                                         }\r
2248 \r
2249                                                         if( m_bCountUniquePeers )\r
2250                                                                 RemoveUniquePeer( ann.strIP );\r
2251                                                 }\r
2252                                         }\r
2253                                 }\r
2254                         }\r
2255                 }\r
2256         }\r
2257 }\r
2258 \r
2259 void CTracker :: RefreshFastCache( )\r
2260 {\r
2261         delete m_pFastCache;\r
2262 \r
2263         m_pFastCache = new CAtomDicti( );\r
2264 \r
2265         if( m_pDFile )\r
2266         {\r
2267                 map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
2268 \r
2269                 for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); i++ )\r
2270                 {\r
2271                         if( (*i).second->isDicti( ) )\r
2272                         {\r
2273                                 map<string, CAtom *> *pmapPeersDicti = ( (CAtomDicti *)(*i).second )->getValuePtr( );\r
2274 \r
2275                                 unsigned long iSeeders = 0;\r
2276                                 unsigned long iLeechers = 0;\r
2277                                 unsigned long iCompleted = 0;\r
2278                                 int64 iTotalLeft = 0;\r
2279                                 int64 iMinLeft = 0;\r
2280                                 int64 iMaxiLeft = 0;\r
2281 \r
2282                                 bool bFirst = true;\r
2283 \r
2284                                 for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); j++ )\r
2285                                 {\r
2286                                         if( (*j).second->isDicti( ) )\r
2287                                         {\r
2288                                                 CAtom *pLeft = ( (CAtomDicti *)(*j).second )->getItem( "left" );\r
2289 \r
2290                                                 if( pLeft && dynamic_cast<CAtomLong *>( pLeft ) )\r
2291                                                 {\r
2292                                                         int64 iLeft = dynamic_cast<CAtomLong *>( pLeft )->getValue( );\r
2293 \r
2294                                                         if( iLeft == 0 )\r
2295                                                                 iSeeders++;\r
2296                                                         else\r
2297                                                         {\r
2298                                                                 iLeechers++;\r
2299 \r
2300                                                                 // only calculate total / min / max on leechers\r
2301 \r
2302                                                                 if( m_bShowAverageLeft )\r
2303                                                                         iTotalLeft += iLeft;\r
2304 \r
2305                                                                 if( bFirst || iLeft < iMinLeft )\r
2306                                                                         iMinLeft = iLeft;\r
2307 \r
2308                                                                 if( bFirst || iLeft > iMaxiLeft )\r
2309                                                                         iMaxiLeft = iLeft;\r
2310 \r
2311                                                                 bFirst = false;\r
2312                                                         }\r
2313                                                 }\r
2314                                         }\r
2315                                 }\r
2316 \r
2317                                 if( m_pCompleted )\r
2318                                 {\r
2319                                         CAtom *pCompleted = m_pCompleted->getItem( (*i).first );\r
2320 \r
2321                                         if( pCompleted && dynamic_cast<CAtomLong *>( pCompleted ) )\r
2322                                                 iCompleted = (unsigned long)dynamic_cast<CAtomLong *>( pCompleted )->getValue( );\r
2323                                 }\r
2324 \r
2325                                 CAtomList *pList = new CAtomList( );\r
2326 \r
2327                                 pList->addItem( new CAtomInt( iSeeders ) );\r
2328                                 pList->addItem( new CAtomInt( iLeechers ) );\r
2329                                 pList->addItem( new CAtomInt( iCompleted ) );\r
2330                                 pList->addItem( new CAtomLong( iTotalLeft ) );\r
2331                                 pList->addItem( new CAtomLong( iMinLeft ) );\r
2332                                 pList->addItem( new CAtomLong( iMaxiLeft ) );\r
2333 \r
2334                                 m_pFastCache->setItem( (*i).first, pList );\r
2335                         }\r
2336                 }\r
2337         }\r
2338 }\r
2339 \r
2340 \r
2341 void CTracker :: serverResponseGET( struct request_t *pRequest, struct response_t *pResponse, user_t user )\r
2342 {\r
2343         if( m_bDisableHTML )\r
2344         {\r
2345                 if( pRequest->strURL == "/announce" )\r
2346                         serverResponseAnnounce( pRequest, pResponse, user );\r
2347                 else if( pRequest->strURL == "/scrape" )\r
2348                         serverResponseScrape( pRequest, pResponse, user );\r
2349                 else if( pRequest->strURL == "/info.bencode" )\r
2350                         serverResponseBencodeInfo( pRequest, pResponse, user );\r
2351                 else\r
2352                         pResponse->strCode = "404 Not Found";\r
2353                 return;\r
2354         }\r
2355         if( pRequest->strURL == "/" || pRequest->strURL == "/index.html" )\r
2356                 serverResponseIndex( pRequest, pResponse, user );\r
2357         else if( pRequest->strURL == "/announce" )\r
2358                 serverResponseAnnounce( pRequest, pResponse, user );\r
2359         else if( pRequest->strURL == "/scrape" )\r
2360                 serverResponseScrape( pRequest, pResponse, user );\r
2361         else if( pRequest->strURL == "/stats.html" )\r
2362                 serverResponseStats( pRequest, pResponse, user );\r
2363         else if( pRequest->strURL == "/torrent.html" )\r
2364                 serverResponseTorrent( pRequest, pResponse, user );\r
2365         //RSS Support - code by labarks\r
2366         else if( pRequest->strURL.substr( 0, 10 ) == "/torrents/" && pRequest->strURL.substr( pRequest->strURL.length() - 8 ) == ".torrent" )\r
2367                 serverResponseTorrent( pRequest, pResponse, user );\r
2368         //end addition\r
2369         else if( pRequest->strURL.substr( 0, 7 ) == "/files/" )\r
2370                 serverResponseFile( pRequest, pResponse, user );\r
2371         else if( pRequest->strURL == "/robots.txt" && !m_strRobots.empty( ) )\r
2372                 serverResponseRobots( pRequest, pResponse, user );\r
2373         else if( pRequest->strURL == "/login.html" )\r
2374                 serverResponseLogin( pRequest, pResponse, user );\r
2375         else if( pRequest->strURL == "/signup.html" )\r
2376                 serverResponseSignup( pRequest, pResponse, user );\r
2377         else if( pRequest->strURL == "/upload.html" )\r
2378                 serverResponseUploadGET( pRequest, pResponse, user );\r
2379         else if( pRequest->strURL == "/info.html" )\r
2380                 serverResponseInfo( pRequest, pResponse, user );\r
2381         else if( pRequest->strURL == "/info.bencode" )\r
2382                 serverResponseBencodeInfo( pRequest, pResponse, user );\r
2383         else if( pRequest->strURL == "/admin.html" )\r
2384                 serverResponseAdmin( pRequest, pResponse, user );\r
2385         else if( pRequest->strURL == "/users.html" )\r
2386                 serverResponseUsers( pRequest, pResponse, user );\r
2387         else if( pRequest->strURL == "/comments.html" )\r
2388                 serverResponseComments( pRequest, pResponse, user );\r
2389         else if( pRequest->strURL == "/favicon.ico" && !m_strFavicon.empty() )\r
2390                 serverResponseIcon( pRequest, pResponse, user );\r
2391         else\r
2392                 pResponse->strCode = "404 Not Found";\r
2393 }\r
2394 \r
2395 void CTracker :: serverResponsePOST( struct request_t *pRequest, struct response_t *pResponse, CAtomList *pPost, user_t user )\r
2396 {\r
2397         if( pPost )\r
2398         {\r
2399                 if( pRequest->strURL == "/upload.html" && !m_bDisableHTML )\r
2400                         serverResponseUploadPOST( pRequest, pResponse, pPost, user );\r
2401                 else\r
2402                         pResponse->strCode = "404 Not Found";\r
2403         }\r
2404         else\r
2405                 pResponse->strCode = "500 Server Error";\r
2406 }\r
2407 \r
2408 void CTracker :: serverResponseRobots( struct request_t *pRequest, struct response_t *pResponse, user_t user )\r
2409 {\r
2410         pResponse->strCode = "200 OK";\r
2411 \r
2412         pResponse->mapHeaders.insert( pair<string, string>( "Content-Type", "text/plain" ) );\r
2413 \r
2414         pResponse->strContent = m_strRobots;\r
2415 }\r
2416 \r
2417 void CTracker :: serverResponseIcon( struct request_t *pRequest, struct response_t *pResponse, user_t user )\r
2418 {\r
2419         pResponse->strCode = "200 OK";\r
2420 \r
2421         pResponse->mapHeaders.insert( pair<string, string>( "Content-Type", "image/x-icon" ) );\r
2422 \r
2423         pResponse->strContent = m_strFavicon;\r
2424 }\r
2425 \r
2426 void CTracker :: Update( )\r
2427 {\r
2428         if( !m_strAllowedDir.empty( ) )\r
2429         {\r
2430                 if( m_iParseAllowedInterval > 0 && GetTime( ) > m_iParseAllowedNext )\r
2431                 {\r
2432                         if( gbDebug )\r
2433                                 UTIL_LogPrint( "tracker - parsing torrents (%s)\n", m_strAllowedDir.c_str( ) );\r
2434 \r
2435                         // don't parse torrents again until we're done since parseTorrents calls gpServer->Update( ) which calls m_pTracker->Update( )\r
2436 \r
2437                         m_iParseAllowedNext = GetTime( ) + 9999;\r
2438 \r
2439                         parseTorrents( m_strAllowedDir.c_str( ) );\r
2440 \r
2441                         m_iParseAllowedNext = GetTime( ) + m_iParseAllowedInterval * 60;\r
2442                 }\r
2443         }\r
2444 \r
2445 #ifdef BNBT_MYSQL\r
2446         else if( m_iMySQLRefreshAllowedInterval > 0 && GetTime( ) > m_iMySQLRefreshAllowedNext )\r
2447         {\r
2448                 if( gbDebug )\r
2449                         UTIL_LogPrint( "mysql - refreshing allowed\n" );\r
2450 \r
2451                 if( m_pAllowed )\r
2452                         delete m_pAllowed;\r
2453 \r
2454                 m_pAllowed = new CAtomDicti( );\r
2455 \r
2456                 CMySQLQuery *pQuery = new CMySQLQuery( "SELECT bhash,bname FROM allowed" );\r
2457 \r
2458                 vector<string> vecQuery;\r
2459 \r
2460                 while( ( vecQuery = pQuery->nextRow( ) ).size( ) == 2 )\r
2461                 {\r
2462                         CAtomList *pList = new CAtomList( );\r
2463 \r
2464                         pList->addItem( new CAtomString( ) );\r
2465                         pList->addItem( new CAtomString( vecQuery[1] ) );\r
2466                         pList->addItem( new CAtomString( ) );\r
2467                         pList->addItem( new CAtomLong( ) );\r
2468                         pList->addItem( new CAtomInt( ) );\r
2469                         pList->addItem( new CAtomString( ) );\r
2470 \r
2471                         // 2006/12/04 fixed the memory leak...\r
2472                         m_pAllowed->setItem( vecQuery[0], pList );\r
2473                 }\r
2474 \r
2475                 delete pQuery;\r
2476 \r
2477                 m_iMySQLRefreshAllowedNext = GetTime( ) + m_iMySQLRefreshAllowedInterval;\r
2478         }\r
2479 \r
2480         if( m_iMySQLRefreshStatsInterval > 0 && GetTime( ) > m_iMySQLRefreshStatsNext )\r
2481         {\r
2482                 if( gbDebug )\r
2483                         UTIL_LogPrint( "mysql - refreshing stats\n" );\r
2484 \r
2485                 if( m_bMySQLOverrideDState )\r
2486                 {\r
2487                         CMySQLQuery mq01( "TRUNCATE TABLE hashes" );\r
2488 \r
2489                         if( !m_strAllowedDir.empty( ) )\r
2490                                 CMySQLQuery mq02( "INSERT INTO hashes (bhash) SELECT DISTINCT bhash FROM dstate" );\r
2491                         else\r
2492                         {\r
2493                                 if( m_iMySQLRefreshAllowedInterval > 0 )\r
2494                                         CMySQLQuery mq03( "INSERT INTO hashes (bhash) SELECT bhash FROM allowed" );\r
2495                                 else\r
2496                                         CMySQLQuery mq04( "INSERT INTO hashes (bhash) SELECT DISTINCT bhash FROM dstate" );\r
2497                         }\r
2498 \r
2499                         CMySQLQuery mq11( "TRUNCATE TABLE seeders" );\r
2500                         CMySQLQuery mq12( "INSERT INTO seeders (bhash) SELECT bhash FROM hashes" );\r
2501                         CMySQLQuery mq13( "REPLACE INTO seeders (bhash,bseeders) SELECT bhash,COUNT(*) FROM dstate WHERE bleft=0 GROUP BY bhash" );\r
2502                         CMySQLQuery mq14( "TRUNCATE TABLE leechers" );\r
2503                         CMySQLQuery mq15( "INSERT INTO leechers (bhash) SELECT bhash FROM hashes" );\r
2504                         CMySQLQuery mq16( "REPLACE INTO leechers (bhash,bleechers) SELECT bhash,COUNT(*) FROM dstate WHERE bleft!=0 GROUP BY bhash" );\r
2505                         CMySQLQuery mq17( "TRUNCATE TABLE torrents" );\r
2506                         CMySQLQuery mq18( "INSERT INTO torrents (bhash,bseeders,bleechers,bcompleted) SELECT hashes.bhash,bseeders,bleechers,bcompleted FROM hashes LEFT JOIN seeders USING(bhash) LEFT JOIN leechers USING(bhash) LEFT JOIN completed USING(bhash)" );\r
2507                 }\r
2508                 else\r
2509                 {\r
2510                         if( m_pDFile )\r
2511                         {\r
2512                                 map<string, CAtom *> *pmapDicti = m_pDFile->getValuePtr( );\r
2513 \r
2514                                 string strQuery;\r
2515 \r
2516                                 if( !pmapDicti->empty( ) )\r
2517                                         strQuery += "INSERT INTO torrents (bhash,bseeders,bleechers,bcompleted) VALUES";\r
2518 \r
2519                                 for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); )\r
2520                                 {\r
2521                                         if( (*i).second->isDicti( ) )\r
2522                                         {\r
2523                                                 map<string, CAtom *> *pmapPeersDicti = ( (CAtomDicti *)(*i).second )->getValuePtr( );\r
2524 \r
2525                                                 unsigned long iSeeders = 0;\r
2526                                                 unsigned long iLeechers = 0;\r
2527 \r
2528                                                 for( map<string, CAtom *> :: iterator j = pmapPeersDicti->begin( ); j != pmapPeersDicti->end( ); j++ )\r
2529                                                 {\r
2530                                                         if( (*j).second->isDicti( ) )\r
2531                                                         {\r
2532                                                                 CAtom *pLeft = ( (CAtomDicti *)(*j).second )->getItem( "left" );\r
2533 \r
2534                                                                 if( pLeft && pLeft->isLong( ) )\r
2535                                                                 {\r
2536                                                                         if( ( (CAtomLong *)pLeft )->getValue( ) == 0 )\r
2537                                                                                 iSeeders++;\r
2538                                                                         else\r
2539                                                                                 iLeechers++;\r
2540                                                                 }\r
2541                                                         }\r
2542                                                 }\r
2543 \r
2544                                                 unsigned long iCompleted = 0;\r
2545 \r
2546                                                 if( m_pCompleted )\r
2547                                                 {\r
2548                                                         CAtom *pCompleted = m_pCompleted->getItem( (*i).first );\r
2549 \r
2550                                                         if( pCompleted && pCompleted->isLong( ) )\r
2551                                                                 iCompleted = (unsigned long)( (CAtomLong *)pCompleted )->getValue( );\r
2552                                                 }\r
2553 \r
2554                                                 strQuery += " (\'" + UTIL_StringToMySQL( (*i).first ) + "\'," + CAtomInt( iSeeders ).toString( ) + "," + CAtomInt( iLeechers ).toString( ) + "," + CAtomInt( iCompleted ).toString( ) + ")";\r
2555 \r
2556                                                 if( ++i != pmapDicti->end( ) )\r
2557                                                         strQuery += ",";\r
2558                                         }\r
2559                                         else\r
2560                                                 i++;\r
2561                                 }\r
2562 //                              strQuery += " ON DUPLICATE KEY UPDATE bseeders=VALUES(bseeders), bleechers=VALUES(bleechers), bcompleted=VALUES(bcompleted) ;";\r
2563 \r
2564                                 if( !strQuery.empty( ) ){\r
2565                                         if( m_iTorrentTraderCompatibility == 1 )\r
2566                                                 strQuery += " ON DUPLICATE KEY UPDATE bseeders=VALUES(bseeders), bleechers=VALUES(bleechers), bcompleted=VALUES(bcompleted) ;";\r
2567                                         else\r
2568                                                 CMySQLQuery mq01( "TRUNCATE TABLE torrents" );\r
2569                                         \r
2570                                         CMySQLQuery mq02( strQuery );\r
2571                                 }\r
2572                         }\r
2573                 }\r
2574 \r
2575                 m_iMySQLRefreshStatsNext = GetTime( ) + m_iMySQLRefreshStatsInterval;\r
2576         }\r
2577 #endif\r
2578 \r
2579         if( m_iSaveScrapeInterval > 0 && GetTime( ) > m_iSaveScrapeNext )\r
2580         {\r
2581                 if( gbDebug )\r
2582                         UTIL_LogPrint( "tracker - saving scrape (%s)\n", m_strSCFile.c_str() );\r
2583 \r
2584                 saveScrapeFile( );\r
2585 \r
2586                 m_iSaveScrapeNext = GetTime( ) + m_iSaveScrapeInterval;\r
2587         }\r
2588 \r
2589         if( GetTime( ) > m_iNextCommandCycle && !m_strECommand.empty() )\r
2590         {\r
2591                 if ( m_bEnableExternal )\r
2592                 {\r
2593                         if( gbDebug )\r
2594                                 UTIL_LogPrint( "tracker - launching external command\n");\r
2595                         m_iNextCommandCycle = GetTime( ) + m_iECommandCycle;\r
2596 #ifdef WIN32\r
2597                         STARTUPINFO si;\r
2598                         PROCESS_INFORMATION pi;\r
2599                         ZeroMemory( &si, sizeof( STARTUPINFO ) );\r
2600                         si.cb = sizeof( STARTUPINFO );\r
2601                         si.dwFlags = STARTF_USESHOWWINDOW;\r
2602                         si.wShowWindow = SW_SHOWNORMAL;\r
2603                         CreateProcess( NULL, (LPSTR )m_strECommand.c_str(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi );\r
2604 #else\r
2605 //                      execvp( m_strECommand.c_str(), {(char *) 0 } );\r
2606 #endif\r
2607                 }\r
2608         }\r
2609 \r
2610         if( GetTime( ) > m_iSaveDFileNext )\r
2611         {\r
2612                 if( gbDebug )\r
2613                         UTIL_LogPrint( "tracker - saving dfile (%s)\n", m_strDFile.c_str( ) );\r
2614 \r
2615                 saveDFile( );\r
2616 \r
2617                 m_iSaveDFileNext = GetTime( ) + m_iSaveDFileInterval;\r
2618         }\r
2619 \r
2620         if( ( !m_strStaticHeaderFile.empty( ) || !m_strStaticFooterFile.empty( ) || !m_strRobotsFile.empty( ) || !m_strIconFile.empty() ) && GetTime( ) > m_iRefreshStaticNext )\r
2621         {\r
2622                 if( gbDebug )\r
2623                         UTIL_LogPrint( "tracker - refreshing static header, static footer, and robots.txt\n" );\r
2624 \r
2625                 if( !m_strStaticHeaderFile.empty( ) )\r
2626                         m_strStaticHeader = UTIL_ReadFile( m_strStaticHeaderFile.c_str( ) );\r
2627 \r
2628                 if( !m_strStaticFooterFile.empty( ) )\r
2629                         m_strStaticFooter = UTIL_ReadFile( m_strStaticFooterFile.c_str( ) );\r
2630 \r
2631                 if( !m_strRobotsFile.empty( ) )\r
2632                         m_strRobots = UTIL_ReadFile( m_strRobotsFile.c_str( ) );\r
2633 \r
2634                 if( !m_strIconFile.empty( ) )\r
2635                         m_strFavicon = UTIL_ReadFile( m_strIconFile.c_str( ) );\r
2636 \r
2637                 parseClientBanList();\r
2638                 parseIPBanList();\r
2639 \r
2640 \r
2641                 m_iRefreshStaticNext = GetTime( ) + m_iRefreshStaticInterval * 60;\r
2642         }\r
2643 \r
2644         if( GetTime( ) > m_iDownloaderTimeOutNext )\r
2645         {\r
2646                 if( gbDebug )\r
2647                         UTIL_LogPrint( "tracker - expiring downloaders\n" );\r
2648 \r
2649                 expireDownloaders( );\r
2650 \r
2651                 m_iDownloaderTimeOutNext = GetTime( ) + m_iDownloaderTimeOutInterval;\r
2652         }\r
2653 \r
2654         if( !m_strDumpXMLFile.empty( ) && GetTime( ) > m_iDumpXMLNext )\r
2655         {\r
2656                 if( gbDebug )\r
2657                         UTIL_LogPrint( "tracker - dumping xml\n" );\r
2658 \r
2659                 saveXML( );\r
2660 \r
2661                 m_iDumpXMLNext = GetTime( ) + m_iDumpXMLInterval;\r
2662         }\r
2663 \r
2664         if( GetTime( ) > m_iRefreshFastCacheNext )\r
2665                 {\r
2666                         RefreshFastCache( );\r
2667 \r
2668                         m_iRefreshFastCacheNext = GetTime( ) + m_iRefreshFastCacheInterval;\r
2669                 }\r
2670 \r
2671 \r
2672         // queued announces\r
2673 \r
2674         if( gpLinkServer || gpLink )\r
2675         {\r
2676                 m_mtxQueued.Claim( );\r
2677                 vector<struct announce_t> vecTemp = m_vecQueued;\r
2678                 m_vecQueued.clear( );\r
2679                 m_mtxQueued.Release( );\r
2680 \r
2681                 for( vector<struct announce_t> :: iterator i = vecTemp.begin( ); i != vecTemp.end( ); i++ )\r
2682                 {\r
2683                         if( m_pAllowed )\r
2684                         {\r
2685                                 if( !m_pAllowed->getItem( (*i).strInfoHash ) )\r
2686                                         continue;\r
2687                         }\r
2688 \r
2689                         Announce( *i );\r
2690                 }\r
2691         }\r
2692         //RSS Support - Code by labarks\r
2693         if( m_iDumpRSSInterval && GetTime( ) > m_iDumpRSSNext )\r
2694                 runSaveRSS( );\r
2695         //end addition\r
2696 }\r