8e9ed451e2ba41c99cbb5146b8135b4f5947b194
[dtbartle/bnbt.git] / util.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 #ifdef __GNUWIN32__\r
25  #define unlink remove\r
26 #endif\r
27 \r
28 #ifndef WIN32\r
29  #include <sys/time.h>\r
30 #endif\r
31 \r
32 #include <stdarg.h>\r
33 \r
34 #include "bnbt.h"\r
35 #include "atom.h"\r
36 #include "bencode.h"\r
37 #include "sha1.h"\r
38 #include "tracker.h"\r
39 #include "util.h"\r
40 \r
41 void UTIL_LogPrint( const char *format, ... )\r
42 {\r
43         time_t tNow = time( NULL );\r
44         char *szTime = asctime( localtime( &tNow ) );\r
45         szTime[strlen( szTime ) - 1] = '\0';\r
46 \r
47         gmtxOutput.Claim( );\r
48 \r
49         printf( "[%s] ", szTime );\r
50 \r
51         va_list args;\r
52         va_start( args, format );\r
53         vprintf( format, args );\r
54         va_end( args );\r
55 \r
56         if( !gstrErrorLogDir.empty( ) && !gstrErrorLogFilePattern.empty( ) )\r
57         {\r
58                 char pTime[256];\r
59                 memset( pTime, 0, sizeof( char ) * 256 );\r
60                 strftime( pTime, sizeof( char ) * 256, gstrErrorLogFilePattern.data( ), localtime( &tNow ) );\r
61 \r
62                 string strFile = gstrErrorLogDir + pTime;\r
63 \r
64                 if( gstrErrorLogFile != strFile )\r
65                 {\r
66                         // start a new log\r
67 \r
68                         gstrErrorLogFile = strFile;\r
69 \r
70                         if( gpErrorLog )\r
71                         {\r
72                                 fclose( gpErrorLog );\r
73 \r
74                                 gpErrorLog = NULL;\r
75                         }\r
76 \r
77                         gpErrorLog = fopen( strFile.c_str( ), "ab" );\r
78                 }\r
79 \r
80                 if( gpErrorLog )\r
81                 {\r
82                         fprintf( gpErrorLog, "[%s] ", szTime );\r
83 \r
84                         va_list args;\r
85                         va_start( args, format );\r
86                         vfprintf( gpErrorLog, format, args );\r
87                         va_end( args );\r
88 \r
89                         giErrorLogCount++;\r
90 \r
91                         if( giErrorLogCount % giFlushInterval == 0 )\r
92                                 fflush( gpErrorLog );\r
93                 }\r
94         }\r
95 \r
96         gmtxOutput.Release( );\r
97 }\r
98 \r
99 //addition by labarks\r
100 string UTIL_Date( )\r
101 {\r
102         time_t tNow = time( NULL );\r
103         string strDate;\r
104         \r
105         char pTime[256];\r
106         memset( pTime, 0, sizeof( char ) * 256 );\r
107         strftime( pTime, sizeof( char ) * 256, "%a, %d %b %Y %H:%M:%S", localtime( &tNow ) );\r
108         #if defined( __APPLE__ ) || defined( __FREEBSD__ )\r
109                         long timezone = -( localtime( &tNow )->tm_gmtoff );\r
110         #endif\r
111 \r
112         // timezone has the wrong sign, change it\r
113                         \r
114         if( timezone > 0 )\r
115                 strDate = (string) pTime + " -" + addzero( abs( timezone / 3600 ) % 60 ) + addzero( abs( timezone / 60 ) % 60 );\r
116         else\r
117                 strDate = (string) pTime + " +" + addzero( abs( timezone / 3600 ) % 60 ) + addzero( abs( timezone / 60 ) % 60 );\r
118 \r
119         return strDate;\r
120 }\r
121 \r
122 string UTIL_AddedToDate( string strAdded )\r
123 {\r
124         time_t rawtime;\r
125         struct tm * tDate; //2004-05-09 01:30:21\r
126         string strDate;\r
127         \r
128         time ( &rawtime );\r
129         tDate = localtime ( &rawtime );\r
130         tDate->tm_year = UTIL_StringToInt( strAdded.substr(0,4) ) - 1900;\r
131         tDate->tm_mon  = UTIL_StringToInt( strAdded.substr(5,2) ) - 1;\r
132         tDate->tm_mday  = UTIL_StringToInt( strAdded.substr(8,2) );\r
133         tDate->tm_hour = UTIL_StringToInt( strAdded.substr(11,2) );\r
134         tDate->tm_min  = UTIL_StringToInt( strAdded.substr(14,2) );\r
135         tDate->tm_sec  = UTIL_StringToInt( strAdded.substr(17,2) );\r
136         mktime(tDate);\r
137         \r
138         char pTime[256];\r
139         memset( pTime, 0, sizeof( char ) * 256 );\r
140         strftime( pTime, sizeof( char ) * 256, "%a, %d %b %Y %H:%M:%S", tDate );\r
141 #if defined( __APPLE__ ) || defined( __FREEBSD__ )\r
142         time_t tNow = time( NULL );\r
143         long timezone = -( localtime( &tNow )->tm_gmtoff );\r
144 #endif\r
145 \r
146         // timezone has the wrong sign, change it\r
147                         \r
148         if( timezone > 0 )\r
149                 strDate = (string) pTime + " -" + addzero( abs( timezone / 3600 ) % 60 ) + addzero( abs( timezone / 60 ) % 60 );\r
150         else\r
151                 strDate = (string) pTime + " +" + addzero( abs( timezone / 3600 ) % 60 ) + addzero( abs( timezone / 60 ) % 60 );\r
152 \r
153         return strDate;\r
154 }\r
155 \r
156 string addzero( unsigned long iLong ) //for timezones used in UTIL_Date and UTIL_AddedToDate\r
157 {\r
158         if( iLong < 10 )\r
159                 return (string) "0" + string() + UTIL_LongToString( iLong );\r
160         else\r
161                 return UTIL_LongToString( iLong );\r
162 }\r
163 //end addition\r
164 \r
165 void UTIL_AccessLogPrint( string strIP, string strUser, string strRequest, int iStatus, int iBytes )\r
166 {\r
167         gmtxOutput.Claim( );\r
168 \r
169         if( !gstrAccessLogDir.empty( ) && !gstrAccessLogFilePattern.empty( ) )\r
170         {\r
171                 time_t tNow = time( NULL );\r
172 \r
173                 char pTime[256];\r
174                 memset( pTime, 0, sizeof( char ) * 256 );\r
175                 strftime( pTime, sizeof( char ) * 256, gstrAccessLogFilePattern.data( ), localtime( &tNow ) );\r
176 \r
177                 string strFile = gstrAccessLogDir + pTime;\r
178 \r
179                 if( gstrAccessLogFile != strFile )\r
180                 {\r
181                         // start a new log\r
182 \r
183                         gstrAccessLogFile = strFile;\r
184 \r
185                         if( gpAccessLog )\r
186                         {\r
187                                 fclose( gpAccessLog );\r
188 \r
189                                 gpAccessLog = NULL;\r
190                         }\r
191 \r
192                         gpAccessLog = fopen( strFile.c_str( ), "ab" );\r
193 \r
194                         if( !gpAccessLog )\r
195                                 UTIL_LogPrint( "log warning - unable to open %s for writing\n", strFile.c_str( ) );\r
196                 }\r
197 \r
198                 if( gpAccessLog )\r
199                 {\r
200                         fprintf( gpAccessLog, "%s - ", strIP.c_str( ) );\r
201 \r
202                         if( strUser.empty( ) )\r
203                                 fprintf( gpAccessLog, "- " );\r
204                         else\r
205                                 fprintf( gpAccessLog, "%s ", strUser.c_str( ) );\r
206 \r
207                         strftime( pTime, sizeof( char ) * 256, "%d/%b/%Y:%H:%M:%S", localtime( &tNow ) );\r
208 \r
209 #if defined( __APPLE__ ) || defined( __FREEBSD__ )\r
210                         long timezone = -( localtime( &tNow )->tm_gmtoff );\r
211 #endif\r
212 \r
213                         // timezone has the wrong sign, change it\r
214 \r
215                         if( timezone > 0 )\r
216                                 fprintf( gpAccessLog, "[%s -%02d%02d] ", pTime, abs( timezone / 3600 ) % 60, abs( timezone / 60 ) % 60 );\r
217                         else\r
218                                 fprintf( gpAccessLog, "[%s +%02d%02d] ", pTime, abs( timezone / 3600 ) % 60, abs( timezone / 60 ) % 60 );\r
219 \r
220                         fprintf( gpAccessLog, "\"%s\" %d %d\n", strRequest.c_str( ), iStatus, iBytes );\r
221 \r
222                         giAccessLogCount++;\r
223 \r
224                         if( giAccessLogCount % giFlushInterval == 0 )\r
225                                 fflush( gpAccessLog );\r
226                 }\r
227         }\r
228 \r
229         gmtxOutput.Release( );\r
230 }\r
231 \r
232 //\r
233 // shamelessly stolen from wget source code\r
234 //\r
235 \r
236 struct bnbttv UTIL_CurrentTime( )\r
237 {\r
238         struct bnbttv btv;\r
239 \r
240 #ifdef WIN32\r
241         FILETIME ft;\r
242         SYSTEMTIME st;\r
243         GetSystemTime( &st );\r
244         SystemTimeToFileTime( &st, &ft );\r
245         btv.wintime.HighPart = ft.dwHighDateTime;\r
246         btv.wintime.LowPart = ft.dwLowDateTime;\r
247 #else\r
248         struct timeval tv;\r
249         gettimeofday( &tv, NULL );\r
250         btv.sec = tv.tv_sec;\r
251         btv.usec = tv.tv_usec;\r
252 #endif\r
253 \r
254         return btv;\r
255 }\r
256 \r
257 long UTIL_ElapsedTime( struct bnbttv btvStart, struct bnbttv btvEnd )\r
258 {\r
259 #ifdef WIN32\r
260         return (long)( ( btvEnd.wintime.QuadPart - btvStart.wintime.QuadPart ) / 10000 );\r
261 #else\r
262         return ( btvEnd.sec - btvStart.sec ) * 1000 + ( btvEnd.usec - btvStart.usec ) / 1000;\r
263 #endif\r
264 }\r
265 \r
266 string UTIL_ElapsedTimeStr( struct bnbttv btvStart, struct bnbttv btvEnd )\r
267 {\r
268         char szGen[8];\r
269         memset( szGen, 0, sizeof( char ) * 8 );\r
270     sprintf( szGen, "%0.3f", UTIL_ElapsedTime( btvStart, btvEnd ) / 1000.0 );\r
271 \r
272         return szGen;\r
273 }\r
274 \r
275 string UTIL_EscapedToString( const string &strEscape )\r
276 {\r
277         // according to RFC 2396\r
278 \r
279         string strString;\r
280 \r
281         for( unsigned long i = 0; i < strEscape.size( ); )\r
282         {\r
283                 if( strEscape[i] == '%' )\r
284                 {\r
285                         if( i < strEscape.size( ) - 2 )\r
286                         {\r
287                                 char pBuf[4];\r
288 \r
289                                 memset( pBuf, 0, sizeof( char ) * 4 );\r
290 \r
291                                 pBuf[0] = strEscape[i + 1];\r
292                                 pBuf[1] = strEscape[i + 2];\r
293 \r
294                                 unsigned int c;\r
295 \r
296                                 sscanf( pBuf, "%02X", &c );\r
297 \r
298                                 strString += c;\r
299 \r
300                                 i += 3;\r
301                         }\r
302                         else\r
303                         {\r
304                                 UTIL_LogPrint( "error decoding escaped string - possible truncation, halting decode\n" );\r
305 \r
306                                 return strString;\r
307                         }\r
308                 }\r
309                 else if( strEscape[i] == '+' )\r
310                 {\r
311                         strString += ' ';\r
312 \r
313                         i++;\r
314                 }\r
315                 else\r
316                 {\r
317                         strString += strEscape[i];\r
318 \r
319                         i++;\r
320                 }\r
321         }\r
322 \r
323         return strString;\r
324 }\r
325 \r
326 string UTIL_HashToString( const string &strHash )\r
327 {\r
328         // convert a 20 character hash to a readable string\r
329 \r
330         string strString;\r
331 \r
332         if( strHash.size( ) != 20 )\r
333                 return string( );\r
334 \r
335         for( unsigned long i = 0; i < strHash.size( ); i++ )\r
336         {\r
337                 char pBuf[4];\r
338 \r
339                 memset( pBuf, 0, sizeof( char ) * 4 );\r
340 \r
341                 // this must be unsigned or some really strange errors appear (i.e. the value of i is reset to zero every loop)\r
342 \r
343                 unsigned char c = strHash[i];\r
344 \r
345                 sprintf( pBuf, "%02x", c );\r
346 \r
347                 strString += pBuf;\r
348         }\r
349 \r
350         return strString;\r
351 }\r
352 \r
353 string UTIL_BytesToString( int64 iBytes )\r
354 {\r
355         int64 iB = iBytes % 1024;\r
356         iBytes /= 1024;\r
357         int64 iKB = iBytes % 1024;\r
358         iBytes /= 1024;\r
359         int64 iMB = iBytes % 1024;\r
360         iBytes /= 1024;\r
361         int64 iGB = iBytes % 1024;\r
362         iBytes /= 1024;\r
363         int64 iTB = iBytes % 1024;\r
364         iBytes /= 1024;\r
365         int64 iPB = iBytes;\r
366 \r
367         // B -> KB -> MB -> GB -> TB -> PB -> EB -> ZB -> YB\r
368 \r
369         string strBytes;\r
370 \r
371         if( iPB > 0 )\r
372         {\r
373                 int iFrac = (int)( (float)iTB / (float)1024 * (float)100 );\r
374 \r
375                 strBytes += CAtomLong( iPB ).toString( );\r
376                 strBytes += ".";\r
377 \r
378                 if( CAtomInt( iFrac ).toString( ).size( ) == 1 )\r
379                         strBytes += "0";\r
380 \r
381                 strBytes += CAtomInt( iFrac ).toString( );\r
382                 strBytes += " PB";\r
383         }\r
384         else if( iTB > 0 )\r
385         {\r
386                 int iFrac = (int)( (float)iGB / (float)1024 * (float)100 );\r
387 \r
388                 strBytes += CAtomLong( iTB ).toString( );\r
389                 strBytes += ".";\r
390 \r
391                 if( CAtomInt( iFrac ).toString( ).size( ) == 1 )\r
392                         strBytes += "0";\r
393 \r
394                 strBytes += CAtomInt( iFrac ).toString( );\r
395                 strBytes += " TB";\r
396         }\r
397         else if( iGB > 0 )\r
398         {\r
399                 int iFrac = (int)( (float)iMB / (float)1024 * (float)100 );\r
400 \r
401                 strBytes += CAtomLong( iGB ).toString( );\r
402                 strBytes += ".";\r
403 \r
404                 if( CAtomInt( iFrac ).toString( ).size( ) == 1 )\r
405                         strBytes += "0";\r
406 \r
407                 strBytes += CAtomInt( iFrac ).toString( );\r
408                 strBytes += " GB";\r
409         }\r
410         else if( iMB > 0 )\r
411         {\r
412                 int iFrac = (int)( (float)iKB / (float)1024 * (float)100 );\r
413 \r
414                 strBytes += CAtomLong( iMB ).toString( );\r
415                 strBytes += ".";\r
416 \r
417                 if( CAtomInt( iFrac ).toString( ).size( ) == 1 )\r
418                         strBytes += "0";\r
419 \r
420                 strBytes += CAtomInt( iFrac ).toString( );\r
421                 strBytes += " MB";\r
422         }\r
423         else if( iKB > 0 )\r
424         {\r
425                 int iFrac = (int)( (float)iB / (float)1024 * (float)100 );\r
426 \r
427                 strBytes += CAtomLong( iKB ).toString( );\r
428                 strBytes += ".";\r
429 \r
430                 if( CAtomInt( iFrac ).toString( ).size( ) == 1 )\r
431                         strBytes += "0";\r
432 \r
433                 strBytes += CAtomInt( iFrac ).toString( );\r
434                 strBytes += " KB";\r
435         }\r
436         else\r
437         {\r
438                 strBytes += CAtomLong( iB ).toString( );\r
439                 strBytes += " B";\r
440         }\r
441 \r
442         return strBytes;\r
443 }\r
444 \r
445 string UTIL_SecondsToString( unsigned long iSeconds )\r
446 {\r
447         // int iS = iSeconds % 60;\r
448 \r
449         iSeconds /= 60;\r
450         int iM = iSeconds % 60;\r
451         iSeconds /= 60;\r
452         int iH = iSeconds % 24;\r
453         iSeconds /= 24;\r
454         int iD = iSeconds;\r
455 \r
456         string strSeconds;\r
457 \r
458         strSeconds += CAtomInt( iD ).toString( );\r
459         strSeconds += "d ";\r
460 \r
461         if( CAtomInt( iH ).toString( ).size( ) == 1 )\r
462                 strSeconds += "0";\r
463 \r
464         strSeconds += CAtomInt( iH ).toString( );\r
465         strSeconds += ":";\r
466 \r
467         if( CAtomInt( iM ).toString( ).size( ) == 1 )\r
468                 strSeconds += "0";\r
469 \r
470         strSeconds += CAtomInt( iM ).toString( );\r
471 \r
472         /*\r
473 \r
474         strSeconds += ":";\r
475 \r
476         if( CAtomInt( iS ).toString( ).size( ) == 1 )\r
477                 strSeconds += "0";\r
478 \r
479         strSeconds += CAtomInt( iS ).toString( );\r
480 \r
481         */\r
482 \r
483         return strSeconds;\r
484 }\r
485 //addition by labarks\r
486 string UTIL_IntToString( int intInt )\r
487 {\r
488         string strInt;\r
489 \r
490         strInt = CAtomInt( intInt ).toString( );\r
491         \r
492         return strInt;\r
493 }\r
494 \r
495 string UTIL_LongToString( unsigned long iLong )\r
496 {\r
497         string strLong;\r
498         \r
499         iLong = (int64) iLong;\r
500 \r
501         strLong = CAtomLong( iLong ).toString( );\r
502         \r
503         return strLong;\r
504 }\r
505 \r
506 int UTIL_StringToInt( string strInt )\r
507 {\r
508         return atoi( strInt.c_str() );\r
509 }\r
510 \r
511 unsigned long UTIL_FileSize( const char *szFile )\r
512 {\r
513         FILE *pFile = NULL;\r
514         if( ( pFile = fopen( szFile, "rb" ) ) == NULL )\r
515         {\r
516                 //UTIL_LogPrint( "error opening file - unable to open %s for reading\n", szFile );\r
517                 return 0;\r
518         }\r
519         fseek( pFile, 0, SEEK_END );\r
520         unsigned long ulFileSize = ftell( pFile );\r
521         fclose( pFile );\r
522 \r
523         return ulFileSize;\r
524 }\r
525 \r
526 string UTIL_FileSizeToString( const char *szFile )\r
527 {\r
528         return UTIL_LongToString( UTIL_FileSize( szFile ) );\r
529 }\r
530 //end addition\r
531 \r
532 string UTIL_StringToEscaped( const string &strString )\r
533 {\r
534         // according to RFC 2396\r
535 \r
536         string strEscape;\r
537 \r
538         for( unsigned long i = 0; i < strString.size( ); i++ )\r
539         {\r
540                 unsigned char c = strString[i];\r
541 \r
542                 if( isalpha( c ) || isdigit( c ) ||\r
543                         c == '-' ||\r
544                         c == '_' ||\r
545                         c == '.' ||\r
546                         c == '!' ||\r
547                         c == '~' ||\r
548                         c == '*' ||\r
549                         c == '\'' ||\r
550                         c == '(' ||\r
551                         c == ')' )\r
552                 {\r
553                         // found an unreserved character\r
554 \r
555                         strEscape += c;\r
556                 }\r
557                 else if( c == ' ' )\r
558                         strEscape += '+';\r
559                 else\r
560                 {\r
561                         // found a reserved character\r
562 \r
563                         char pBuf[4];\r
564 \r
565                         memset( pBuf, 0, sizeof( char ) * 4 );\r
566 \r
567                         sprintf( pBuf, "%02X", c );\r
568 \r
569                         strEscape += "%";\r
570                         strEscape += pBuf;\r
571                 }\r
572         }\r
573 \r
574         return strEscape;\r
575 }\r
576 \r
577 //addition by labarks\r
578 string UTIL_URLEncode( const string &strString )\r
579 {\r
580         // according to RFC 2396\r
581 \r
582         string strEscape;\r
583 \r
584         for( unsigned long i = 0; i < strString.size( ); i++ )\r
585         {\r
586                 unsigned char c = strString[i];\r
587 \r
588                 if( isalpha( c ) || isdigit( c ) ||\r
589                         c == '/' ||\r
590                         c == '&' ||\r
591                         c == ';' ||\r
592                         c == '?' ||\r
593                         c == ':' ||\r
594                         c == '@' ||\r
595                         c == '+' ||\r
596                         c == '=' ||\r
597                         c == '$' ||\r
598                         c == ',' ||\r
599                         c == '-' ||\r
600                         c == '_' ||\r
601                         c == '.' ||\r
602                         c == '!' ||\r
603                         c == '~' ||\r
604                         c == '*' ||\r
605                         c == '\'' ||\r
606                         c == '(' ||\r
607                         c == ')' )\r
608                 {\r
609                         // found an unreserved character\r
610 \r
611                         strEscape += c;\r
612                 }\r
613                 else\r
614                 {\r
615                         // found a reserved character\r
616 \r
617                         char pBuf[4];\r
618 \r
619                         memset( pBuf, 0, sizeof( char ) * 4 );\r
620 \r
621                         sprintf( pBuf, "%02X", c );\r
622 \r
623                         strEscape += "%";\r
624                         strEscape += pBuf;\r
625                 }\r
626         }\r
627 \r
628         return strEscape;\r
629 }\r
630 //end addition\r
631 \r
632 string UTIL_StringToEscapedStrict( const string &strString )\r
633 {\r
634         string strEscape;\r
635 \r
636         for( unsigned long i = 0; i < strString.size( ); i++ )\r
637         {\r
638                 unsigned char c = strString[i];\r
639 \r
640                 if( isalpha( c ) || isdigit( c ) ||\r
641                         c == '-' ||\r
642                         c == '_' ||\r
643                         c == '.' ||\r
644                         c == '!' ||\r
645                         c == '~' ||\r
646                         c == '*' ||\r
647                         c == '\'' ||\r
648                         c == '(' ||\r
649                         c == ')' )\r
650                 {\r
651                         // found an unreserved character\r
652 \r
653                         strEscape += c;\r
654                 }\r
655                 else\r
656                 {\r
657                         // found a reserved character\r
658 \r
659                         char pBuf[4];\r
660 \r
661                         memset( pBuf, 0, sizeof( char ) * 4 );\r
662 \r
663                         sprintf( pBuf, "%02X", c );\r
664 \r
665                         strEscape += "%";\r
666                         strEscape += pBuf;\r
667                 }\r
668         }\r
669 \r
670         return strEscape;\r
671 }\r
672 \r
673 string UTIL_StringToHash( const string &strString )\r
674 {\r
675         // convert a readable string hash to a 20 character hash\r
676 \r
677         string strHash;\r
678 \r
679         if( strString.size( ) != 40 )\r
680                 return string( );\r
681 \r
682         for( unsigned long i = 0; i < strString.size( ); i += 2 )\r
683         {\r
684                 char pBuf[4];\r
685 \r
686                 memset( pBuf, 0, sizeof( char ) * 4 );\r
687 \r
688                 pBuf[0] = strString[i];\r
689                 pBuf[1] = strString[i + 1];\r
690 \r
691                 unsigned int c;\r
692 \r
693                 sscanf( pBuf, "%02x", &c );\r
694 \r
695                 strHash += c;\r
696         }\r
697 \r
698         return strHash;\r
699 }\r
700 \r
701 string UTIL_AccessToString( int iAccess )\r
702 {\r
703         if( iAccess & ACCESS_ADMIN )\r
704                 return "Admin";\r
705         else if( iAccess & ACCESS_EDIT )\r
706                 return "Moderator";\r
707         else if( iAccess & ACCESS_UPLOAD )\r
708                 return "Uploader";\r
709         else if( iAccess & ACCESS_COMMENTS )\r
710                 return "Poster";\r
711         else if( iAccess & ACCESS_DL )\r
712                 return "Downloader";\r
713         else if( iAccess & ACCESS_VIEW )\r
714                 return "Basic";\r
715         else\r
716                 return "None";\r
717 }\r
718 \r
719 int64 UTIL_StringTo64( const char *sz64 )\r
720 {\r
721         int64 i;\r
722 \r
723 #if defined( WIN32 )\r
724         sscanf( sz64, "%I64d", &i );\r
725 #elif defined( __FREEBSD__ )\r
726         sscanf( sz64, "%qd", &i );\r
727 #else\r
728         sscanf( sz64, "%lld", &i );\r
729 #endif\r
730 \r
731         return i;\r
732 }\r
733 \r
734 string UTIL_InfoHash( CAtom *pTorrent )\r
735 {\r
736         if( pTorrent && pTorrent->isDicti( ) )\r
737         {\r
738                 CAtom *pInfo = ( (CAtomDicti *)pTorrent )->getItem( "info" );\r
739 \r
740                 if( pInfo && pInfo->isDicti( ) )\r
741                 {\r
742                         CAtomDicti *pInfoDicti = (CAtomDicti *)pInfo;\r
743 \r
744                         // encode the string\r
745 \r
746                         string strData = Encode( pInfo );\r
747 \r
748                         // hash it\r
749 \r
750                         CSHA1 hasher;\r
751 \r
752                         hasher.Update( (unsigned char *)strData.c_str( ), strData.size( ) );\r
753                         hasher.Final( );\r
754 \r
755                         char szInfoHash[64];\r
756                         memset( szInfoHash, 0, sizeof( char ) * 64 );\r
757 \r
758                         hasher.ReportHash( szInfoHash );\r
759 \r
760                         return UTIL_StringToHash( szInfoHash );\r
761                 }\r
762         }\r
763 \r
764         return string( );\r
765 }\r
766 \r
767 bool UTIL_CheckFile( const char *szFile )\r
768 {\r
769         // check if file exists\r
770 \r
771         FILE *pFile = NULL;\r
772 \r
773         if( ( pFile = fopen( szFile, "r" ) ) == NULL )\r
774                 return false;\r
775 \r
776         fclose( pFile );\r
777 \r
778         return true;\r
779 }\r
780 \r
781 void UTIL_MakeFile( const char *szFile, string strContents )\r
782 {\r
783         FILE *pFile = NULL;\r
784 \r
785         if( ( pFile = fopen( szFile, "wb" ) ) == NULL )\r
786         {\r
787                 UTIL_LogPrint( "warning - unable to open %s for writing\n", szFile );\r
788 \r
789                 return;\r
790         }\r
791 \r
792         fwrite( (void *)strContents.c_str( ), sizeof( char ), strContents.size( ), pFile );\r
793         fclose( pFile );\r
794 }\r
795 \r
796 void UTIL_DeleteFile( const char *szFile )\r
797 {\r
798         if( unlink( szFile ) == 0 )\r
799                 UTIL_LogPrint( "deleted \"%s\"\n", szFile );\r
800         else\r
801         {\r
802 #ifdef WIN32\r
803                 UTIL_LogPrint( "error deleting \"%s\"\n", szFile );\r
804 #else\r
805                 UTIL_LogPrint( "error deleting \"%s\" - %s\n", szFile, strerror( errno ) );\r
806 #endif\r
807         }\r
808 }\r
809 \r
810 void UTIL_MoveFile( const char *szFile, const char *szDest )\r
811 {\r
812         if( UTIL_CheckFile( szDest ) )\r
813                 UTIL_LogPrint( "error archiving \"%s\" - destination file already exists\n", szDest );\r
814         else\r
815                 UTIL_MakeFile( szDest, UTIL_ReadFile( szFile ) );\r
816 \r
817         // thanks MrMister\r
818 \r
819         UTIL_DeleteFile( szFile );\r
820 }\r
821 \r
822 string UTIL_ReadFile( const char *szFile )\r
823 {\r
824         FILE *pFile = NULL;\r
825 \r
826         if( ( pFile = fopen( szFile, "rb" ) ) == NULL )\r
827         {\r
828                 UTIL_LogPrint( "warning - unable to open %s for reading\n", szFile );\r
829 \r
830                 return string( );\r
831         }\r
832 \r
833         fseek( pFile, 0, SEEK_END );\r
834         unsigned long ulFileSize = ftell( pFile );\r
835         fseek( pFile, 0, SEEK_SET );\r
836         char *pData = (char *)malloc( sizeof( char ) * ulFileSize );\r
837         memset( pData, 0, sizeof( char ) * ulFileSize );\r
838         fread( (void *)pData, sizeof( char ), ulFileSize, pFile );\r
839         fclose( pFile );\r
840         string strFile( pData, ulFileSize );\r
841         free( pData );\r
842 \r
843         return strFile;\r
844 }\r
845 \r
846 string UTIL_ToLower( string strUpper )\r
847 {\r
848         for( unsigned long i = 0; i < strUpper.size( ); i++ )\r
849                 strUpper[i] = tolower( strUpper[i] );\r
850 \r
851         return strUpper;\r
852 }\r
853 \r
854 string UTIL_StripPath( string strPath )\r
855 {\r
856         string :: size_type iFileStart = strPath.rfind( '\\' );\r
857 \r
858         if( iFileStart == string :: npos )\r
859         {\r
860                 iFileStart = strPath.rfind( '/' );\r
861 \r
862                 if( iFileStart == string :: npos )\r
863                         iFileStart = 0;\r
864                 else\r
865                         iFileStart++;\r
866         }\r
867         else\r
868                 iFileStart++;\r
869 \r
870         return strPath.substr( iFileStart );\r
871 }\r
872 \r
873 string UTIL_RemoveHTML( string strHTML )\r
874 {\r
875         for( unsigned long i = 0; i < strHTML.size( ); i++ )\r
876         {\r
877                 if( strHTML[i] == '<' )\r
878                         strHTML.replace( i, 1, "&lt;" );\r
879                 else if( strHTML[i] == '>' )\r
880                         strHTML.replace( i, 1, "&gt;" );\r
881                 else if( strHTML[i] == '&' )\r
882                         strHTML.replace( i, 1, "&amp;" );\r
883                 else if( strHTML[i] == '"' )\r
884                         strHTML.replace( i, 1, "&quot;" );\r
885                 else if( strHTML[i] == '\n' )\r
886                 {\r
887                         if( i > 0 )\r
888                         {\r
889                                 if( strHTML[i - 1] == '\r' )\r
890                                 {\r
891                                         strHTML.replace( i - 1, 2, "<br>" );\r
892 \r
893                                         i += 2;\r
894                                 }\r
895                                 else\r
896                                 {\r
897                                         strHTML.replace( i, 1, "<br>" );\r
898 \r
899                                         i += 3;\r
900                                 }\r
901                         }\r
902                         else\r
903                         {\r
904                                 strHTML.replace( i, 1, "<br>" );\r
905 \r
906                                 i += 3;\r
907                         }\r
908                 }\r
909         }\r
910 \r
911         return strHTML;\r
912 }\r
913 \r
914 string UTIL_FailureReason( string strFailureReason )\r
915 {\r
916         CAtomDicti dict;\r
917 \r
918         dict.setItem( "failure reason", new CAtomString( strFailureReason ) );\r
919 \r
920         return Encode( &dict );\r
921 }\r
922 \r
923 /*\r
924 \r
925 ===================\r
926 UTIL_DecodeHTTPPost\r
927 ===================\r
928 \r
929 [\r
930   {\r
931     disposition->{\r
932                    key1->string (quotes stripped)\r
933                    key2->string (quotes stripped)\r
934                    key3->string (quotes stripped)\r
935                    key4->string (quotes stripped)\r
936                    ...\r
937                  }\r
938     data->string\r
939   },\r
940 \r
941   {\r
942     disposition->{\r
943                    key1->string (quotes stripped)\r
944                    key2->string (quotes stripped)\r
945                    key3->string (quotes stripped)\r
946                    key4->string (quotes stripped)\r
947                    ...\r
948                  }\r
949     data->string\r
950   }\r
951 ]\r
952 \r
953 */\r
954 \r
955 CAtomList *UTIL_DecodeHTTPPost( string strPost )\r
956 {\r
957         // find the boundary\r
958 \r
959         string :: size_type iBoundary = strPost.find( "boundary=" );\r
960 \r
961         if( iBoundary == string :: npos )\r
962                 return NULL;\r
963 \r
964         iBoundary += strlen( "boundary=" );\r
965 \r
966         string strBoundary = strPost.substr( iBoundary );\r
967 \r
968         string :: size_type iBoundEnd = strBoundary.find( "\r\n" );\r
969 \r
970         if( iBoundEnd == string :: npos )\r
971                 return NULL;\r
972 \r
973         strBoundary = strBoundary.substr( 0, iBoundEnd );\r
974 \r
975         // strBoundary now contains the boundary\r
976 \r
977         string :: size_type iContent = strPost.find( "\r\n\r\n" );\r
978 \r
979         if( iContent == string :: npos )\r
980                 return NULL;\r
981 \r
982         iContent += strlen( "\r\n\r\n" );\r
983 \r
984         string strContent = strPost.substr( iContent );\r
985 \r
986         // decode\r
987 \r
988         CAtomList *pList = new CAtomList( );\r
989 \r
990         string :: size_type iSegStart = 0;\r
991         string :: size_type iSegEnd = 0;\r
992 \r
993         while( 1 )\r
994         {\r
995                 // segment start\r
996 \r
997                 iSegStart = strContent.find( strBoundary, iSegStart );\r
998 \r
999                 if( iSegStart == string :: npos )\r
1000                         return pList;\r
1001 \r
1002                 iSegStart += strBoundary.size( );\r
1003 \r
1004                 if( strContent.substr( iSegStart, 2 ) == "--" )\r
1005                         return pList;\r
1006 \r
1007                 iSegStart += strlen( "\r\n" );\r
1008 \r
1009                 // segment end\r
1010 \r
1011                 iSegEnd = strContent.find( strBoundary, iSegStart );\r
1012 \r
1013                 if( iSegEnd == string :: npos )\r
1014                 {\r
1015                         UTIL_LogPrint( "error decoding HTTP POST request - unexpected end of request\n" );\r
1016 \r
1017                         delete pList;\r
1018 \r
1019                         pList = NULL;\r
1020 \r
1021                         return NULL;\r
1022                 }\r
1023 \r
1024                 iSegEnd -= strlen( "\r\n--" );\r
1025 \r
1026                 // found segment\r
1027 \r
1028                 CAtomDicti *pSegment = new CAtomDicti( );\r
1029 \r
1030                 pList->addItem( pSegment );\r
1031 \r
1032                 // this could do with some serious optimizing...\r
1033 \r
1034                 string strSeg = strContent.substr( iSegStart, iSegEnd - iSegStart );\r
1035 \r
1036                 string :: size_type iDispStart = strSeg.find( "Content-Disposition: " );\r
1037 \r
1038                 if( iDispStart == string :: npos )\r
1039                 {\r
1040                         UTIL_LogPrint( "error decoding HTTP POST request - couldn't find Content-Disposition\n" );\r
1041 \r
1042                         delete pList;\r
1043 \r
1044                         pList = NULL;\r
1045 \r
1046                         return NULL;\r
1047                 }\r
1048 \r
1049                 iDispStart += strlen( "Content-Disposition: " );\r
1050 \r
1051                 string :: size_type iDispEnd = strSeg.find( "\r\n", iDispStart );\r
1052 \r
1053                 if( iDispEnd == string :: npos )\r
1054                 {\r
1055                         UTIL_LogPrint( "error decoding HTTP POST request - malformed Content-Disposition\n" );\r
1056 \r
1057                         delete pList;\r
1058 \r
1059                         pList = NULL;\r
1060 \r
1061                         return NULL;\r
1062                 }\r
1063 \r
1064                 string strDisp = strSeg.substr( iDispStart, iDispEnd - iDispStart );\r
1065 \r
1066                 string :: size_type iDispPrev = 0;\r
1067                 string :: size_type iDispPos = 0;\r
1068 \r
1069                 CAtomDicti *pDisp = new CAtomDicti( );\r
1070 \r
1071                 pSegment->setItem( "disposition", pDisp );\r
1072 \r
1073                 while( 1 )\r
1074                 {\r
1075                         // assume a semicolon indicates the end of the item and will never appear inside the item (probably a bad assumption)\r
1076 \r
1077                         iDispPrev = iDispPos;\r
1078                         iDispPos = strDisp.find( ";", iDispPos );\r
1079 \r
1080                         if( iDispPos == string :: npos )\r
1081                         {\r
1082                                 // decode last item\r
1083 \r
1084                                 iDispPos = strDisp.size( );\r
1085                         }\r
1086 \r
1087                         string strCurr = strDisp.substr( iDispPrev, iDispPos - iDispPrev );\r
1088 \r
1089                         string :: size_type iSplit = strCurr.find( "=" );\r
1090 \r
1091                         if( iSplit == string :: npos )\r
1092                         {\r
1093                                 // found a key without value, i.e. "form-data", useless so ignore it\r
1094 \r
1095                                 if( iDispPos == strDisp.size( ) )\r
1096                                         break;\r
1097 \r
1098                                 // + strlen( ";" )\r
1099 \r
1100                                 iDispPos++;\r
1101 \r
1102                                 continue;\r
1103                         }\r
1104 \r
1105                         // strip whitespace\r
1106 \r
1107                         string :: size_type iKeyStart = strCurr.find_first_not_of( " " );\r
1108 \r
1109                         if( iKeyStart == string :: npos || iKeyStart > iSplit )\r
1110                         {\r
1111                                 UTIL_LogPrint( "error decoding HTTP POST request - malformed Content-Disposition\n" );\r
1112 \r
1113                                 delete pList;\r
1114 \r
1115                                 pList = NULL;\r
1116 \r
1117                                 return NULL;\r
1118                         }\r
1119 \r
1120                         string strKey = strCurr.substr( iKeyStart, iSplit - iKeyStart );\r
1121                         string strValue = strCurr.substr( iSplit + 1 );\r
1122 \r
1123                         // strip quotes\r
1124 \r
1125                         if( strValue.size( ) > 1 && strValue[0] == '"' )\r
1126                                 strValue = strValue.substr( 1, strValue.size( ) - 2 );\r
1127 \r
1128                         pDisp->setItem( strKey, new CAtomString( strValue ) );\r
1129 \r
1130                         if( iDispPos == strDisp.size( ) )\r
1131                                 break;\r
1132 \r
1133                         // + strlen( ";" )\r
1134 \r
1135                         iDispPos++;\r
1136                 }\r
1137 \r
1138                 // data\r
1139 \r
1140                 string :: size_type iDataStart = strSeg.find( "\r\n\r\n" );\r
1141 \r
1142                 if( iDataStart == string :: npos )\r
1143                 {\r
1144                         UTIL_LogPrint( "error decoding HTTP POST request - malformed segment\n" );\r
1145 \r
1146                         delete pList;\r
1147 \r
1148                         pList = NULL;\r
1149 \r
1150                         return NULL;\r
1151                 }\r
1152 \r
1153                 iDataStart += strlen( "\r\n\r\n" );\r
1154 \r
1155                 pSegment->setItem( "data", new CAtomString( strSeg.substr( iDataStart ) ) );\r
1156         }\r
1157 \r
1158         // this should never happen, so who cares\r
1159 \r
1160         delete pList;\r
1161 \r
1162         pList = NULL;\r
1163 \r
1164         return NULL;\r
1165 }\r