source: trunk/libtransmission/clients.c @ 3462

Last change on this file since 3462 was 3462, checked in by charles, 14 years ago

merge the wiki.theory.org, T, and libtorrent client lists. T knows about dozens more clients now.

  • Property svn:keywords set to Date Rev Author Id
File size: 14.0 KB
Line 
1/******************************************************************************
2 * $Id: clients.c 3462 2007-10-19 00:02:37Z charles $
3 *
4 * Copyright (c) 2005 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <ctype.h> /* isprint */
26#include <stdio.h>
27#include <stdlib.h> /* bsearch */
28#include <string.h>
29
30#include <sys/types.h> /* event.h needs this */
31#include <event.h>
32
33#include "transmission.h"
34#include "trcompat.h"
35#include "utils.h" /* tr_strdup */
36
37static int charToInt( char character )
38{
39    int value;
40    if( character >= 'A' && character <= 'Z' )
41        value = 10 + character - 'A';
42    else if( character >= 'a' && character <= 'z')
43        value = 36 + character - 'a';
44    else
45        value = character - '0';
46   
47    return value;
48}
49
50/*
51 * Azureus-style uses the following encoding: '-', two characters for client id,
52 * four ascii digits for version number, '-', followed by random numbers.
53 * For example: '-AZ2060-'...
54 */
55
56struct az_client
57{
58    const char * abbreviation;
59    int version_width[4];
60    const char * name;
61};
62
63static struct az_client azureus_clients[] =
64{
65    { "AG", {  1,  1,  1,  0 }, "Ares" },
66    { "AR", { -1, -1, -1, -1 }, "Arctic Torrent" },
67    { "AV", { -1, -1, -1, -1 }, "Avicora" },
68    { "AX", {  2,  2,  0,  0 }, "BitPump" },
69    { "AZ", {  1,  1,  1,  1 }, "Azureus" },
70    { "A~", {  1,  1,  1,  0 }, "Ares" },
71    { "BB", {  1,  3,  0,  0 }, "BitBuddy" },
72    { "BC", {  2,  2,  0,  0 }, "BitComet" },
73    { "BF", { -1, -1, -1, -1 }, "Bitflu" },
74    { "BG", {  1,  1,  1,  1 }, "BTG" },
75    { "BR", {  1,  1,  2,  0 }, "BitRocket" },
76    { "BS", { -1, -1, -1, -1 }, "BTSlave" },
77    { "BX", { -1, -1, -1, -1 }, "Bittorrent X" },
78    { "CD", {  2,  2,  0,  0 }, "Enhanced CTorrent" },
79    { "CT", {  1,  1,  2,  0 }, "CTorrent" },
80    { "DE", {  1,  1,  1,  1 }, "DelugeTorrent" },
81    { "DP", { -1, -1, -1, -1 }, "Propagate" },
82    { "EB", { -1, -1, -1, -1 }, "EBit" },
83    { "ES", {  1,  1,  1,  1 }, "Electric Sheep" },
84    { "FT", {  4,  0,  0,  0 }, "FoxTorrent" },
85    { "GR", {  1,  1,  1,  1 }, "GetRight" },
86    { "GS", {  4,  0,  0,  0 }, "GSTorrent" },
87    { "HL", {  1,  1,  1,  0 }, "Halite" },
88    { "HN", { -1, -1, -1, -1 }, "Hydranode" },
89    { "KT", {  1,  1,  1,  0 }, "KTorrent" },
90    { "LH", { -1, -1, -1, -1 }, "LH-ABC" },
91    { "LK", { -1, -1, -1, -1 }, "Linkage" },
92    { "LP", {  2,  2,  0,  0 }, "Lphant" },
93    { "LT", {  1,  1,  1,  1 }, "Libtorrent" },
94    { "LW", { -1, -1, -1, -1 }, "LimeWire" },
95    { "ML", { -1, -1, -1, -1 }, "MLDonkey" },
96    { "MO", { -1, -1, -1, -1 }, "MonoTorrent" },
97    { "MP", { -1, -1, -1, -1 }, "MooPolice" },
98    { "MT", { -1, -1, -1, -1 }, "MoonlightTorrent" },
99    { "PD", {  1,  1,  1,  1 }, "Pando" },
100    { "QD", { -1, -1, -1, -1 }, "QQDownload" },
101    { "QT", { -1, -1, -1, -1 }, "Qt 4 Torrent Example" },
102    { "RT", { -1, -1, -1, -1 }, "Retriever" },
103    { "SB", { -1, -1, -1, -1 }, "Swiftbit" },
104    { "SN", { -1, -1, -1, -1 }, "ShareNet" },
105    { "SS", { -1, -1, -1, -1 }, "SwarmScope" },
106    { "ST", { -1, -1, -1, -1 }, "SymTorrent" },
107    { "SZ", {  1,  1,  1,  1 }, "Shareaza" },
108    { "S~", {  1,  1,  1,  1 }, "Shareaza (beta)" },
109    { "TN", { -1, -1, -1, -1 }, "Torrent.Net" },
110    { "TR", {  1,  2,  1,  0 }, "Transmission" },
111    { "TS", {  1,  1,  1,  1 }, "TorrentStorm" },
112    { "TT", {  1,  1,  1,  1 }, "TuoTu" },
113    { "UL", { -1, -1, -1, -1 }, "uLeecher" },
114    { "UT", {  1,  2,  0,  0 }, "uTorrent" },
115    { "WT", { -1, -1, -1, -1 }, "BitLet" },
116    { "WY", { -1, -1, -1, -1 }, "FireTorrent" },
117    { "XL", { -1, -1, -1, -1 }, "Xunlei" },
118    { "XT", { -1, -1, -1, -1 }, "XanTorrent" },
119    { "XX", {  1,  1,  2,  0 }, "Xtorrent" },
120    { "ZT", { -1, -1, -1, -1 }, "ZipTorrent" },
121    { "lt", {  1,  1,  1,  1 }, "libTorrent" },
122    { "qB", {  1,  1,  1,  0 }, "qBittorrent" },
123    { "st", { -1, -1, -1, -1 }, "sharktorrent" }
124};
125
126static int
127isStyleAzureus( const uint8_t * id )
128{
129    return id[0]=='-' && id[7]=='-';
130}
131
132static char*
133getAzureusAbbreviation( const uint8_t * id, char * setme )
134{
135    setme[0] = id[1];
136    setme[1] = id[2];
137    setme[2] = '\0';
138    return setme;
139}
140
141static int
142compareAzureusAbbreviations( const void * va, const void * vb )
143{
144    const char * abbreviation = va;
145    const struct az_client * b = vb;
146    return strcmp( abbreviation, b->abbreviation );
147}
148
149static const struct az_client*
150getAzureusClient( const uint8_t * peer_id )
151{
152    const struct az_client * ret = NULL;
153   
154    if( isStyleAzureus( peer_id ) )
155    {
156        char abbreviation[3];
157        ret = bsearch( getAzureusAbbreviation( peer_id, abbreviation ),
158                       azureus_clients,
159                       sizeof(azureus_clients) / sizeof(azureus_clients[0]),
160                       sizeof(struct az_client),
161                       compareAzureusAbbreviations );
162    }
163
164    return ret;
165}
166
167
168struct generic_client
169{
170    int offset;
171    char const * id;
172    char const * name;
173};
174
175static struct generic_client generic_clients[] =
176{
177    { 0, "346-", "TorrentTopia" },
178    { 0, "10-------", "JVtorrent" },
179    { 0, "Deadman Walking-", "Deadman" },
180    { 5, "Azureus", "Azureus 2.0.3.2" },
181    { 0, "DansClient", "XanTorrent" },
182    { 4, "btfans", "SimpleBT" },
183    { 0, "eX", "eXeem" },
184    { 0, "PRC.P---", "Bittorrent Plus! II" },
185    { 0, "P87.P---", "Bittorrent Plus!" },
186    { 0, "S587Plus", "Bittorrent Plus!" },
187    { 0, "martini", "Martini Man" },
188    { 0, "Plus---", "Bittorrent Plus" },
189    { 0, "turbobt", "TurboBT" },
190    { 0, "a00---0", "Swarmy" },
191    { 0, "a02---0", "Swarmy" },
192    { 0, "T00---0", "Teeweety" },
193    { 0, "BTDWV-", "Deadman Walking" },
194    { 2, "BS", "BitSpirit" },
195    { 0, "Pando-", "Pando" },
196    { 0, "LIME", "LimeWire" },
197    { 0, "btuga", "BTugaXP" },
198    { 0, "oernu", "BTugaXP" },
199    { 0, "Mbrst", "Burst!" },
200    { 0, "PEERAPP", "PeerApp" },
201    { 0, "Plus", "Plus!" },
202    { 0, "-Qt-", "Qt" },
203    { 0, "exbc", "BitComet" },
204    { 0, "DNA", "BitTorrent DNA" },
205    { 0, "-G3", "G3 Torrent" },
206    { 0, "-FG", "FlashGet" },
207    { 0, "-ML", "MLdonkey" },
208    { 0, "XBT", "XBT" },
209    { 0, "OP", "Opera" },
210    { 2, "RS", "Rufus" }
211};
212
213/***
214****
215***/
216
217char*
218tr_clientForId( const uint8_t * id )
219{
220    char * ret = NULL;
221   
222    if( isStyleAzureus( id ) )
223    {
224        const struct az_client * client = getAzureusClient( id );
225
226        if( client != NULL )
227        {
228            struct evbuffer * buf = evbuffer_new( );
229
230            evbuffer_add_printf( buf, "%s ", client->name );
231
232            if( client->version_width[0] == -1 )
233                evbuffer_add( buf, id+3, 4 );
234            else {
235                int i, offset;
236                for( i=0, offset=3; i<4; ++i ) {
237                    const int width = client->version_width[i];
238                    const int isdigit = isdigit( id[offset] );
239                    if( !width )
240                        break;
241                    if( offset!=3 )
242                        evbuffer_add( buf, (isdigit?".":" "), 1 );
243                    if( !isdigit || width==1 || offset!=3 )
244                        evbuffer_add( buf, id+offset, width );
245                    else{
246                        char * tmp = tr_strndup( (char*)(id+offset), width );
247                        evbuffer_add_printf( buf, "%d", atoi(tmp) );
248                        tr_free( tmp );
249                    }
250                    offset += width;
251                }
252            }
253
254            evbuffer_add( buf, "\0", 1 );
255            ret = tr_strdup( (char*) EVBUFFER_DATA( buf ) );
256            evbuffer_free( buf );
257        }
258        else if( !memcmp( &id[1], "BF", 2 ) )
259        {
260            asprintf( &ret, "Bitflu (%d/%d/%02d)",
261                      charToInt( id[6] ),
262                      charToInt( id[4] ) * 10 + charToInt( id[5] ),
263                      charToInt( id[3] ) );
264        }
265        else if( !memcmp( &id[1], "BOW", 3 ) )
266        {
267            if( !memcmp( &id[4], "A0C", 3 ) )
268                asprintf( &ret, "Bits on Wheels 1.0.6" );
269            else if( !memcmp( &id[4], "A0B", 3 ) )
270                asprintf( &ret, "Bits on Wheels 1.0.5" );
271            else
272                asprintf( &ret, "Bits on Wheels (%3.3s", id+4 );
273        }
274        if( ret )
275        {
276fprintf( stderr, "peer_id [%8.8s] returns [%s]\n", id, ret );
277            return ret;
278        }
279    }
280
281    /* generic clients */
282    {
283        int i;
284        const int n = sizeof(generic_clients) / sizeof(generic_clients[0]);
285        for( i=0; !ret && i<n; ++i ) {
286            const struct generic_client * client = &generic_clients[i];
287            if( !memcmp( id+client->offset, client->id, strlen(client->id) ) )
288                ret = tr_strdup( client->name );
289        }
290
291        if( ret )
292            return ret;
293    }
294   
295    /* Tornado-style */
296    if( !memcmp( &id[4], "----", 4 ) || !memcmp( &id[4], "--0", 3 ) )
297    {
298        if( id[0] == 'T' )
299        {
300            asprintf( &ret, "BitTornado %d.%d.%d", charToInt( id[1] ),
301                        charToInt( id[2] ), charToInt( id[3] ) );
302        }
303        else if( id[0] == 'A' )
304        {
305            asprintf( &ret, "ABC %d.%d.%d", charToInt( id[1] ),
306                        charToInt( id[2] ), charToInt( id[3] ) );
307        }
308        else if( id[0] == 'R' )
309        {
310            asprintf( &ret, "Tribler %c.%c", id[1], id[2] );
311        }
312        else if( id[0] == 'S' )
313        {
314            asprintf( &ret, "Shad0w's Client %d.%d.%d", charToInt( id[1] ),
315                        charToInt( id[2] ), charToInt( id[3] ) );
316        }
317       
318        if( ret )
319        {
320            return ret;
321        }
322    }
323   
324    /* Different formatting per client */
325    if( id[0] == 'M' && id[2] == '-' && id[7] == '-' )
326    {
327        if( id[4] == '-' && id[6] == '-' )
328        {
329            asprintf( &ret, "BitTorrent %c.%c.%c", id[1], id[3], id[5] );
330        }
331        else if( id[5] == '-' )
332        {
333            asprintf( &ret, "BitTorrent %c.%c%c.%c", id[1], id[3], id[4], id[6] );
334        }
335       
336        if( ret )
337        {
338            return ret;
339        }
340    }
341    if( id[0] == 'Q' && id[2] == '-' && id[7] == '-' )
342    {
343        if( id[4] == '-' && id[6] == '-' )
344        {
345            asprintf( &ret, "Queen Bee %c.%c.%c", id[1], id[3], id[5] );
346        }
347        else if( id[5] == '-' )
348        {
349            asprintf( &ret, "Queen Bee %c.%c%c.%c", id[1], id[3], id[4], id[6] );
350        }
351       
352        if( ret )
353        {
354            return ret;
355        }
356    }
357   
358    /* All versions of each client are formatted the same */
359    if( !memcmp( id, "exbc", 4 ) )
360    {
361        asprintf( &ret, "%s %d.%02d",
362                    !memcmp( &id[6], "LORD", 4 ) ? "BitLord" : "BitComet",
363                    id[4], id[5] );
364    }
365    else if( !memcmp( id, "OP", 2 ) )
366    {
367        asprintf( &ret, "Opera (%c%c%c%c)", id[2], id[3], id[4], id[5] );
368    }
369    else if( !memcmp( id, "-ML", 3 ) )
370    {
371        asprintf( &ret, "MLDonkey %c%c%c%c%c",
372                  id[3], id[4], id[5], id[6], id[7] );
373    }
374    else if( !memcmp( id, "AZ", 2 ) && !memcmp( &id[6], "BT", 2 ) )
375    {
376        asprintf( &ret, "BitTyrant %c.%c.%c.%c",
377                    id[2], id[3], id[4], id[5] );
378    }
379    else if( !memcmp( id, "-FG", 3 ) )
380    {
381        asprintf( &ret, "FlashGet %d.%c%c",
382                  charToInt( id[3] ) * 10 + charToInt( id[4] ),
383                      id[5], id[6] );
384    }
385    else if( !memcmp( id, "DNA", 3 ) )
386    {
387        asprintf( &ret, "BitTorrent DNA %d.%d.%d", charToInt( id[3] ) * 10 + charToInt( id[4] ),
388                    charToInt( id[5] ) * 10 + charToInt( id[6] ), charToInt( id[7] ) * 10 + charToInt( id[8] ) );
389    }
390    else if( !memcmp( id, "Plus", 4 ) )
391    {
392        asprintf( &ret, "Plus! v2 %c.%c%c", id[4], id[5], id[6] );
393    }
394    else if( !memcmp( id, "XBT", 3 ) )
395    {
396        asprintf( &ret, "XBT Client %c%c%c%s", id[3], id[4], id[5],
397                    id[6] == 'd' ? " (debug)" : "" );
398    }
399    else if( !memcmp( id, "Mbrst", 5 ) )
400    {
401        asprintf( &ret, "burst! %c.%c.%c", id[5], id[7], id[9] );
402    }
403    else if( !memcmp( id, "btpd", 4 ) )
404    {
405        asprintf( &ret, "BT Protocol Daemon %c%c%c", id[5], id[6], id[7] );
406    }
407    else if( id[0] == 'Q' && !memcmp( &id[4], "--", 2 ) )
408    {
409        asprintf( &ret, "BTQueue %d.%d.%d", charToInt( id[1] ),
410                    charToInt( id[2] ), charToInt( id[3] ) );
411    }
412    else if( !memcmp( id, "BLZ", 3 ) )
413    {
414        asprintf( &ret, "Blizzard Downloader %d.%d", id[3] + 1, id[4] );
415    }
416    else if( '\0' == id[0] && !memcmp( &id[1], "BS", 2 ) )
417    {
418        asprintf( &ret, "BitSpirit %u", ( id[1] == 0 ? 1 : id[1] ) );
419    }
420
421    /* No match */
422    if( !ret )
423    {
424        if( isprint( id[0] ) && isprint( id[1] ) && isprint( id[2] ) &&
425            isprint( id[3] ) && isprint( id[4] ) && isprint( id[5] ) &&
426            isprint( id[6] ) && isprint( id[7] ) )
427        {
428            asprintf( &ret, "unknown client (%c%c%c%c%c%c%c%c)",
429                  id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7] );
430        }
431        else
432        {
433            asprintf( &ret, "unknown client (0x%02x%02x%02x%02x%02x%02x%02x%02x)",
434                  id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7] );
435        }
436    }
437
438    return ret;
439}
Note: See TracBrowser for help on using the repository browser.