source: trunk/libtransmission/magnet.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: 6.9 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: magnet.c 11709 2011-01-19 13:48:47Z jordan $
11 */
12
13#include <assert.h>
14#include <string.h> /* strchr() */
15
16#include "transmission.h"
17#include "bencode.h"
18#include "magnet.h"
19#include "utils.h"
20#include "web.h"
21
22/***
23****
24***/
25
26/* this base32 code converted from code by Robert Kaye and Gordon Mohr
27 * and is public domain. see http://bitzi.com/publicdomain for more info */
28
29static const int base32Lookup[] =
30{
31    0xFF,0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, /* '0', '1', '2', '3', '4', '5', '6', '7' */
32    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* '8', '9', ':', ';', '<', '=', '>', '?' */
33    0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06, /* '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G' */
34    0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, /* 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O' */
35    0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, /* 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W' */
36    0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF, /* 'X', 'Y', 'Z', '[', '\', ']', '^', '_' */
37    0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06, /* '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g' */
38    0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, /* 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' */
39    0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, /* 'p', 'q', 'r', 's', 't', 'u', 'v', 'w' */
40    0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF  /* 'x', 'y', 'z', '{', '|', '}', '~', 'DEL' */
41};
42
43static const int base32LookupLen = sizeof( base32Lookup ) / sizeof( base32Lookup[0] );
44
45static void
46base32_to_sha1( uint8_t * out, const char * in, const int inlen )
47{
48    const int outlen = 20;
49    int i, index, offset;
50
51    memset( out, 0, 20 );
52
53    assert( inlen == 32 );
54
55    for( i=0, index=0, offset=0; i<inlen; ++i )
56    {
57        int digit;
58        int lookup = in[i] - '0';
59
60        /* Skip chars outside the lookup table */
61        if( lookup<0 || lookup>=base32LookupLen )
62            continue;
63
64        /* If this digit is not in the table, ignore it */
65        digit = base32Lookup[lookup];
66        if( digit == 0xFF )
67            continue;
68
69        if( index <= 3 ) {
70            index = (index + 5) % 8;
71            if( index == 0 ) {
72                out[offset] |= digit;
73                offset++;
74                if( offset >= outlen )
75                    break;
76            } else {
77                out[offset] |= digit << (8 - index);
78            }
79        } else {
80            index = (index + 5) % 8;
81            out[offset] |= (digit >> index);
82            offset++;
83
84            if( offset >= outlen )
85                break;
86            out[offset] |= digit << (8 - index);
87       }
88   }
89}
90
91/***
92****
93***/
94
95#define MAX_TRACKERS 64
96#define MAX_WEBSEEDS 64
97
98tr_magnet_info *
99tr_magnetParse( const char * uri )
100{
101    tr_bool got_checksum = FALSE;
102    int trCount = 0;
103    int wsCount = 0;
104    char * tr[MAX_TRACKERS];
105    char * ws[MAX_WEBSEEDS];
106    char * displayName = NULL;
107    uint8_t sha1[SHA_DIGEST_LENGTH];
108    tr_magnet_info * info = NULL;
109
110    if( ( uri != NULL ) && !memcmp( uri, "magnet:?", 8 ) )
111    {
112        const char * walk;
113
114        for( walk=uri+8; walk && *walk; )
115        {
116            const char * key = walk;
117            const char * delim = strchr( key, '=' );
118            const char * val = delim == NULL ? NULL : delim + 1;
119            const char * next = strchr( delim == NULL ? key : val, '&' );
120            int keylen, vallen;
121
122            if( delim != NULL )
123                keylen = delim - key;
124            else if( next != NULL )
125                keylen = next - key;
126            else
127                keylen = strlen( key );
128
129            if( val == NULL )
130                vallen = 0;
131            else if( next != NULL )
132                vallen = next - val;
133            else
134                vallen = strlen( val );
135
136            if( ( keylen==2 ) && !memcmp( key, "xt", 2 ) && val && !memcmp( val, "urn:btih:", 9 ) )
137            {
138                const char * hash = val + 9;
139                const int hashlen = vallen - 9;
140
141                if( hashlen == 40 ) {
142                    tr_hex_to_sha1( sha1, hash );
143                    got_checksum = TRUE;
144                }
145                else if( hashlen == 32 ) {
146                    base32_to_sha1( sha1, hash, hashlen );
147                    got_checksum = TRUE;
148                }
149            }
150
151            if( ( keylen==2 ) && !memcmp( key, "dn", 2 ) )
152                displayName = tr_http_unescape( val, vallen );
153
154            if( trCount < MAX_TRACKERS ) {
155                int i;
156                if( ( keylen==2 ) && !memcmp( key, "tr", 2 ) )
157                    tr[trCount++] = tr_http_unescape( val, vallen );
158                else if( ( sscanf( key, "tr.%d=", &i ) == 1 ) && ( i > 0 ) ) /* ticket #3341 */
159                    tr[trCount++] = tr_http_unescape( val, vallen );
160            }
161
162            if( ( keylen==2 ) && !memcmp( key, "ws", 2 ) && ( wsCount < MAX_TRACKERS ) )
163                ws[wsCount++] = tr_http_unescape( val, vallen );
164
165            walk = next != NULL ? next + 1 : NULL;
166        }
167    }
168
169    if( got_checksum )
170    {
171        info = tr_new0( tr_magnet_info, 1 );
172        info->displayName = displayName;
173        info->trackerCount = trCount;
174        info->trackers = tr_memdup( tr, sizeof(char*) * trCount );
175        info->webseedCount = wsCount;
176        info->webseeds = tr_memdup( ws, sizeof(char*) * wsCount );
177        memcpy( info->hash, sha1, sizeof(uint8_t) * SHA_DIGEST_LENGTH );
178    }
179
180    return info;
181}
182
183void
184tr_magnetFree( tr_magnet_info * info )
185{
186    if( info != NULL )
187    {
188        int i;
189
190        for( i=0; i<info->trackerCount; ++i )
191            tr_free( info->trackers[i] );
192        tr_free( info->trackers );
193
194        for( i=0; i<info->webseedCount; ++i )
195            tr_free( info->webseeds[i] );
196        tr_free( info->webseeds );
197
198        tr_free( info->displayName );
199        tr_free( info );
200    }
201}
202
203void
204tr_magnetCreateMetainfo( const tr_magnet_info * info, tr_benc * top )
205{
206    int i;
207    tr_benc * d;
208    tr_bencInitDict( top, 4 );
209
210    /* announce list */
211    if( info->trackerCount == 1 )
212        tr_bencDictAddStr( top, "announce", info->trackers[0] );
213    else {
214        tr_benc * trackers = tr_bencDictAddList( top, "announce-list", info->trackerCount );
215        for( i=0; i<info->trackerCount; ++i )
216            tr_bencListAddStr( tr_bencListAddList( trackers, 1 ), info->trackers[i] );
217    }
218
219    /* webseeds */
220    if( info->webseedCount > 0 ) {
221        tr_benc * urls = tr_bencDictAddList( top, "url-list", info->webseedCount );
222        for( i=0; i<info->webseedCount; ++i )
223            tr_bencListAddStr( urls, info->webseeds[i] );
224    }
225
226    /* nonstandard keys */
227    d = tr_bencDictAddDict( top, "magnet-info", 2 );
228    tr_bencDictAddRaw( d, "info_hash", info->hash, 20 );
229    if( info->displayName != NULL )
230        tr_bencDictAddStr( d, "display-name", info->displayName );
231}
232
233
Note: See TracBrowser for help on using the repository browser.