st-transfer.c

来自「linux下网络收音机的源码」· C语言 代码 · 共 1,115 行 · 第 1/2 页

C
1,115
字号
/* * Deprecated. */gbooleanst_transfer_get_lines_with_session (STTransferSession *session,				    const char *url,				    STTransferLineCallback cb,				    gpointer data,				    GError **err){  g_return_val_if_fail(session != NULL, FALSE);  g_return_val_if_fail(url != NULL, FALSE);  g_return_val_if_fail(cb != NULL, FALSE);  return st_transfer_session_get_by_line_internal(session, url, 0, NULL, NULL, cb, data, err);}static char *st_transfer_get_header_charset (const char *header){  char *charset = NULL;  g_return_val_if_fail(header != NULL, NULL);  if (g_str_has_prefix(header, "Content-Type: "))    {      char *s;      s = sg_ascii_strcasestr(header + 14, "charset=");      if (s)	{	  char *end;	  s += 8;	  end = strstr(s, "\r\n");	  charset = end ? g_strndup(s, end - s) : g_strdup(s);	}    }  return charset;}static char *st_transfer_get_body_charset (const char *body){  char *charset = NULL;  char *s;  g_return_val_if_fail(body != NULL, NULL);    s = sg_ascii_strcasestr(body, "<meta http-equiv=\"content-type");  if (! s)    s = sg_ascii_strcasestr(body, "<meta http-equiv=\'content-type");      if (s)    {      s = sg_ascii_strcasestr(s + 17, "charset=");      if (s)	{	  char *end;	  s += 8;	  end = strpbrk(s, "'\"");	  if (end)	    charset = g_strndup(s, end - s);	}    }  return charset;}static voidst_transfer_line_data_init (STTransferLineData *data,			    STTransfer *transfer,			    STTransferSection section,			    STTransferLineCallback cb,			    gpointer cb_data){  g_return_if_fail(data != NULL);  g_return_if_fail(transfer != NULL);  data->transfer = transfer;  data->section = section;  data->line = g_string_new(NULL);  *data->terminator = 0;  data->line_cb = cb;  data->line_cb_data = cb_data;}static voidst_transfer_line_data_flush (STTransferLineData *data){  char *freeme = NULL;  const char *line = NULL;  g_return_if_fail(data != NULL);  if (data->transfer->flags & ST_TRANSFER_PASS_NEWLINE && *data->terminator)    g_string_append_len(data->line, data->terminator, sizeof(data->terminator));  switch (data->section)    {    case ST_TRANSFER_SECTION_HEADERS:      if (sg_ascii_validate(data->line->str))	{	  line = data->line->str;	  if (data->transfer->flags & (ST_TRANSFER_UTF8 | ST_TRANSFER_PARSE_HTTP_CHARSET)	      && ! data->transfer->header_charset)	    data->transfer->header_charset = st_transfer_get_header_charset(line);	}      else	st_notice(_("invalid ASCII in HTTP header"));      break;    case ST_TRANSFER_SECTION_BODY:      if (data->transfer->flags & ST_TRANSFER_UTF8)	{	  GError *err = NULL;	  if (data->transfer->flags & ST_TRANSFER_PARSE_HTML_CHARSET	      && ! data->transfer->body_charset)	    data->transfer->body_charset = st_transfer_get_body_charset(data->line->str);	  freeme = g_convert(data->line->str,			     data->line->len,			     "UTF-8",			     CHARSET(data->transfer->header_charset, data->transfer->body_charset),			     NULL,			     NULL,			     &err);	  if (freeme)	    line = freeme;	  else	    {	      st_notice(_("cannot convert a line of the HTTP body to UTF-8: %s"), err->message);	      g_error_free(err);	    }	}      else	line = data->line->str;      break;    default:      g_return_if_reached();    }    if (data->line_cb && line)    data->line_cb(line, data->line_cb_data);  g_string_truncate(data->line, 0);  *data->terminator = 0;  g_free(freeme);}static voidst_transfer_line_data_free (STTransferLineData *data, gboolean flush){  g_return_if_fail(data != NULL);  if (flush && *data->line->str)    st_transfer_line_data_flush(data);  g_string_free(data->line, TRUE);}static gbooleanst_transfer_session_get_by_line_internal (STTransferSession *session,					  const char *url,					  STTransferFlags flags,					  STTransferLineCallback header_cb,					  gpointer header_data,					  STTransferLineCallback body_cb,					  gpointer body_data,					  GError **err){  STTransfer transfer = { 0, };  STTransferLineData header_line_data;  STTransferLineData body_line_data;  gboolean status;  g_return_val_if_fail(session != NULL, FALSE);  g_return_val_if_fail(url != NULL, FALSE);    transfer.url = url;  transfer.flags = flags;  transfer.session = session;  if (header_cb || flags & (ST_TRANSFER_UTF8 | ST_TRANSFER_PARSE_HTTP_CHARSET))    {      st_transfer_line_data_init(&header_line_data, &transfer, ST_TRANSFER_SECTION_HEADERS, header_cb, header_data);      transfer.header_cb = st_transfer_session_get_by_line_cb;      transfer.header_data = &header_line_data;    }  if (body_cb)    {      st_transfer_line_data_init(&body_line_data, &transfer, ST_TRANSFER_SECTION_BODY, body_cb, body_data);      transfer.body_cb = st_transfer_session_get_by_line_cb;      transfer.body_data = &body_line_data;    }  status = st_transfer_perform(&transfer, err);    if (transfer.header_cb)    st_transfer_line_data_free(&header_line_data, status);  if (body_cb)    st_transfer_line_data_free(&body_line_data, status);  g_free(transfer.header_charset);  g_free(transfer.body_charset);    return status;}static gbooleanst_transfer_perform (STTransfer *transfer, GError **err){  int status;#ifndef ST_REGRESSION_TEST  char *hostname;#endif  g_return_val_if_fail(transfer != NULL, FALSE);  g_return_val_if_fail(transfer->url != NULL, FALSE);  g_return_val_if_fail(transfer->session != NULL, FALSE);#ifndef ST_REGRESSION_TEST  transfer->thread = st_thread_get();  g_return_val_if_fail(transfer->thread != NULL, FALSE);  if (st_thread_is_aborted(transfer->thread))    return FALSE;#endif /* ! ST_REGRESSION_TEST */#ifndef ST_REGRESSION_TEST  GDK_THREADS_ENTER();  st_thread_set_progress(transfer->thread, TRUE, 0);  gdk_flush();  GDK_THREADS_LEAVE();#endif /* ! ST_REGRESSION_TEST */  if (! st_transfer_set_proxy_settings(transfer))    {#ifndef ST_REGRESSION_TEST      GDK_THREADS_ENTER();      st_thread_abort(transfer->thread);      gdk_flush();      GDK_THREADS_LEAVE();#endif /* ! ST_REGRESSION_TEST */            return FALSE;		/* aborted */    }#ifndef ST_REGRESSION_TEST  hostname = st_transfer_get_hostname(transfer->url);  GDK_THREADS_ENTER();  st_thread_printf(transfer->thread, TRUE, _("Connecting to %s..."), hostname ? hostname : transfer->url);  gdk_flush();  GDK_THREADS_LEAVE();  g_free(hostname);#endif /* ! ST_REGRESSION_TEST */    curl_easy_setopt(transfer->session->handle, CURLOPT_USERAGENT, AGENT_STRING);  curl_easy_setopt(transfer->session->handle, CURLOPT_URL, transfer->url);  curl_easy_setopt(transfer->session->handle, CURLOPT_HEADERFUNCTION, transfer->header_cb);  curl_easy_setopt(transfer->session->handle, CURLOPT_HEADERDATA, transfer->header_data);  curl_easy_setopt(transfer->session->handle, CURLOPT_WRITEFUNCTION, transfer->body_cb);  curl_easy_setopt(transfer->session->handle, CURLOPT_WRITEDATA, transfer->body_data);  curl_easy_setopt(transfer->session->handle, CURLOPT_NOPROGRESS, FALSE);  curl_easy_setopt(transfer->session->handle, CURLOPT_PROGRESSFUNCTION, st_transfer_progress_cb);  curl_easy_setopt(transfer->session->handle, CURLOPT_PROGRESSDATA, transfer);  curl_easy_setopt(transfer->session->handle, CURLOPT_ERRORBUFFER, transfer->error);  curl_easy_setopt(transfer->session->handle, CURLOPT_PROXYTYPE, transfer->proxy_type);  curl_easy_setopt(transfer->session->handle, CURLOPT_PROXY, transfer->proxy_server);  curl_easy_setopt(transfer->session->handle, CURLOPT_PROXYPORT, transfer->proxy_port);  curl_easy_setopt(transfer->session->handle, CURLOPT_PROXYUSERPWD, transfer->proxy_userpwd);  curl_easy_setopt(transfer->session->handle, CURLOPT_COOKIEFILE, "");  curl_easy_setopt(transfer->session->handle, CURLOPT_FOLLOWLOCATION, TRUE);  curl_easy_setopt(transfer->session->handle, CURLOPT_NOBODY, transfer->body_cb == NULL);  curl_easy_setopt(transfer->session->handle, CURLOPT_ENCODING, "");  curl_easy_setopt(transfer->session->handle, CURLOPT_NOSIGNAL, TRUE);    status = curl_easy_perform(transfer->session->handle);    st_transfer_free_proxy_settings(transfer);  if (status != CURLE_OK      && status != CURLE_ABORTED_BY_CALLBACK#ifndef ST_REGRESSION_TEST      && ! st_thread_is_aborted(transfer->thread)#endif      )    g_set_error(err, 0, 0, "%s", transfer->error); /* failure which isn't abort */  return status == CURLE_OK;}static gbooleanst_transfer_set_proxy_settings (STTransfer *transfer){  gboolean status = TRUE;#ifndef ST_REGRESSION_TEST  gboolean proxy_enabled;  gboolean auth_enabled;  char *auth_name;  char *auth_password;#endif /* ! ST_REGRESSION_TEST */  g_return_val_if_fail(transfer != NULL, FALSE);#ifndef ST_REGRESSION_TEST  G_LOCK(st_settings);  proxy_enabled = st_settings.proxy_enabled;  if (proxy_enabled && st_settings.proxy_server)    {      transfer->proxy_type = st_settings.proxy_type;      transfer->proxy_server = g_strdup(st_settings.proxy_server);      transfer->proxy_port = st_settings.proxy_port;    }  auth_enabled = st_settings.proxy_auth_enabled;  auth_name = g_strdup(st_settings.proxy_auth_name);  auth_password = g_strdup(st_settings.proxy_auth_password);  G_UNLOCK(st_settings);    if (proxy_enabled && st_settings.proxy_server && auth_enabled)    {      char *name = NULL;      char *password = NULL;      if (auth_name && auth_password)	{	  name = g_strdup(auth_name);	  password = g_strdup(auth_password);	}      else	{	  GDK_THREADS_ENTER();	  st_thread_printf(transfer->thread, TRUE, _("Waiting for proxy password..."));	  gdk_flush();	  GDK_THREADS_LEAVE();	  st_auth_dialog(auth_name,			 auth_password,			 &name,			 &password,			 _("Password required"),			 _("Enter your username and password for proxy '%s'."),			 transfer->proxy_server);	}      if (name && password)	transfer->proxy_userpwd = g_strconcat(name, ":", password, NULL);      else			/* cancelled by user */	status = FALSE;      g_free(name);      g_free(password);    }  else    transfer->proxy_userpwd = g_strdup(""); /* libcurl crashes in handleSock5Proxy() if this is NULL */  g_free(auth_name);  g_free(auth_password);#endif /* ! ST_REGRESSION_TEST */  return status;}static voidst_transfer_free_proxy_settings (STTransfer *transfer){  g_return_if_fail(transfer != NULL);    g_free(transfer->proxy_server);  g_free(transfer->proxy_userpwd);}/** * st_transfer_escape: * @url: an URL or URL part to escape. * * Escapes unsafe characters of @url using standard percent notation. * * Return value: @url with unsafe characters escaped. The returned * string must be freed when no longer needed. **/char *st_transfer_escape (const char *url){  return curl_escape(url, 0);}static gbooleanst_transfer_progress_cb (gpointer data,			 double dltotal,			 double dlnow,			 double ultotal,			 double ulnow){#ifndef ST_REGRESSION_TEST  STTransfer *transfer = data;#endif  gboolean aborted;#ifdef ST_REGRESSION_TEST  aborted = FALSE;#else  aborted = st_thread_is_aborted(transfer->thread);  if (! aborted)    {      GDK_THREADS_ENTER();      if (sg_double_equal(dltotal, 0))	st_thread_printf(transfer->thread,			 TRUE,			 ngettext("Receiving (%u byte so far)...",				  "Receiving (%u bytes so far)...",				  (unsigned int) dlnow),			 (unsigned int) dlnow);      else	st_thread_printf(transfer->thread,			 TRUE,			 ngettext("Receiving (%u byte out of %u)...",				  "Receiving (%u bytes out of %u)...",				  (unsigned int) dlnow),			 (unsigned int) dlnow,			 (unsigned int) dltotal);	        if (! sg_double_equal(dlnow, transfer->downloaded))	{	  st_thread_set_progress(transfer->thread, TRUE, sg_double_equal(dltotal, 0) ? -1 : dlnow / dltotal);	  transfer->downloaded = dlnow;	}      gdk_flush();      GDK_THREADS_LEAVE();    }#endif /* ST_REGRESSION_TEST */  return aborted;}#ifndef ST_REGRESSION_TESTstatic char *st_transfer_get_hostname (const char *url){  char *s1;    g_return_val_if_fail(url != NULL, NULL);  if ((s1 = st_strstr_span(url, "://")))    {      char *s2;      return (s2 = strpbrk(s1, "/?"))	? g_strndup(s1, s2 - s1)	: g_strdup(s1);    }  else    return NULL;}#endif /* ! ST_REGRESSION_TEST */static size_tst_transfer_session_get_cb (const char *buffer,			    size_t size,			    size_t nitems,			    gpointer data){  GString *string = data;  size_t len;  len = size * nitems;  g_string_append_len(string, buffer, len);    return len;}static size_tst_transfer_session_get_binary_cb (const char *buffer,				   size_t size,				   size_t nitems,				   gpointer data){  GByteArray *array = data;  size_t len;  len = size * nitems;  g_byte_array_append(array, buffer, len);    return len;}static size_tst_transfer_session_get_by_line_cb (const char *buffer,				    size_t size,				    size_t nitems,				    gpointer data){  STTransferLineData *line_data = data;  size_t len;  int start = 0;  int i;  len = size * nitems;  /* handles lf (UNIX), crlf (DOS) and cr (Mac) terminators */  for (i = 0; i < len; i++)    {      gboolean processed = FALSE;      if (*line_data->terminator)	{	  if (buffer[i] == '\n' && *line_data->terminator == '\r')	    {	      line_data->terminator[1] = '\n';	      processed = TRUE;	      start = i + 1;	    }	  else	    start = i;	  st_transfer_line_data_flush(line_data);	}      if (! processed && (buffer[i] == '\n' || buffer[i] == '\r'))	{	  g_string_append_len(line_data->line, buffer + start, i - start);	  line_data->terminator[0] = buffer[i];	  line_data->terminator[1] = 0;	}    }  if (start < len)    g_string_append_len(line_data->line, buffer + start, len - start);    return len;}/*** private implementation **************************************************/voidst_transfer_init (void){  if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)    {#ifdef ST_REGRESSION_TEST      g_critical("unable to initialize libcurl");#else      st_error_dialog(_("A fatal error has occurred"),		      _("Unable to initialize the curl library."));      exit(1);#endif /* ST_REGRESSION_TEST */    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?