Пример #1
0
static tr_quark
append_new_quark (const void * str, size_t len)
{
  tr_quark ret;
  struct tr_key_struct * tmp;
  tmp = tr_new (struct tr_key_struct, 1);
  tmp->str = tr_strndup (str, len);
  tmp->len = len;
  ret = TR_N_KEYS + tr_ptrArraySize (&my_runtime);
  tr_ptrArrayAppend (&my_runtime, tmp);
  return ret;
}
Пример #2
0
static char*
makeURL( tr_webseed *    w,
         const tr_file * file )
{
    char *            ret;
    struct evbuffer * out = tr_getBuffer( );
    const char *      url = w->url;
    const size_t      url_len = strlen( url );

    evbuffer_add( out, url, url_len );

    /* if url ends with a '/', add the torrent name */
    if( url[url_len - 1] == '/' )
    {
        const char * str = file->name;

        /* this is like curl_escape() but doesn't munge the
         * '/' directory separators in the path */
        while( str && *str )
        {
            switch( *str )
            {
                case ',': case '-': case '.': case '/':
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                case 'a': case 'b': case 'c': case 'd': case 'e':
                case 'f': case 'g': case 'h': case 'i': case 'j':
                case 'k': case 'l': case 'm': case 'n': case 'o':
                case 'p': case 'q': case 'r': case 's': case 't':
                case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
                case 'A': case 'B': case 'C': case 'D': case 'E':
                case 'F': case 'G': case 'H': case 'I': case 'J':
                case 'K': case 'L': case 'M': case 'N': case 'O':
                case 'P': case 'Q': case 'R': case 'S': case 'T':
                case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
                    evbuffer_add( out, str, 1 );
                    break;
                default:
                    evbuffer_add_printf( out, "%%%02X", *str );
                    break;
            }
            str++;
        }
    }

    ret = tr_strndup( EVBUFFER_DATA( out ), EVBUFFER_LENGTH( out ) );
    tr_releaseBuffer( out );
    return ret;
}
Пример #3
0
static uint64_t
parseDownloadDir( tr_torrent *    tor,
                  const uint8_t * buf,
                  uint32_t        len )
{
    uint64_t ret = 0;

    if( buf && *buf && len )
    {
        tr_free( tor->downloadDir );
        tor->downloadDir = tr_strndup( (char*)buf, len );
        ret = TR_FR_DOWNLOAD_DIR;
    }

    return ret;
}
Пример #4
0
static char*
getOldTorrentFilename( const tr_handle * handle,
                       const tr_info *   inf )
{
    char *            ret;
    struct evbuffer * buf = evbuffer_new( );

    evbuffer_add_printf( buf, "%s%c%s", tr_getTorrentDir( handle ),
                         TR_PATH_DELIMITER,
                         inf->hashString );
    if( handle->tag )
        evbuffer_add_printf( buf, "-%s", handle->tag );

    ret = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
    evbuffer_free( buf );
    return ret;
}
Пример #5
0
static char*
getOldTorrentFilename( const tr_session * session,
                       const tr_info *   inf )
{
    char *            ret;
    struct evbuffer * buf = tr_getBuffer( );

    evbuffer_add_printf( buf, "%s%c%s", tr_getTorrentDir( session ),
                         TR_PATH_DELIMITER,
                         inf->hashString );
    if( session->tag )
        evbuffer_add_printf( buf, "-%s", session->tag );

    ret = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
    tr_releaseBuffer( buf );
    return ret;
}
Пример #6
0
static int tr_parser_parse_octal_literal(const char **str)
{
	const char *s;
	char *copy, *copy_end;
	size_t len = 0;
	unsigned int value;
	
	if(str == NULL || *str == NULL)
		return INVALID_CHAR;

	// Manually count the number of octal numerals.
	// That is needed because strtoul skips whitespace, which we must not do.				
	for(s = *str; *s != '\0' && *s >= '0' && *s <= '7'; s++)
		len++;

	if(len == 0)
		return INVALID_CHAR;

	copy = tr_strndup(*str, len);
	if(copy == NULL)
		return INVALID_CHAR;

	while(len > 0) {
		copy[len] = '\0';
		value = (unsigned int)strtoul(copy, &copy_end, 8);
		
		// strtol failed
		if(copy == copy_end) {
			value = INVALID_CHAR;
			break;
		// literal too large, try with one fewer character
		} else if(value > UCHAR_MAX) {
			len--;
		// all good
		} else {
			*str += (copy_end - copy);
			break;
		}
	}

	free(copy);
	return value;
}
Пример #7
0
static char*
makeURL( tr_webseed *    w,
         const tr_file * file )
{
    char *            ret;
    struct evbuffer * out = evbuffer_new( );
    const char *      url = w->url;
    const size_t      url_len = strlen( url );

    evbuffer_add( out, url, url_len );

    /* if url ends with a '/', add the torrent name */
    if( url[url_len - 1] == '/' && file->name )
        tr_http_escape( out, file->name, strlen(file->name), FALSE );

    ret = tr_strndup( EVBUFFER_DATA( out ), EVBUFFER_LENGTH( out ) );
    evbuffer_free( out );
    return ret;
}
Пример #8
0
static char*
replaceSubstr( const char * str, const char * in, const char * out )
{
    char * walk;
    struct evbuffer * buf = evbuffer_new( );
    const size_t inlen = strlen( in );
    const size_t outlen = strlen( out );

    while(( walk = strstr( str, in )))
    {
        evbuffer_add( buf, str, walk-str );
        evbuffer_add( buf, out, outlen );
        str = walk + inlen;
    }

    walk = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
    evbuffer_free( buf );
    return walk;
}
Пример #9
0
static char_class_t tr_parser_try_parse_class(const char **str,
										      tr_parser_error_t* error_out)
{
	const char* class_name_end;
	char* class_name;
	ptrdiff_t class_name_len;

	char_class_t char_class;

	if(str == NULL || *str == NULL)
		return CC_INVALID;	

	class_name_end = tr_parser_find_next_token(*str, ":]");
	if(class_name_end == NULL)
		return CC_INVALID;

	class_name_len = (class_name_end - *str);
	if(class_name_len == 0) {
		tr_parser_error(error_out, *str, "missing character class name");
		return CC_INVALID;
	}
		
	class_name = tr_strndup(*str, class_name_len);
	if(class_name == NULL) {
		tr_fatal_error("out of memory");
		return CC_INVALID;
	}
	
	char_class = char_class_get(class_name);				
	if(char_class == CC_INVALID) {
		tr_parser_error(error_out, *str, "invalid character class `%s`",
			            class_name);
				
		free(class_name);
		return CC_INVALID;
	}
	
	free(class_name);

	*str = class_name_end + 2;
	return char_class;
}
Пример #10
0
char *
tr_sys_path_dirname (const char  * path,
                     tr_error   ** error)
{
  if (path == NULL || path[0] == '\0')
    return tr_strdup (".");

  if (!is_valid_path (path))
    {
      set_system_error (error, ERROR_PATH_NOT_FOUND);
      return NULL;
    }

  const bool is_unc = is_unc_path (path);

  if (is_unc && path[2] == '\0')
    return tr_strdup (path);

  const char * end = path + strlen (path);
  while (end > path && is_slash (*(end - 1)))
    --end;

  if (end == path)
    return tr_strdup ("/");

  const char * name = end;
  while (name > path && *(name - 1) != ':' && !is_slash (*(name - 1)))
    --name;
  while (name > path && is_slash (*(name - 1)))
    --name;

  if (name == path)
    return tr_strdup (is_unc ? "\\\\" : ".");

  if (name > path && *(name - 1) == ':' && *name != '\0' && !is_slash (*name))
    return tr_strdup_printf ("%c:.", path[0]);

  return tr_strndup (path, name - path);
}
Пример #11
0
char* tr_sys_path_basename(char const* path, tr_error** error)
{
    if (path == NULL || path[0] == '\0')
    {
        return tr_strdup(".");
    }

    if (!is_valid_path(path))
    {
        set_system_error(error, ERROR_PATH_NOT_FOUND);
        return NULL;
    }

    char const* end = path + strlen(path);

    while (end > path && is_slash(*(end - 1)))
    {
        --end;
    }

    if (end == path)
    {
        return tr_strdup("/");
    }

    char const* name = end;

    while (name > path && *(name - 1) != ':' && !is_slash(*(name - 1)))
    {
        --name;
    }

    if (name == end)
    {
        return tr_strdup("/");
    }

    return tr_strndup(name, end - name);
}
Пример #12
0
static bool
path_contains_no_symlinks (const char * path)
{
  const char * p = path;

  while (*p != '\0')
    {
      tr_sys_path_info info;
      char * pathPart;
      const char * slashPos = strchr (p, '/');

#ifdef _WIN32

      const char * backslashPos = strchr (p, '\\');
      if (slashPos == NULL || (backslashPos != NULL && backslashPos < slashPos))
        slashPos = backslashPos;

#endif

      if (slashPos == NULL)
        slashPos = p + strlen (p) - 1;

      pathPart = tr_strndup (path, slashPos - path + 1);

      if (!tr_sys_path_get_info (pathPart, TR_SYS_PATH_NO_FOLLOW, &info, NULL) ||
          (info.type != TR_SYS_PATH_IS_FILE && info.type != TR_SYS_PATH_IS_DIRECTORY))
        {
          tr_free (pathPart);
          return false;
        }

      tr_free (pathPart);

      p = slashPos + 1;
    }

  return true;
}
Пример #13
0
static int
getfile( char **      setme,
         const char * root,
         tr_benc *    path )
{
    int err;

    if( !tr_bencIsList( path ) )
    {
        err = TR_EINVALID;
    }
    else
    {
        struct evbuffer * buf = evbuffer_new( );
        int               n = tr_bencListSize( path );
        int               i;

        evbuffer_add( buf, root, strlen( root ) );
        for( i = 0; i < n; ++i )
        {
            const char * str;
            if( tr_bencGetStr( tr_bencListChild( path, i ), &str )
              && strcmp( str, ".." ) )
            {
                evbuffer_add( buf, TR_PATH_DELIMITER_STR, 1 );
                evbuffer_add( buf, str, strlen( str ) );
            }
        }

        *setme = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
        /* fprintf( stderr, "[%s]\n", *setme ); */
        evbuffer_free( buf );
        err = 0;
    }

    return err;
}
Пример #14
0
static void
on_scrape_done (tr_session   * session,
                bool           did_connect,
                bool           did_timeout,
                long           response_code,
                const void   * msg,
                size_t         msglen,
                void         * vdata)
{
    tr_scrape_response * response;
    struct scrape_data * data = vdata;

    response = &data->response;
    response->did_connect = did_connect;
    response->did_timeout = did_timeout;
    dbgmsg (data->log_name, "Got scrape response for \"%s\"", response->url);

    if (response_code != HTTP_OK)
    {
        const char * fmt = _("Tracker gave HTTP response code %1$ld (%2$s)");
        const char * response_str = tr_webGetResponseStr (response_code);
        response->errmsg = tr_strdup_printf (fmt, response_code, response_str);
    }
    else
    {
        tr_variant top;
        int64_t intVal;
        tr_variant * files;
        tr_variant * flags;
        size_t len;
        const char * str;
        const bool variant_loaded = !tr_variantFromBenc (&top, msg, msglen);

        if (getenv ("TR_CURL_VERBOSE") != NULL)
        {
            if (!variant_loaded)
                fprintf (stderr, "%s", "Scrape response was not in benc format\n");
            else {
                int i, len;
                char * str = tr_variantToStr (&top, TR_VARIANT_FMT_JSON, &len);
                fprintf (stderr, "%s", "Scrape response:\n< ");
                for (i=0; i<len; ++i)
                    fputc (str[i], stderr);
                fputc ('\n', stderr);
                tr_free (str);
            }
        }

        if (variant_loaded)
        {
            if (tr_variantDictFindStr (&top, TR_KEY_failure_reason, &str, &len))
                response->errmsg = tr_strndup (str, len);

            if (tr_variantDictFindDict (&top, TR_KEY_flags, &flags))
                if (tr_variantDictFindInt (flags, TR_KEY_min_request_interval, &intVal))
                    response->min_request_interval = intVal;

            if (tr_variantDictFindDict (&top, TR_KEY_files, &files))
            {
                int i = 0;

                for (;;)
                {
                    int j;
                    tr_quark key;
                    tr_variant * val;

                    /* get the next "file" */
                    if (!tr_variantDictChild (files, i++, &key, &val))
                        break;

                    /* populate the corresponding row in our response array */
                    for (j=0; j<response->row_count; ++j)
                    {
                        struct tr_scrape_response_row * row = &response->rows[j];
                        if (!memcmp (tr_quark_get_string(key,NULL), row->info_hash, SHA_DIGEST_LENGTH))
                        {
                            if (tr_variantDictFindInt (val, TR_KEY_complete, &intVal))
                                row->seeders = intVal;
                            if (tr_variantDictFindInt (val, TR_KEY_incomplete, &intVal))
                                row->leechers = intVal;
                            if (tr_variantDictFindInt (val, TR_KEY_downloaded, &intVal))
                                row->downloads = intVal;
                            if (tr_variantDictFindInt (val, TR_KEY_downloaders, &intVal))
                                row->downloaders = intVal;
                            break;
                        }
                    }
                }
            }

            tr_variantFree (&top);
        }
    }

    tr_runInEventThread (session, on_scrape_done_eventthread, data);
}
Пример #15
0
static void
on_announce_done (tr_session   * session,
                  bool           did_connect,
                  bool           did_timeout,
                  long           response_code,
                  const void   * msg,
                  size_t         msglen,
                  void         * vdata)
{
    tr_announce_response * response;
    struct announce_data * data = vdata;

    response = &data->response;
    response->did_connect = did_connect;
    response->did_timeout = did_timeout;
    dbgmsg (data->log_name, "Got announce response");

    if (response_code != HTTP_OK)
    {
        const char * fmt = _("Tracker gave HTTP response code %1$ld (%2$s)");
        const char * response_str = tr_webGetResponseStr (response_code);
        response->errmsg = tr_strdup_printf (fmt, response_code, response_str);
    }
    else
    {
        tr_variant benc;
        const bool variant_loaded = !tr_variantFromBenc (&benc, msg, msglen);

        if (getenv ("TR_CURL_VERBOSE") != NULL)
        {
            if (!variant_loaded)
                fprintf (stderr, "%s", "Announce response was not in benc format\n");
            else {
                int i, len;
                char * str = tr_variantToStr (&benc, TR_VARIANT_FMT_JSON, &len);
                fprintf (stderr, "%s", "Announce response:\n< ");
                for (i=0; i<len; ++i)
                    fputc (str[i], stderr);
                fputc ('\n', stderr);
                tr_free (str);
            }
        }

        if (variant_loaded && tr_variantIsDict (&benc))
        {
            int64_t i;
            size_t len;
            tr_variant * tmp;
            const char * str;
            const uint8_t * raw;

            if (tr_variantDictFindStr (&benc, TR_KEY_failure_reason, &str, &len))
                response->errmsg = tr_strndup (str, len);

            if (tr_variantDictFindStr (&benc, TR_KEY_warning_message, &str, &len))
                response->warning = tr_strndup (str, len);

            if (tr_variantDictFindInt (&benc, TR_KEY_interval, &i))
                response->interval = i;

            if (tr_variantDictFindInt (&benc, TR_KEY_min_interval, &i))
                response->min_interval = i;

            if (tr_variantDictFindStr (&benc, TR_KEY_tracker_id, &str, &len))
                response->tracker_id_str = tr_strndup (str, len);

            if (tr_variantDictFindInt (&benc, TR_KEY_complete, &i))
                response->seeders = i;

            if (tr_variantDictFindInt (&benc, TR_KEY_incomplete, &i))
                response->leechers = i;

            if (tr_variantDictFindInt (&benc, TR_KEY_downloaded, &i))
                response->downloads = i;

            if (tr_variantDictFindRaw (&benc, TR_KEY_peers6, &raw, &len)) {
                dbgmsg (data->log_name, "got a peers6 length of %zu", len);
                response->pex6 = tr_peerMgrCompact6ToPex (raw, len,
                                              NULL, 0, &response->pex6_count);
            }

            if (tr_variantDictFindRaw (&benc, TR_KEY_peers, &raw, &len)) {
                dbgmsg (data->log_name, "got a compact peers length of %zu", len);
                response->pex = tr_peerMgrCompactToPex (raw, len,
                                               NULL, 0, &response->pex_count);
            } else if (tr_variantDictFindList (&benc, TR_KEY_peers, &tmp)) {
                response->pex = listToPex (tmp, &response->pex_count);
                dbgmsg (data->log_name, "got a peers list with %zu entries",
                        response->pex_count);
            }
        }

        if (variant_loaded)
            tr_variantFree (&benc);
    }

    tr_runInEventThread (session, on_announce_done_eventthread, data);
}
Пример #16
0
static int tr_parser_try_parse_repeat(const char **str,
									  unsigned int *repeat_count,
									  tr_parser_error_t* error_out)
{
	const char *repeat_start, *repeat_marker, *repeat_end;
	char *repeat_count_str;

	int c;

	if(str == NULL || *str == NULL)
		return INVALID_CHAR;

	// check for a valid repeat structure

	repeat_marker = tr_parser_find_next_token(*str, "*");
	if(repeat_marker == NULL)
		return INVALID_CHAR;

	repeat_end = tr_parser_find_next_token(repeat_marker + 1, "]");
	if(repeat_end == NULL)
		return INVALID_CHAR;
		
	repeat_start = *str;

	c = tr_parser_parse_one_char(&repeat_start, error_out);
	if(c == INVALID_CHAR) {
		tr_parser_error(error_out, repeat_start,
			            "repetition with no character");
		return INVALID_CHAR;
	}

	// copy 0 or more characters that lie between the asterisk and the closing
	// bracket.

	repeat_count_str = tr_strndup(repeat_marker + 1,
								  repeat_end - (repeat_marker + 1));
	if(repeat_count_str == NULL) {
		tr_fatal_error("out of memory");


		return INVALID_CHAR;
	}
	
	// no characters means an indefinite repetition, as does a repetition count
	// of zero.
	if (*repeat_count_str == '\0') {
		*repeat_count = 0;
	} else {
		char* repeat_count_str_end = NULL;

		*repeat_count = strtoul(repeat_count_str, &repeat_count_str_end, 0);
			
		// the repetition count should end right before the closing bracket
		if(repeat_count_str_end != repeat_end) {
			tr_parser_error(error_out, repeat_count_str,
							"invalid number of repetitions `%.*s`",
							(int)(repeat_end - repeat_count_str),
							repeat_count_str);

			*repeat_count = 0;
			return INVALID_CHAR;
		}
	}

	*str = repeat_end + 1;
	return c;
}
Пример #17
0
static void
addTask( void * vtask )
{
    struct tr_web_task * task = vtask;
    const tr_session * session = task->session;

    if( ( session == NULL ) || ( session->web == NULL ) )
        return;

    if( !task->resolved_host )
    {
        dbgmsg( "couldn't resolve host for \"%s\"... task failed", task->url );
        task_finish( task, 0 );
    }
    else
    {
        CURL * e = curl_easy_init( );
        struct tr_web * web = session->web;
        const int timeout = getTimeoutFromURL( task->url );
        const long verbose = getenv( "TR_CURL_VERBOSE" ) != NULL;
        const char * user_agent = TR_NAME "/" SHORT_VERSION_STRING;

        /* insert the resolved host into the URL s.t. curl's DNS won't block
         * even if -- like on most OSes -- it wasn't built with C-Ares :(
         * "http://www.craptrackular.org/announce?key=val&key2=..." becomes
         * "http://127.0.0.1/announce?key=val&key2=..." */
        {
            char * host;
            struct evbuffer * buf = evbuffer_new( );
            char * pch = strstr( task->url, task->host );
            char * tail = pch + strlen( task->host );
            evbuffer_add( buf, task->url, pch - task->url );
            evbuffer_add_printf( buf, "%s", task->resolved_host );
            evbuffer_add_printf( buf, "%s", tail );
            task->resolved_url = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
            dbgmsg( "old url: \"%s\" -- new url: \"%s\"", task->url, task->resolved_url );
            evbuffer_free( buf );

            /* Manually add a Host: argument that refers to the true URL */
            if( ( ( task->port <= 0 ) ) ||
                ( ( task->port == 80 ) && !strncmp( task->url, "http://", 7 ) ) ||
                ( ( task->port == 443 ) && !strncmp( task->url, "https://", 8 ) ) )
                host = tr_strdup_printf( "Host: %s", task->host );
            else
                host = tr_strdup_printf( "Host: %s:%d", task->host, task->port );

            task->slist = curl_slist_append( NULL, host );
            task->slist = curl_slist_append( task->slist, "Accept:" );
            curl_easy_setopt( e, CURLOPT_HTTPHEADER, task->slist );
            tr_free( host );
        }

        dbgmsg( "adding task #%lu [%s]", task->tag, task->resolved_url ? task->resolved_url : task->url );

        if( !task->range && session->isProxyEnabled ) {
            curl_easy_setopt( e, CURLOPT_PROXY, session->proxy );
            curl_easy_setopt( e, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
            curl_easy_setopt( e, CURLOPT_PROXYPORT, session->proxyPort );
            curl_easy_setopt( e, CURLOPT_PROXYTYPE,
                                      getCurlProxyType( session->proxyType ) );
        }
        if( !task->range && session->isProxyAuthEnabled ) {
            char * str = tr_strdup_printf( "%s:%s", session->proxyUsername,
                                                    session->proxyPassword );
            curl_easy_setopt( e, CURLOPT_PROXYUSERPWD, str );
            tr_free( str );
        }

        task->easy = e;
        task->multi = web->multi;

        /* use our own timeout instead of CURLOPT_TIMEOUT because the latter
         * doesn't play nicely with curl_multi.  See curl bug #2501457 */
        task->timer_event_isSet = TRUE;
        evtimer_set( &task->timer_event, task_timeout_cb, task );
        tr_timerAdd( &task->timer_event, timeout, 0 );

        curl_easy_setopt( e, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
        curl_easy_setopt( e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction );
        curl_easy_setopt( e, CURLOPT_SOCKOPTDATA, task );
        curl_easy_setopt( e, CURLOPT_WRITEDATA, task );
        curl_easy_setopt( e, CURLOPT_WRITEFUNCTION, writeFunc );
        curl_easy_setopt( e, CURLOPT_DNS_CACHE_TIMEOUT, MIN_DNS_CACHE_TIME );
        curl_easy_setopt( e, CURLOPT_FOLLOWLOCATION, 1L );
        curl_easy_setopt( e, CURLOPT_AUTOREFERER, 1L );
        curl_easy_setopt( e, CURLOPT_FORBID_REUSE, 1L );
        curl_easy_setopt( e, CURLOPT_MAXREDIRS, -1L );
        curl_easy_setopt( e, CURLOPT_PRIVATE, task );
        curl_easy_setopt( e, CURLOPT_SSL_VERIFYHOST, 0L );
        curl_easy_setopt( e, CURLOPT_SSL_VERIFYPEER, 0L );
        curl_easy_setopt( e, CURLOPT_URL, task->resolved_url ? task->resolved_url : task->url );
        curl_easy_setopt( e, CURLOPT_USERAGENT, user_agent );
        curl_easy_setopt( e, CURLOPT_VERBOSE, verbose );
        if( web->haveAddr )
            curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( &web->addr ) );
        if( task->range )
            curl_easy_setopt( e, CURLOPT_RANGE, task->range );

        if( curl_multi_add_handle( web->multi, e ) == CURLM_OK )
            ++web->taskCount;
    }
}
Пример #18
0
static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad)
{
    TR_ASSERT(tr_isTorrent(tor));

    size_t len;
    int64_t i;
    char const* str;
    char* filename;
    tr_variant top;
    bool boolVal;
    uint64_t fieldsLoaded = 0;
    bool const wasDirty = tor->isDirty;
    tr_error* error = NULL;

    filename = getResumeFilename(tor);

    if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, &error))
    {
        tr_logAddTorDbg(tor, "Couldn't read \"%s\": %s", filename, error->message);
        tr_error_free(error);

        tr_free(filename);
        return fieldsLoaded;
    }

    tr_logAddTorDbg(tor, "Read resume file \"%s\"", filename);

    if ((fieldsToLoad & TR_FR_CORRUPT) != 0 && tr_variantDictFindInt(&top, TR_KEY_corrupt, &i))
    {
        tor->corruptPrev = i;
        fieldsLoaded |= TR_FR_CORRUPT;
    }

    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR)) != 0 &&
        tr_variantDictFindStr(&top, TR_KEY_destination, &str, &len) && str != NULL && *str != '\0')
    {
        bool const is_current_dir = tor->currentDir == tor->downloadDir;
        tr_free(tor->downloadDir);
        tor->downloadDir = tr_strndup(str, len);

        if (is_current_dir)
        {
            tor->currentDir = tor->downloadDir;
        }

        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
    }

    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR)) != 0 &&
        tr_variantDictFindStr(&top, TR_KEY_incomplete_dir, &str, &len) && str != NULL && *str != '\0')
    {
        bool const is_current_dir = tor->currentDir == tor->incompleteDir;
        tr_free(tor->incompleteDir);
        tor->incompleteDir = tr_strndup(str, len);

        if (is_current_dir)
        {
            tor->currentDir = tor->incompleteDir;
        }

        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
    }

    if ((fieldsToLoad & TR_FR_DOWNLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloaded, &i))
    {
        tor->downloadedPrev = i;
        fieldsLoaded |= TR_FR_DOWNLOADED;
    }

    if ((fieldsToLoad & TR_FR_UPLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_uploaded, &i))
    {
        tor->uploadedPrev = i;
        fieldsLoaded |= TR_FR_UPLOADED;
    }

    if ((fieldsToLoad & TR_FR_MAX_PEERS) != 0 && tr_variantDictFindInt(&top, TR_KEY_max_peers, &i))
    {
        tor->maxConnectedPeers = i;
        fieldsLoaded |= TR_FR_MAX_PEERS;
    }

    if ((fieldsToLoad & TR_FR_RUN) != 0 && tr_variantDictFindBool(&top, TR_KEY_paused, &boolVal))
    {
        tor->isRunning = !boolVal;
        fieldsLoaded |= TR_FR_RUN;
    }

    if ((fieldsToLoad & TR_FR_ADDED_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_added_date, &i))
    {
        tor->addedDate = i;
        fieldsLoaded |= TR_FR_ADDED_DATE;
    }

    if ((fieldsToLoad & TR_FR_DONE_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_done_date, &i))
    {
        tor->doneDate = i;
        fieldsLoaded |= TR_FR_DONE_DATE;
    }

    if ((fieldsToLoad & TR_FR_ACTIVITY_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_activity_date, &i))
    {
        tr_torrentSetActivityDate(tor, i);
        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
    }

    if ((fieldsToLoad & TR_FR_TIME_SEEDING) != 0 && tr_variantDictFindInt(&top, TR_KEY_seeding_time_seconds, &i))
    {
        tor->secondsSeeding = i;
        fieldsLoaded |= TR_FR_TIME_SEEDING;
    }

    if ((fieldsToLoad & TR_FR_TIME_DOWNLOADING) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloading_time_seconds, &i))
    {
        tor->secondsDownloading = i;
        fieldsLoaded |= TR_FR_TIME_DOWNLOADING;
    }

    if ((fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY) != 0 &&
        tr_variantDictFindInt(&top, TR_KEY_bandwidth_priority, &i) && tr_isPriority(i))
    {
        tr_torrentSetPriority(tor, i);
        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
    }

    if ((fieldsToLoad & TR_FR_PEERS) != 0)
    {
        fieldsLoaded |= loadPeers(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_FILE_PRIORITIES) != 0)
    {
        fieldsLoaded |= loadFilePriorities(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_PROGRESS) != 0)
    {
        fieldsLoaded |= loadProgress(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_DND) != 0)
    {
        fieldsLoaded |= loadDND(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_SPEEDLIMIT) != 0)
    {
        fieldsLoaded |= loadSpeedLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_RATIOLIMIT) != 0)
    {
        fieldsLoaded |= loadRatioLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_IDLELIMIT) != 0)
    {
        fieldsLoaded |= loadIdleLimits(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_FILENAMES) != 0)
    {
        fieldsLoaded |= loadFilenames(&top, tor);
    }

    if ((fieldsToLoad & TR_FR_NAME) != 0)
    {
        fieldsLoaded |= loadName(&top, tor);
    }

    /* loading the resume file triggers of a lot of changes,
     * but none of them needs to trigger a re-saving of the
     * same resume information... */
    tor->isDirty = wasDirty;

    tr_variantFree(&top);
    tr_free(filename);
    return fieldsLoaded;
}
Пример #19
0
static void
handle_upload( struct evhttp_request * req,
               struct tr_rpc_server *  server )
{
    if( req->type != EVHTTP_REQ_POST )
    {
        send_simple_response( req, 405, NULL );
    }
    else
    {
        const char * content_type = evhttp_find_header( req->input_headers,
                                                        "Content-Type" );

        const char * query = strchr( req->uri, '?' );
        const int    paused = query && strstr( query + 1, "paused=true" );

        const char * in = (const char *) EVBUFFER_DATA( req->input_buffer );
        size_t       inlen = EVBUFFER_LENGTH( req->input_buffer );

        const char * boundary_key = "boundary=";
        const char * boundary_key_begin = strstr( content_type,
                                                  boundary_key );
        const char * boundary_val =
            boundary_key_begin ? boundary_key_begin +
            strlen( boundary_key ) : "arglebargle";

        char *       boundary = tr_strdup_printf( "--%s", boundary_val );
        const size_t boundary_len = strlen( boundary );

        const char * delim = tr_memmem( in, inlen, boundary, boundary_len );
        while( delim )
        {
            size_t       part_len;
            const char * part = delim + boundary_len;
            inlen -= ( part - in );
            in = part;
            delim = tr_memmem( in, inlen, boundary, boundary_len );
            part_len = delim ? (size_t)( delim - part ) : inlen;

            if( part_len )
            {
                char * text = tr_strndup( part, part_len );
                if( strstr( text, "filename=\"" ) )
                {
                    const char * body = strstr( text, "\r\n\r\n" );
                    if( body )
                    {
                        char * b64;
                        size_t  body_len;
                        tr_benc top, *args;
                        struct evbuffer * json = tr_getBuffer( );

                        body += 4; /* walk past the \r\n\r\n */
                        body_len = part_len - ( body - text );
                        if( body_len >= 2
                          && !memcmp( &body[body_len - 2], "\r\n", 2 ) )
                            body_len -= 2;

                        tr_bencInitDict( &top, 2 );
                        args = tr_bencDictAddDict( &top, "arguments", 2 );
                        tr_bencDictAddStr( &top, "method", "torrent-add" );
                        b64 = tr_base64_encode( body, body_len, NULL );
                        tr_bencDictAddStr( args, "metainfo", b64 );
                        tr_bencDictAddInt( args, "paused", paused );
                        tr_bencSaveAsJSON( &top, json );
                        tr_rpc_request_exec_json( server->session,
                                                  EVBUFFER_DATA( json ),
                                                  EVBUFFER_LENGTH( json ),
                                                  NULL, NULL );

                        tr_releaseBuffer( json );
                        tr_free( b64 );
                        tr_bencFree( &top );
                    }
                }
                tr_free( text );
            }
        }

        tr_free( boundary );

        /* use xml here because json responses to file uploads is trouble.
         * see http://www.malsup.com/jquery/form/#sample7 for details */
        evhttp_add_header( req->output_headers, "Content-Type",
                           "text/xml; charset=UTF-8" );
        send_simple_response( req, HTTP_OK, NULL );
    }
}