Updated init script.
[dtbartle/bnbt.git] / tracker_upload.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 #include "bnbt.h"\r
25 #include "atom.h"\r
26 #include "bencode.h"\r
27 #include "client.h"\r
28 #include "tracker.h"\r
29 #include "util.h"\r
30 \r
31 void CTracker :: serverResponseUploadGET( struct request_t *pRequest, struct response_t *pResponse, user_t user )\r
32 {\r
33         struct bnbttv btv = UTIL_CurrentTime( );\r
34 \r
35         pResponse->strCode = "200 OK";\r
36 \r
37         pResponse->mapHeaders.insert( pair<string, string>( "Content-Type", string( "text/html; charset=" ) + gstrCharSet ) );\r
38 \r
39         pResponse->strContent += "<html>\n";\r
40         pResponse->strContent += "<head>\n";\r
41         // The Trintiy Tracker - Modification Begins\r
42         // The following changes "BNBT File Uploader" to "BNBT Torrent Uplaoder"\r
43         // in the Title Bar of the web browser\r
44 \r
45         if ( !gstrTrackerTitle.empty( ) )\r
46                 pResponse->strContent += "<title>" + gstrTrackerTitle + " - Torrent Uploader</title>\n";\r
47         else\r
48                 pResponse->strContent += "<title>BNBT Torrent Uploader</title>\n";\r
49 \r
50         /* Original Source Code:\r
51         pResponse->strContent += "<title>BNBT File Uploader</title>\n";\r
52         */\r
53 \r
54         // ------------------------------------------------- End of Modification\r
55 \r
56         // The Trinity Tracker - Addition Begins\r
57         // The following adds an RTT link\r
58         // when viewing the UPLOAD TORRENT page (upload.html)\r
59 \r
60         pResponse->strContent += "<p><a href=\"/index.html\">Return to Tracker</a></p>\n";\r
61 \r
62         // ------------------------------------------------- End of Addition\r
63 \r
64         if( !gstrStyle.empty( ) )\r
65                 pResponse->strContent += "<link rel=stylesheet type=\"text/css\" href=\"" + gstrStyle + "\">\n";\r
66 \r
67         pResponse->strContent += "</head>\n";\r
68         pResponse->strContent += "<body>\n";\r
69 \r
70         if( !m_bDisableLogon )\r
71         {\r
72                 if( user.strLogin.empty( ) )\r
73                         pResponse->strContent += "<p class=\"login1_index\">You are not logged in. Click <a href=\"/login.html\">here</a> to login.</p>\n";\r
74                 else\r
75                         pResponse->strContent += "<p class=\"login2_index\">You are logged in as <span class=\"username\">" + UTIL_RemoveHTML( user.strLogin ) + "</span>. Click <a href=\"/login.html?logout=1\">here</a> to logout.</p>\n";\r
76         }\r
77 \r
78         // The Trinity Edition - Modification Begins\r
79         // The following changes "BNBT File Uploader" to "BNBT Torrent Uploader"\r
80         // in the <h3> tag\r
81 \r
82         if ( !gstrTrackerTitle.empty( ) )\r
83                 pResponse->strContent += "<h3>" + gstrTrackerTitle + " - Torrent Uploader</h3>\n";\r
84         else\r
85                 pResponse->strContent += "<h3>BNBT Torrent Uploader</h3>\n";\r
86 \r
87         /* Original Source Code:\r
88         pResponse->strContent += "<h3>BNBT File Uploader</h3>\n";\r
89         */\r
90 \r
91         if( user.iAccess & ACCESS_UPLOAD )\r
92         {\r
93                 if( m_strUploadDir.empty( ) )\r
94                 {\r
95                         pResponse->strContent += "<p class=\"denied\">This tracker does not allow file uploads. Click <a href=\"/index.html\">here</a> to return to the tracker.</p>\n";\r
96 \r
97                         if( m_bGen )\r
98                                 pResponse->strContent += "<p class=\"gen\">Generated in " + UTIL_ElapsedTimeStr( btv, UTIL_CurrentTime( ) ) + " seconds.</p>\n";\r
99 \r
100                         pResponse->strContent += "</body>\n";\r
101                         pResponse->strContent += "</html>\n";\r
102 \r
103                         return;\r
104                 }\r
105                 else if( m_iMaxTorrents > 0 )\r
106                 {\r
107                         if( m_pAllowed && m_pAllowed->getValuePtr( )->size( ) >= (unsigned int)m_iMaxTorrents )\r
108                                 {\r
109                                         pResponse->strContent += "<p class=\"denied\">This tracker has reached its torrent limit. Click <a href=\"/index.html\">here</a> to return to the tracker.</p>\n";\r
110 \r
111                                         if( m_bGen )\r
112                                                 pResponse->strContent += "<p class=\"gen\">Generated in " + UTIL_ElapsedTimeStr( btv, UTIL_CurrentTime( ) ) + " seconds.</p>\n";\r
113 \r
114                                         pResponse->strContent += "</body>\n";\r
115                                         pResponse->strContent += "</html>\n";\r
116 \r
117                                         return;\r
118                                 }\r
119                 }\r
120 \r
121                 pResponse->strContent += "<form method=\"post\" action=\"/upload.html\" enctype=\"multipart/form-data\">\n";\r
122                 // The Trinity Edition - Modification Begins\r
123                 // The following changes have been made:\r
124 \r
125                 // 1. Field Descriptions now appear above the input fields\r
126                 // 2. Information regarding Optional input has been moved to a list below\r
127                 // 3. Modified the Tag field descriptor to read "Tag/Category"\r
128                 // 4. When FORCE_ANNOUNCE_URL is null/empty, the tracker's Announce URL will be displayed\r
129                 //    a CSS class "announce" is also set for this string, which can be used to HIDE the \r
130                 //    "Announce URL" by using the following CSS command:\r
131                 //    .announce{display:none}\r
132                 // 5. Added a CANCEL button after the UPLOAD button.\r
133 \r
134                 pResponse->strContent += "Torrent File to Upload<br>\n";\r
135                 pResponse->strContent += "<input name=\"torrent\" type=file size=50><br><br>\n";                \r
136                 pResponse->strContent += "Name (Optional - See Note Below)<br>\n";\r
137                 pResponse->strContent += "<input name=\"name\" type=text size=64 maxlength=" + CAtomInt( MAX_FILENAME_LEN ).toString( ) + "> <br><br>\n";            \r
138 \r
139                 if( m_bAllowInfoLink )\r
140                 {\r
141             pResponse->strContent += "Informational Link (Optional - See Note Below)<br>\n";\r
142                         pResponse->strContent += "<input name=\"infolink\" type=text size=64 maxlength=" + CAtomInt( MAX_INFOLINK_LEN ).toString( ) + " value=\"\"> <br><br>\n";\r
143                 }\r
144 \r
145         if( m_vecTags.size( ) > 0 )\r
146                         pResponse->strContent += "Tag/Category <select name=\"tag\">\n";\r
147 \r
148                 for( vector< pair<string, string> > :: iterator i = m_vecTags.begin( ); i != m_vecTags.end( ); i++ )\r
149                         pResponse->strContent += "<option>" + (*i).first + "\n";\r
150 \r
151                 if( m_vecTags.size( ) > 0 )\r
152                         pResponse->strContent += "</select>\n";\r
153                 \r
154                 pResponse->strContent += "<ul>\n";\r
155                 pResponse->strContent += "<li>If <b>Name</b> is left blank, the torrent filename will be used.</li>\n";\r
156                 pResponse->strContent += "<li>Names must be less than " + CAtomInt( MAX_FILENAME_LEN ).toString( ) + " characters long</li>\n";\r
157                 pResponse->strContent += "<li>HTML cannot be used in these fields.</li>\n";\r
158                 pResponse->strContent += "<li>Informational Links must start with <b>http://</b></li>\n";\r
159                 pResponse->strContent += "<li><strong>Max. File Size:</strong> " + UTIL_BytesToString( giMaxRecvSize ) + "</li>\n";\r
160 \r
161                 if( !m_strForceAnnounceURL.empty( ) )\r
162                         pResponse->strContent += "<li><strong>Auto Announce URL:</strong> " + UTIL_RemoveHTML( m_strForceAnnounceURL ) + "</li>\n";\r
163 \r
164                 else {\r
165             pResponse->strContent += "<script type=\"text/javascript\" language=\"javascript\">\n";\r
166                         pResponse->strContent += "document.write(\"<li class=announce><strong>Announce URL:</strong> http://\" + parent.location.host + \"/announce</li>\");";\r
167                         pResponse->strContent += "\n";\r
168                         pResponse->strContent += "</script>\n";\r
169                 }\r
170 \r
171                 pResponse->strContent += "</ul>\n";\r
172         \r
173                 pResponse->strContent += "<input type=submit value=\"Upload\">\n";\r
174                 pResponse->strContent += "<input type=button value=\"Cancel\" onClick=\"javascript:history.back()\">\n";\r
175 \r
176                 /* Original Source Code:\r
177                 pResponse->strContent += "<input name=\"torrent\" type=file size=24> Torrent<br><br>\n";\r
178                 pResponse->strContent += "<input name=\"name\" type=text size=64 maxlength=" + CAtomInt( MAX_FILENAME_LEN ).toString( ) + "> Name (optional - if blank, the name will be taken from the filename)<br><br>\n";\r
179 \r
180                 if( m_bAllowInfoLink )\r
181                         pResponse->strContent += "<input name=\"infolink\" type=text size=64 maxlength=" + CAtomInt( MAX_INFOLINK_LEN ).toString( ) + "> Info Link (optional)<br><br>\n";\r
182 \r
183                 if( m_vecTags.size( ) > 0 )\r
184                         pResponse->strContent += "<select name=\"tag\">\n";\r
185 \r
186                 for( unsigned long i = 0; i < m_vecTags.size( ); i++ )\r
187                         pResponse->strContent += "<option>" + m_vecTags[i].strTag + "\n";\r
188 \r
189                 if( m_vecTags.size( ) > 0 )\r
190                         pResponse->strContent += "</select> Tag\n";\r
191 \r
192                 pResponse->strContent += "<ul>\n";\r
193                 pResponse->strContent += "<li>Names must be less than " + CAtomInt( MAX_FILENAME_LEN ).toString( ) + " characters long</li>\n";\r
194                 pResponse->strContent += "<li>No HTML</li>\n";\r
195                 pResponse->strContent += "<li><strong>Max. File Size:</strong> " + UTIL_BytesToString( MAX_RECV_SIZE ) + "</li>\n";\r
196 \r
197                 if( !m_strForceAnnounceURL.empty( ) )\r
198                         pResponse->strContent += "<li><strong>Auto Announce URL:</strong> " + UTIL_RemoveHTML( m_strForceAnnounceURL ) + "</li>\n";\r
199 \r
200                 pResponse->strContent += "</ul>\n";\r
201                 pResponse->strContent += "<input type=submit value=\"Upload\">\n";\r
202                 */\r
203 \r
204                 // ------------------------------------------------- End of Modification\r
205 \r
206                 pResponse->strContent += "</form>\n";\r
207         }\r
208         else\r
209                 pResponse->strContent += "<p class=\"denied\">You are not authorized to view this page.</p>\n";\r
210 \r
211         if( m_bGen )\r
212                 pResponse->strContent += "<p class=\"gen\">Generated in " + UTIL_ElapsedTimeStr( btv, UTIL_CurrentTime( ) ) + " seconds.</p>\n";\r
213 \r
214         pResponse->strContent += "</body>\n";\r
215         pResponse->strContent += "</html>\n";\r
216 }\r
217 \r
218 void CTracker :: serverResponseUploadPOST( struct request_t *pRequest, struct response_t *pResponse, CAtomList *pPost, user_t user )\r
219 {\r
220         struct bnbttv btv = UTIL_CurrentTime( );\r
221 \r
222         if( m_strUploadDir.empty( ) || !( user.iAccess & ACCESS_UPLOAD ) )\r
223         {\r
224                 pResponse->strCode = "403 Forbidden";\r
225 \r
226                 return;\r
227         }\r
228 \r
229         if( m_iMaxTorrents > 0 )\r
230         {\r
231                 if( m_pAllowed && m_pAllowed->getValuePtr( )->size( ) >= (unsigned int)m_iMaxTorrents )\r
232                         {\r
233                                 pResponse->strCode = "403 Forbidden";\r
234 \r
235                                 return;\r
236                         }\r
237                 }\r
238 \r
239         string strFile;\r
240         string strTorrent;\r
241         string strTag;\r
242         string strPostedName;\r
243         string strPostedInfoLink;\r
244 \r
245         if( pPost )\r
246         {\r
247                 vector<CAtom *> vecSegs = pPost->getValue( );\r
248 \r
249                 for( unsigned long i = 0; i < vecSegs.size( ); i++ )\r
250                 {\r
251                         if( vecSegs[i]->isDicti( ) )\r
252                         {\r
253                                 CAtomDicti *pSeg = (CAtomDicti *)vecSegs[i];\r
254 \r
255                                 CAtom *pDisp = ( (CAtomDicti *)vecSegs[i] )->getItem( "disposition" );\r
256                                 CAtom *pDat = ( (CAtomDicti *)vecSegs[i] )->getItem( "data" );\r
257 \r
258                                 if( pDisp && pDisp->isDicti( ) && pDat )\r
259                                 {\r
260                                         CAtom *pName = ( (CAtomDicti *)pDisp )->getItem( "name" );\r
261 \r
262                                         if( pName )\r
263                                         {\r
264                                                 string strName = pName->toString( );\r
265 \r
266                                                 if( strName == "torrent" )\r
267                                                 {\r
268                                                         CAtom *pFile = ( (CAtomDicti *)pDisp )->getItem( "filename" );\r
269 \r
270                                                         if( pFile )\r
271                                                         {\r
272                                                                 // the path is local to the peer\r
273 \r
274                                                                 strFile = UTIL_StripPath( pFile->toString( ) );\r
275 \r
276                                                                 strTorrent = pDat->toString( );\r
277                                                         }\r
278                                                         else\r
279                                                         {\r
280                                                                 pResponse->strCode = "400 Bad Request";\r
281 \r
282                                                                 return;\r
283                                                         }\r
284                                                 }\r
285                                                 else if( strName == "tag" )\r
286                                                         strTag = pDat->toString( );\r
287                                                 else if( strName == "name" )\r
288                                                         strPostedName = pDat->toString( ).substr( 0, MAX_FILENAME_LEN );\r
289                                                 else if( strName == "infolink" )\r
290                                                         strPostedInfoLink = pDat->toString( ).substr( 0, MAX_INFOLINK_LEN );\r
291                                         }\r
292                                         else\r
293                                         {\r
294                                                 pResponse->strCode = "400 Bad Request";\r
295 \r
296                                                 return;\r
297                                         }\r
298                                 }\r
299                         }\r
300                 }\r
301         }\r
302         else\r
303         {\r
304                 pResponse->strCode = "400 Bad Request";\r
305 \r
306                 return;\r
307         }\r
308 \r
309         pResponse->strCode = "200 OK";\r
310 \r
311         pResponse->mapHeaders.insert( pair<string, string>( "Content-Type", string( "text/html; charset=" ) + gstrCharSet ) );\r
312 \r
313         pResponse->strContent += "<html>\n";\r
314         pResponse->strContent += "<head>\n";\r
315         if ( !gstrTrackerTitle.empty( ) )\r
316                 pResponse->strContent += "<title>" + gstrTrackerTitle + " - Torrent Uploader</title>\n";\r
317         else\r
318                 pResponse->strContent += "<title>BNBT Torrent Uploader</title>\n";\r
319 \r
320         if( !gstrStyle.empty( ) )\r
321                 pResponse->strContent += "<link rel=stylesheet type=\"text/css\" href=\"" + gstrStyle + "\">\n";\r
322 \r
323         pResponse->strContent += "</head>\n";\r
324         pResponse->strContent += "<body>\n";\r
325 \r
326         if( user.strLogin.empty( ) )\r
327                 pResponse->strContent += "<p class=\"login1_upload\">You are not logged in. Click <a href=\"/login.html\">here</a> to login.</p>\n";\r
328         else\r
329                 pResponse->strContent += "<p class=\"login2_upload\">You are logged in as <span class=\"username\">" + UTIL_RemoveHTML( user.strLogin ) + "</span>. Click <a href=\"/login.html?logout=1\">here</a> to logout.</p>\n";\r
330 \r
331         string strPath = m_strUploadDir + strFile;\r
332 \r
333         string :: size_type iExt = strFile.rfind( "." );\r
334 \r
335         string strExt;\r
336 \r
337         if( iExt != string :: npos )\r
338                 strExt = strFile.substr( iExt );\r
339 \r
340         if( strTorrent.empty( ) )\r
341         {\r
342                 pResponse->strContent += "<h3>Upload Failed</h3>\n";\r
343                 pResponse->strContent += "<p>The uploaded file is corrupt or invalid. Click <a href=\"/upload.html\">here</a> to return to the upload page.</p>\n";\r
344         }\r
345         else if( strExt != ".torrent" )\r
346         {\r
347                 pResponse->strContent += "<h3>Upload Failed</h3>\n";\r
348                 pResponse->strContent += "<p>The uploaded file is not a .torrent file. Click <a href=\"/upload.html\">here</a> to return to the upload page.</p>\n";\r
349         }\r
350         else if( !checkTag( strTag ) )\r
351         {\r
352                 pResponse->strContent += "<h3>Upload Failed</h3>\n";\r
353                 pResponse->strContent += "<p>The file tag is invalid. Click <a href=\"/upload.html\">here</a> to return to the upload page.</p>\n";\r
354         }\r
355         else if( UTIL_CheckFile( strPath.c_str( ) ) )\r
356         {\r
357                 pResponse->strContent += "<h3>Upload Failed</h3>\n";\r
358                 pResponse->strContent += "<p>The uploaded file already exists. Click <a href=\"/upload.html\">here</a> to return to the upload page.</p>\n";\r
359         }\r
360         else\r
361         {\r
362                 CAtom *pTorrent = Decode( strTorrent );\r
363 \r
364                 if( pTorrent && pTorrent->isDicti( ) )\r
365                 {\r
366                         string strInfoHash = UTIL_InfoHash( pTorrent );\r
367 \r
368                         if( !strInfoHash.empty( ) )\r
369                         {\r
370                                 if( m_pDFile->getItem( strInfoHash ) )\r
371                                 {\r
372                                         pResponse->strContent += "<h3>Upload Failed</h3>\n";\r
373                                         pResponse->strContent += "<p>A file with the uploaded file's info hash already exists. Click <a href=\"/upload.html\">here</a> to return to the upload page.</p>\n";\r
374                                 }\r
375                                 else\r
376                                 {\r
377                                         if( !m_strForceAnnounceURL.empty( ) )\r
378                                                 ( (CAtomDicti *)pTorrent )->setItem( "announce", new CAtomString( m_strForceAnnounceURL ) );\r
379 \r
380                                         UTIL_MakeFile( strPath.c_str( ), Encode( pTorrent ) );\r
381 \r
382                                         addTag( strInfoHash, strTag, strPostedName, user.strLogin, strPostedInfoLink );\r
383 \r
384                                         pResponse->strContent += "<h3>Upload Successful</h3>\n";\r
385 \r
386                                         // The Trinity Edition - Addition Begins\r
387                                         // The following adds an RTT link and a link to Upload Another Torrent\r
388                                         // when a user has just SUCCESSFULLY UPLOADED A TORRENT - regardless of parsing method used\r
389 \r
390                                         pResponse->strContent += "<p><a href=\"/upload.html\">Upload Another Torrent</a> | <a href=\"/index.html\">Return To Tracker</a></p>\n\n";\r
391 \r
392                                         // ------------------------------------------------- End of Addition\r
393 \r
394                                         // The Trinity Edition - Modification Begins\r
395                                         // The following removes the multiple RTT links that appear based on parsing method used\r
396 \r
397                                         if( m_bParseOnUpload )\r
398                                         {\r
399                                                 if( m_pAllowed )\r
400                                                         parseTorrent( strPath.c_str( ) );\r
401 \r
402                                                 pResponse->strContent += "<p>The uploaded file is ready. You should start seeding it now.</p>\n";\r
403                                         }\r
404                                         else\r
405                                         {\r
406                                                 pResponse->strContent += "<p>The uploaded file will be ready in " + CAtomInt( m_iParseAllowedInterval ).toString( );\r
407 \r
408                                                 if( m_iParseAllowedInterval == 1 )\r
409                                                         pResponse->strContent += " minute. You should start seeding it as soon as possible.</p>\n";\r
410                                                 else\r
411                                                         pResponse->strContent += " minutes. You should start seeding it as soon as possible.</p>\n";\r
412                                         }\r
413 \r
414                                         /* Original Source Code:\r
415                                         if( m_bParseOnUpload )\r
416                                         {\r
417                                                 if( m_pAllowed )\r
418                                                         parseTorrent( strPath.c_str( ) );\r
419 \r
420                                                 pResponse->strContent += "<p>The uploaded file is ready. You should start seeding it now. Click <a href=\"/index.html\">here</a> to return to the tracker.</p>\n";\r
421                                         }\r
422                                         else\r
423                                         {\r
424                                                 pResponse->strContent += "<p>The uploaded file will be ready in " + CAtomInt( m_iParseAllowedInterval ).toString( );\r
425 \r
426                                                 if( m_iParseAllowedInterval == 1 )\r
427                                                         pResponse->strContent += " minute. You should start seeding it as soon as possible. Click <a href=\"/index.html\">here</a> to return to the tracker.</p>\n";\r
428                                                 else\r
429                                                         pResponse->strContent += " minutes. You should start seeding it as soon as possible. Click <a href=\"/index.html\">here</a> to return to the tracker.</p>\n";\r
430                                         }\r
431                                         */\r
432 \r
433                                         // ------------------------------------------------- End of Modification\r
434 \r
435                                         // The Trinity Edition - Addition Begins\r
436                                         // The following displays SEEDING INSTRUCTIONS after a user successfully uploads a torrent\r
437 \r
438                     pResponse->strContent += "<h3>Seeding Instructions</h3>\n";\r
439                     pResponse->strContent += "To begin seeding your torrent...\n";\r
440                                         pResponse->strContent += "<ol>\n";\r
441                                         pResponse->strContent += "<li>Locate and double-click the torrent file on your hard drive.&dagger;</li>\n";\r
442                                         pResponse->strContent += "<li>Choose the save location where the torrented files exist already.</li>\n";\r
443                                         pResponse->strContent += "<li>Your client will check the existing data and should then say <b>Download Complete</b>.</li>\n";\r
444                                         pResponse->strContent += "<li>Your client should then contact the tracker and begin seeding to others.</li>\n";\r
445                                         pResponse->strContent += "</ol>\n";\r
446                                         pResponse->strContent += "<p>To verify that you have correctly started to seed your torrent,<br>\n";\r
447                     pResponse->strContent += "<a href=\"/index.html\">Return to the Tracker</a> and examine the <u>SDs</u> (Seeders) column.</p>\n";\r
448                                         pResponse->strContent += "<table><tr><td style=\"font-weight:normal; border:1px solid black; padding:10px\">\n";\r
449                                         pResponse->strContent += "<p>&dagger; Depending on this tracker's configuration, the torrent may not<br>\n";\r
450                                         pResponse->strContent += "show up until it has been seeded, and therefore cannot be<br>\n";\r
451                                         pResponse->strContent += "initially started using the [DL] link on the tracker's main page.</p>\n";\r
452                                         pResponse->strContent += "</td></tr></table>\n";\r
453 \r
454                                         // ------------------------------------------------- End of Addition\r
455 \r
456                                         UTIL_LogPrint( "%s uploaded %s\n", inet_ntoa( pRequest->sin.sin_addr ), strFile.c_str( ) );\r
457                                 }\r
458                         }\r
459                         else\r
460                         {\r
461                                 pResponse->strContent += "<h3>Upload Failed</h3>\n";\r
462                                 pResponse->strContent += "<p>The uploaded file is corrupt or invalid. Click <a href=\"/upload.html\">here</a> to return to the upload page.</p>\n";\r
463                         }\r
464                 }\r
465                 else\r
466                 {\r
467                         pResponse->strContent += "<h3>Upload Failed</h3>\n";\r
468                         pResponse->strContent += "<p>The uploaded file is corrupt or invalid. Click <a href=\"/upload.html\">here</a> to return to the upload page.</p>\n";\r
469                 }\r
470 \r
471                 if( pTorrent )\r
472                         delete pTorrent;\r
473         }\r
474 \r
475         if( m_bGen )\r
476                 pResponse->strContent += "<p class=\"gen\">Generated in " + UTIL_ElapsedTimeStr( btv, UTIL_CurrentTime( ) ) + " seconds.</p>\n";\r
477 \r
478         pResponse->strContent += "</body>\n";\r
479         pResponse->strContent += "</html>\n";\r
480 }\r