source: branches/1.5x/libtransmission/clients.c @ 8204

Last change on this file since 8204 was 8204, checked in by charles, 13 years ago

(1.5x libT) various backports for 1.52:
(1) recognize Aria2 as a client
(2) remove jhujhiti's tr_suspectAddress(), since he removed it from trunka
(3) on Mac, better detection of where the Web UI files are located
(4) reintroduce the web task queue
(5) various minor formatting changes to reduce the diffs between 1.52 and trunk

  • Property svn:keywords set to Date Rev Author Id
File size: 16.9 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: clients.c 8204 2009-04-10 17:34:25Z charles $
11 */
12
13/* thanks amc1! */
14
15#include <ctype.h> /* isprint, tolower */
16#include <stdio.h>
17#include <stdlib.h> /* strtol */
18#include <string.h>
19
20#include <libevent/event.h> /* evbuffer */
21
22#include "transmission.h"
23#include "clients.h"
24#include "utils.h"
25
26static int
27charint( char ch )
28{
29    if( '0' <= ch && ch <= '9' ) return      ch - '0';
30    if( 'A' <= ch && ch <= 'Z' ) return 10 + ch - 'A';
31    if( 'a' <= ch && ch <= 'z' ) return 36 + ch - 'a';
32    return 0;
33}
34
35static int 
36getShadowInt( char ch, int * setme ) 
37{ 
38    const char * str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-"; 
39    const char * pch = strchr( str, ch ); 
40    if( !pch ) 
41    return 0; 
42        *setme = pch - str; 
43    return 1; 
44} 
45
46static int
47strint( const void * pch, int span )
48{
49    char tmp[64];
50    memcpy( tmp, pch, span );
51    tmp[span] = '\0';
52    return strtol( tmp, NULL, 0 );
53}
54
55static const char*
56getMnemonicEnd( char ch )
57{
58    switch( ch )
59    {
60        case 'b': case 'B': return " (Beta)";
61        case 'd': return " (Debug)";
62        case 'x': case 'X': case 'Z': return " (Dev)";
63        default: return "";
64    }
65}
66
67static void
68three_digits( char * buf, size_t buflen, const char * name, const uint8_t * digits )
69{
70    tr_snprintf( buf, buflen, "%s %d.%d.%d", name,
71                 charint( digits[0] ),
72                 charint( digits[1] ),
73                 charint( digits[2] ) );
74}
75static void
76four_digits( char * buf, size_t buflen, const char * name, const uint8_t * digits )
77{
78    tr_snprintf( buf, buflen, "%s %d.%d.%d.%d", name,
79                 charint( digits[0] ),
80                 charint( digits[1] ),
81                 charint( digits[2] ),
82                 charint( digits[3] ) );
83}
84static void
85two_major_two_minor( char * buf, size_t buflen, const char * name, const uint8_t * digits )
86{
87    tr_snprintf( buf, buflen, "%s %d.%02d", name,
88                 strint( digits, 2 ),
89                 strint( digits+2, 2 ) );
90}
91static void
92no_version( char * buf, size_t buflen, const char * name )
93{
94    tr_strlcpy( buf, name, buflen );
95}
96
97static void
98mainline_style( char * buf, size_t buflen, const char * name, const uint8_t * id )
99{
100    if( id[4] == '-' && id[6] == '-' )
101        tr_snprintf( buf, buflen, "%s %c.%c.%c", name, id[1], id[3], id[5] );
102    else if( id[5] == '-' )
103        tr_snprintf( buf, buflen, "%s %c.%c%c.%c", name, id[1], id[3], id[4], id[6] );
104}
105
106static int
107isMainlineStyle( const uint8_t * peer_id )
108{
109    /**
110     * One of the following styles will be used:
111     *   Mx-y-z--
112     *   Mx-yy-z-
113     */ 
114    return peer_id[2]=='-'
115        && peer_id[7]=='-'
116        && ( peer_id[4]=='-' || peer_id[5]=='-' );
117}
118
119static int
120decodeBitCometClient( char * buf, size_t buflen, const uint8_t * id )
121{
122    int is_bitlord;
123    int major, minor;
124    const char * name;
125    const char * mod = NULL;
126
127    if( !memcmp( id, "exbc", 4 ) ) mod = "";
128    else if( !memcmp( id, "FUTB", 4 )) mod = "(Solidox Mod) ";
129    else if( !memcmp( id, "xUTB", 4 )) mod = "(Mod 2) ";
130    else return FALSE;
131
132    is_bitlord = !memcmp( id+6, "LORD", 4 );
133    name = (is_bitlord) ? "BitLord " : "BitComet ";
134    major = id[4];
135    minor = id[5];
136
137    /**
138     * Bitcomet, and older versions of BitLord, are of the form x.yy.
139     * Bitcoment 1.0 and onwards are of the form x.y.
140     */
141    if( is_bitlord && major>0 )
142        tr_snprintf( buf, buflen, "%s%s%d.%d", name, mod, major, minor );
143    else
144        tr_snprintf( buf, buflen, "%s%s%d.%02d", name, mod, major, minor );
145
146    return TRUE;
147}
148
149static int
150decodeBitSpiritClient( char * buf, size_t buflen, const uint8_t * id )
151{
152    const int isBS = !memcmp( id+2, "BS", 2 );
153    if( isBS )
154    {
155        const int version = id[1] ? id[1] : 1;
156        tr_snprintf( buf, buflen, "BitSpirit v%d", version );
157    }
158    return isBS;
159}
160
161void
162tr_clientForId( char * buf, size_t buflen, const void * id_in )
163{
164    const uint8_t * id = id_in;
165
166    *buf = '\0';
167
168    if( !id )
169        return;
170
171    /* Azureus-style */
172    if( id[0] == '-' && id[7] == '-' )
173    {
174        if( !memcmp( id+1, "UT", 2 ) )
175        {
176            tr_snprintf( buf, buflen, "\xc2\xb5Torrent %d.%d.%d%s",
177                         strint(id+3,1), strint(id+4,1), strint(id+5,1), getMnemonicEnd(id[6]) );
178        }
179        if( !memcmp( id+1, "UM", 2 ) )
180        {
181            tr_snprintf( buf, buflen, "\xc2\xb5Torrent Mac %d.%d.%d%s",
182                         strint(id+3,1), strint(id+4,1), strint(id+5,1), getMnemonicEnd(id[6]) );
183        }
184
185        else if( !memcmp( id+1, "TR", 2 ) )
186        {
187            if( !memcmp( id+3, "000", 3 ) ) /* very old client style: -TR0006- is 0.6 */
188                tr_snprintf( buf, buflen, "Transmission 0.%c", id[6] );
189            else if( !memcmp( id+3, "00", 2) ) /* previous client style: -TR0072- is 0.72 */
190                tr_snprintf( buf, buflen, "Transmission 0.%02d", strint(id+5,2) );
191            else /* current client style: -TR111Z- is 1.11+ */
192                tr_snprintf( buf, buflen, "Transmission %d.%02d%s", strint(id+3,1), strint(id+4,2),
193                          id[6]=='Z' || id[6]=='X' ? "+" : "" );
194        }
195       
196        else if( !memcmp( id+1, "AZ", 2 ) )
197        {
198            if( id[3] > '3' || ( id[3] == '3' && id[4] >= '1' ) ) /* Vuze starts at version 3.1.0.0 */
199                four_digits( buf, buflen, "Vuze", id+3 );
200            else
201                four_digits( buf, buflen, "Azureus", id+3 );
202        }
203       
204        else if( !memcmp( id+1, "KT", 2 ) )
205        {
206            if( id[5] == 'D' )
207                tr_snprintf( buf, buflen, "KTorrent %d.%d Dev %d", charint(id[3]), charint(id[4]), charint(id[6]) );
208            else if( id[5] == 'R' )
209                tr_snprintf( buf, buflen, "KTorrent %d.%d RC %d", charint(id[3]), charint(id[4]), charint(id[6]) );
210            else
211                three_digits( buf, buflen, "KTorrent", id+3 );
212        }
213
214        else if( !memcmp( id+1, "AR", 2 ) ) four_digits( buf, buflen, "Ares", id+3 );
215        else if( !memcmp( id+1, "AT", 2 ) ) four_digits( buf, buflen, "Artemis", id+3 );
216        else if( !memcmp( id+1, "AV", 2 ) ) four_digits( buf, buflen, "Avicora", id+3 );
217        else if( !memcmp( id+1, "BG", 2 ) ) four_digits( buf, buflen, "BTGetit", id+3 );
218        else if( !memcmp( id+1, "BM", 2 ) ) four_digits( buf, buflen, "BitMagnet", id+3 );
219        else if( !memcmp( id+1, "BP", 2 ) ) four_digits( buf, buflen, "BitTorrent Pro (Azureus + Spyware)", id+3 );
220        else if( !memcmp( id+1, "BX", 2 ) ) four_digits( buf, buflen, "BittorrentX", id+3 );
221        else if( !memcmp( id+1, "bk", 2 ) ) four_digits( buf, buflen, "BitKitten (libtorrent)", id+3 );
222        else if( !memcmp( id+1, "BS", 2 ) ) four_digits( buf, buflen, "BTSlave", id+3 );
223        else if( !memcmp( id+1, "BW", 2 ) ) four_digits( buf, buflen, "BitWombat", id+3 );
224        else if( !memcmp( id+1, "BX", 2 ) ) four_digits( buf, buflen, "BittorrentX", id+3 );
225        else if( !memcmp( id+1, "EB", 2 ) ) four_digits( buf, buflen, "EBit", id+3 );
226        else if( !memcmp( id+1, "DE", 2 ) ) four_digits( buf, buflen, "Deluge", id+3 );
227        else if( !memcmp( id+1, "DP", 2 ) ) four_digits( buf, buflen, "Propogate Data Client", id+3 );
228        else if( !memcmp( id+1, "FC", 2 ) ) four_digits( buf, buflen, "FileCroc", id+3 );
229        else if( !memcmp( id+1, "FT", 2 ) ) four_digits( buf, buflen, "FoxTorrent/RedSwoosh", id+3 );
230        else if( !memcmp( id+1, "GR", 2 ) ) four_digits( buf, buflen, "GetRight", id+3 );
231        else if( !memcmp( id+1, "HN", 2 ) ) four_digits( buf, buflen, "Hydranode", id+3 );
232        else if( !memcmp( id+1, "LC", 2 ) ) four_digits( buf, buflen, "LeechCraft", id+3 );
233        else if( !memcmp( id+1, "LH", 2 ) ) four_digits( buf, buflen, "LH-ABC", id+3 );
234        else if( !memcmp( id+1, "NX", 2 ) ) four_digits( buf, buflen, "Net Transport", id+3 );
235        else if( !memcmp( id+1, "MO", 2 ) ) four_digits( buf, buflen, "MonoTorrent", id+3 );
236        else if( !memcmp( id+1, "MR", 2 ) ) four_digits( buf, buflen, "Miro", id+3 );
237        else if( !memcmp( id+1, "MT", 2 ) ) four_digits( buf, buflen, "Moonlight", id+3 );
238        else if( !memcmp( id+1, "OT", 2 ) ) four_digits( buf, buflen, "OmegaTorrent", id+3 );
239        else if( !memcmp( id+1, "PD", 2 ) ) four_digits( buf, buflen, "Pando", id+3 );
240        else if( !memcmp( id+1, "QD", 2 ) ) four_digits( buf, buflen, "QQDownload", id+3 );
241        else if( !memcmp( id+1, "RS", 2 ) ) four_digits( buf, buflen, "Rufus", id+3 );
242        else if( !memcmp( id+1, "RT", 2 ) ) four_digits( buf, buflen, "Retriever", id+3 );
243        else if( !memcmp( id+1, "SD", 2 ) ) four_digits( buf, buflen, "Xunlei", id+3 );
244        else if( !memcmp( id+1, "SS", 2 ) ) four_digits( buf, buflen, "SwarmScope", id+3 );
245        else if( !memcmp( id+1, "SZ", 2 ) ) four_digits( buf, buflen, "Shareaza", id+3 );
246        else if( !memcmp( id+1, "S~", 2 ) ) four_digits( buf, buflen, "Shareaza", id+3 );
247        else if( !memcmp( id+1, "st", 2 ) ) four_digits( buf, buflen, "SharkTorrent", id+3 );
248        else if( !memcmp( id+1, "TN", 2 ) ) four_digits( buf, buflen, "Torrent .NET", id+3 );
249        else if( !memcmp( id+1, "TS", 2 ) ) four_digits( buf, buflen, "TorrentStorm", id+3 );
250        else if( !memcmp( id+1, "UL", 2 ) ) four_digits( buf, buflen, "uLeecher!", id+3 );
251        else if( !memcmp( id+1, "VG", 2 ) ) four_digits( buf, buflen, "Vagaa", id+3 );
252        else if( !memcmp( id+1, "WT", 2 ) ) four_digits( buf, buflen, "BitLet", id+3 );
253        else if( !memcmp( id+1, "WY", 2 ) ) four_digits( buf, buflen, "Wyzo", id+3 );
254        else if( !memcmp( id+1, "XL", 2 ) ) four_digits( buf, buflen, "Xunlei", id+3 );
255        else if( !memcmp( id+1, "XT", 2 ) ) four_digits( buf, buflen, "XanTorrent", id+3 );
256        else if( !memcmp( id+1, "ZT", 2 ) ) four_digits( buf, buflen, "Zip Torrent", id+3 );
257
258        else if( !memcmp( id+1, "AG", 2 ) ) three_digits( buf, buflen, "Ares", id+3 );
259        else if( !memcmp( id+1, "A~", 2 ) ) three_digits( buf, buflen, "Ares", id+3 );
260        else if( !memcmp( id+1, "ES", 2 ) ) three_digits( buf, buflen, "Electric Sheep", id+3 );
261        else if( !memcmp( id+1, "HL", 2 ) ) three_digits( buf, buflen, "Halite", id+3 );
262        else if( !memcmp( id+1, "LT", 2 ) ) three_digits( buf, buflen, "libtorrent (Rasterbar)", id+3 );
263        else if( !memcmp( id+1, "lt", 2 ) ) three_digits( buf, buflen, "libTorrent (Rakshasa)", id+3 );
264        else if( !memcmp( id+1, "MP", 2 ) ) three_digits( buf, buflen, "MooPolice", id+3 );
265        else if( !memcmp( id+1, "TT", 2 ) ) three_digits( buf, buflen, "TuoTu", id+3 );
266        else if( !memcmp( id+1, "qB", 2 ) ) three_digits( buf, buflen, "qBittorrent", id+3 );
267
268        else if( !memcmp( id+1, "AX", 2 ) ) two_major_two_minor( buf, buflen, "BitPump", id+3 );
269        else if( !memcmp( id+1, "BC", 2 ) ) two_major_two_minor( buf, buflen, "BitComet", id+3 );
270        else if( !memcmp( id+1, "CD", 2 ) ) two_major_two_minor( buf, buflen, "Enhanced CTorrent", id+3 );
271        else if( !memcmp( id+1, "LP", 2 ) ) two_major_two_minor( buf, buflen, "Lphant", id+3 );
272
273        else if( !memcmp( id+1, "BF", 2 ) ) no_version( buf, buflen, "BitFlu" );
274        else if( !memcmp( id+1, "LW", 2 ) ) no_version( buf, buflen, "LimeWire" );
275
276        else if( !memcmp( id+1, "BB", 2 ) )
277        {
278            tr_snprintf( buf, buflen, "BitBuddy %c.%c%c%c", id[3], id[4], id[5], id[6] );
279        }
280        else if( !memcmp( id+1, "BR", 2 ) )
281        {
282            tr_snprintf( buf, buflen, "BitRocket %c.%c (%c%c)", id[3], id[4], id[5], id[6] );
283        }
284        else if( !memcmp( id+1, "CT", 2 ) )
285        {
286            tr_snprintf( buf, buflen, "CTorrent %d.%d.%02d", charint(id[3]), charint(id[4]), strint(id+5,2) );
287        }
288        else if( !memcmp( id+1, "XX", 2 ) )
289        {
290            tr_snprintf( buf, buflen, "Xtorrent %d.%d (%d)", charint(id[3]), charint(id[4]), strint(id+5,2) );
291        }
292        else if( !memcmp( id+1, "BOW", 3 ) )
293        {
294                 if( !memcmp( &id[4], "A0B", 3 ) ) tr_snprintf( buf, buflen, "Bits on Wheels 1.0.5" );
295            else if( !memcmp( &id[4], "A0C", 3 ) ) tr_snprintf( buf, buflen, "Bits on Wheels 1.0.6" );
296            else                                   tr_snprintf( buf, buflen, "Bits on Wheels %c.%c.%c", id[4], id[5], id[5] );
297        }
298
299        if( *buf )
300            return;
301    }
302
303    /* Mainline */
304    if( isMainlineStyle( id ) )
305    {
306        if( *id=='M' ) mainline_style( buf, buflen, "BitTorrent", id );
307        if( *id=='Q' ) mainline_style( buf, buflen, "Queen Bee", id );
308        if( *buf ) return;
309    }
310
311    if( decodeBitCometClient( buf, buflen, id ) )
312        return;
313    if( decodeBitSpiritClient( buf, buflen, id ) )
314        return;
315
316    /* Clients with no version */
317         if( !memcmp( id, "AZ2500BT", 8 ) )  no_version( buf, buflen, "BitTyrant (Azureus Mod)" );
318    else if( !memcmp( id, "LIME", 4 ) )      no_version( buf, buflen, "Limewire" );
319    else if( !memcmp( id, "martini", 7 ) )   no_version( buf, buflen, "Martini Man" );
320    else if( !memcmp( id, "Pando", 5 ) )     no_version( buf, buflen, "Pando" );
321    else if( !memcmp( id, "a00---0", 7 ) )   no_version( buf, buflen, "Swarmy" );
322    else if( !memcmp( id, "a02---0", 7 ) )   no_version( buf, buflen, "Swarmy" );
323    else if( !memcmp( id, "-G3", 3 ) )       no_version( buf, buflen, "G3 Torrent" );
324    else if( !memcmp( id, "10-------", 9 ) ) no_version( buf, buflen, "JVtorrent" );
325    else if( !memcmp( id, "346-", 4 ) )      no_version( buf, buflen, "TorrentTopia" );
326    else if( !memcmp( id, "eX", 2 ) )        no_version( buf, buflen, "eXeem" );
327    else if( !memcmp( id, "-aria2-", 7 ) )   no_version( buf, buflen, "aria2" );
328    else if( !memcmp( id, "-FG", 3 ) )       two_major_two_minor( buf, buflen, "FlashGet", id+3 );
329   
330    /* Everything else */ 
331    else if( !memcmp( id, "S3", 2 ) && id[2] == '-' && id[4] == '-' && id[6] == '-' )
332    {
333        tr_snprintf( buf, buflen, "Amazon S3 %c.%c.%c", id[3], id[5], id[7] );
334    }
335    else if( !memcmp( id, "OP", 2 ) )
336    {
337        tr_snprintf( buf, buflen, "Opera (Build %c%c%c%c)", id[2], id[3], id[4], id[5] );
338    }
339    else if( !memcmp( id, "-ML", 3 ) )
340    {
341        tr_snprintf( buf, buflen, "MLDonkey %c%c%c%c%c", id[3], id[4], id[5], id[6], id[7] );
342    }
343    else if( !memcmp( id, "DNA", 3 ) )
344    {
345        tr_snprintf( buf, buflen, "BitTorrent DNA %d.%d.%d", strint(id+3,2),
346                                                             strint(id+5,2),
347                                                             strint(id+7,2) );
348    }
349    else if( !memcmp( id, "Plus", 4 ) )
350    {
351        tr_snprintf( buf, buflen, "Plus! v2 %c.%c%c", id[4], id[5], id[6] );
352    }
353    else if( !memcmp( id, "XBT", 3 ) )
354    {
355        tr_snprintf( buf, buflen, "XBT Client %c.%c.%c%s", id[3], id[4], id[5], getMnemonicEnd(id[6]) );
356    }
357    else if( !memcmp( id, "Mbrst", 5 ) )
358    {
359        tr_snprintf( buf, buflen, "burst! %c.%c.%c", id[5], id[7], id[9] );
360    }
361    else if( !memcmp( id, "btpd", 4 ) )
362    {
363        tr_snprintf( buf, buflen, "BT Protocol Daemon %c%c%c", id[5], id[6], id[7] );
364    }
365    else if( !memcmp( id, "BLZ", 3 ) )
366    {
367        tr_snprintf( buf, buflen, "Blizzard Downloader %d.%d", id[3]+1, id[4] );
368    }
369    else if( '\0' == id[0] && !memcmp( &id[1], "BS", 2 ) )
370    {
371        tr_snprintf( buf, buflen, "BitSpirit %u", ( id[1] == 0 ? 1 : id[1] ) );
372    }
373    else if( !memcmp( id, "QVOD", 4 ) )
374    {
375        four_digits( buf, buflen, "QVOD", id+4 );
376    }
377    else if( !memcmp( id, "-NE", 3 ) )
378    {
379        four_digits( buf, buflen, "BT Next Evolution", id+3 );
380    }
381
382    /* Shad0w-style */
383    {
384        int a, b, c;
385        if( strchr( "AOQRSTU", id[0] )
386            && getShadowInt( id[1], &a )
387            && getShadowInt( id[2], &b )
388            && getShadowInt( id[3], &c ) )
389        {
390            const char * name = NULL;
391
392            switch( id[0] )
393            {
394                case 'A': name = "ABC"; break;
395                case 'O': name = "Osprey"; break;
396                case 'Q': name = "BTQueue"; break;
397                case 'R': name = "Tribler"; break;
398                case 'S': name = "Shad0w"; break;
399                case 'T': name = "BitTornado"; break;
400                case 'U': name = "UPnP NAT Bit Torrent"; break;
401            }
402
403            if( name )
404            {
405                tr_snprintf( buf, buflen, "%s %d.%d.%d", name, a, b, c );
406                return;
407            }
408        }
409    }
410
411    /* No match */
412    if( !*buf )
413    {
414        struct evbuffer * out = tr_getBuffer( );
415        const char *in, *in_end;
416        for( in=(const char*)id, in_end=in+8; in!=in_end; ++in ) {
417            if( isprint( *in ) )
418                evbuffer_add_printf( out, "%c", *in );
419            else
420                evbuffer_add_printf( out, "%%%02X", (unsigned int)*in );
421        }
422
423        tr_strlcpy( buf, EVBUFFER_DATA( out ), buflen );
424        tr_releaseBuffer( out );
425    }
426}
Note: See TracBrowser for help on using the repository browser.