source: trunk/libtransmission/clients.c @ 11709

Last change on this file since 11709 was 11709, checked in by jordan, 11 years ago

Update the copyright year in the source code comments.

The Berne Convention says that the copyright year is moot, so instead of adding another year to each file as in previous years, I've removed the year altogether from the source code comments in libtransmission, gtk, qt, utils, daemon, and cli.

Juliusz's copyright notice in tr-dht and Johannes' copyright notice in tr-lpd have been left alone; it didn't seem appropriate to modify them.

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