static void uriSchemeRequestCallback(WebKitURISchemeRequest* request, gpointer userData)
    {
        URISchemeTest* test = static_cast<URISchemeTest*>(userData);
        test->m_uriSchemeRequest = request;
        test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));

        g_assert(webkit_uri_scheme_request_get_web_view(request) == test->m_webView);

        GRefPtr<GInputStream> inputStream = adoptGRef(g_memory_input_stream_new());
        test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(inputStream.get()));

        const char* scheme = webkit_uri_scheme_request_get_scheme(request);
        g_assert(scheme);
        g_assert(test->m_handlersMap.contains(String::fromUTF8(scheme)));

        if (!g_strcmp0(scheme, "error")) {
            GUniquePtr<GError> error(g_error_new_literal(g_quark_from_string(errorDomain), errorCode, errorMessage));
            webkit_uri_scheme_request_finish_error(request, error.get());
            return;
        }

        const URISchemeHandler& handler = test->m_handlersMap.get(String::fromUTF8(scheme));

        if (!g_strcmp0(scheme, "echo")) {
            char* replyHTML = g_strdup_printf(handler.reply.data(), webkit_uri_scheme_request_get_path(request));
            g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(inputStream.get()), replyHTML, strlen(replyHTML), g_free);
        } else if (!g_strcmp0(scheme, "closed"))
            g_input_stream_close(inputStream.get(), 0, 0);
        else if (!handler.reply.isNull())
            g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(inputStream.get()), handler.reply.data(), handler.reply.length(), 0);

        webkit_uri_scheme_request_finish(request, inputStream.get(), handler.replyLength, handler.mimeType.data());
    }
void WebSoupRequestManager::didHandleURIRequest(const IPC::DataReference& requestData, uint64_t contentLength, const String& mimeType, uint64_t requestID)
{
    WebSoupRequestAsyncData* data = m_requestMap.get(requestID);
    ASSERT(data);
    GRefPtr<GTask> task = data->releaseTask();
    ASSERT(task.get());

    WebKitSoupRequestGeneric* request = WEBKIT_SOUP_REQUEST_GENERIC(g_task_get_source_object(task.get()));
    webkitSoupRequestGenericSetContentLength(request, contentLength ? contentLength : -1);
    webkitSoupRequestGenericSetContentType(request, !mimeType.isEmpty() ? mimeType.utf8().data() : 0);

    GInputStream* dataStream;
    if (!requestData.size()) {
        // Empty reply, just create and empty GMemoryInputStream.
        dataStream = g_memory_input_stream_new();
        m_requestMap.remove(requestID);
    } else if (requestData.size() == contentLength) {
        // We don't expect more data, so we can just create a GMemoryInputStream with all the data.
        dataStream = g_memory_input_stream_new_from_data(g_memdup(requestData.data(), requestData.size()), contentLength, g_free);
        m_requestMap.remove(requestID);
    } else {
        // We expect more data chunks from the UI process.
        dataStream = webkitSoupRequestInputStreamNew(contentLength);
        data->stream = dataStream;
        webkitSoupRequestInputStreamAddData(WEBKIT_SOUP_REQUEST_INPUT_STREAM(dataStream), requestData.data(), requestData.size());
    }
    g_task_return_pointer(task.get(), dataStream, g_object_unref);
}
Beispiel #3
0
static void
save_snapshot_get_message_cb (EMsgComposer *composer,
                              GAsyncResult *result,
                              GSimpleAsyncResult *simple)
{
	SaveContext *context;
	CamelMimeMessage *message;
	GInputStream *input_stream;
	CamelStream *camel_stream;
	GByteArray *buffer;
	GError *local_error = NULL;

	context = g_simple_async_result_get_op_res_gpointer (simple);

	message = e_msg_composer_get_message_draft_finish (
		composer, result, &local_error);

	if (local_error != NULL) {
		g_warn_if_fail (message == NULL);
		g_simple_async_result_take_error (simple, local_error);
		g_simple_async_result_complete (simple);
		g_object_unref (simple);
		return;
	}

	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));

	/* Decode the message to an in-memory buffer.  We have to do this
	 * because CamelStreams are synchronous-only, and using threads is
	 * dangerous because CamelDataWrapper is not reentrant. */
	buffer = g_byte_array_new ();
	camel_stream = camel_stream_mem_new ();
	camel_stream_mem_set_byte_array (
		CAMEL_STREAM_MEM (camel_stream), buffer);
	camel_data_wrapper_decode_to_stream_sync (
		CAMEL_DATA_WRAPPER (message), camel_stream, NULL, NULL);
	g_object_unref (camel_stream);

	g_object_unref (message);

	/* Load the buffer into a GMemoryInputStream. */
	input_stream = g_memory_input_stream_new ();
	if (buffer->len > 0)
		g_memory_input_stream_add_data (
			G_MEMORY_INPUT_STREAM (input_stream),
			buffer->data, (gssize) buffer->len,
			(GDestroyNotify) g_free);
	g_byte_array_free (buffer, FALSE);

	/* Splice the input and output streams. */
	g_output_stream_splice_async (
		context->output_stream, input_stream,
		G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
		G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
		G_PRIORITY_DEFAULT, context->cancellable,
		(GAsyncReadyCallback) save_snapshot_splice_cb,
		simple);

	g_object_unref (input_stream);
}
Beispiel #4
0
static gboolean
myopen(FetchData *fetch_data, GError **error)
{
    g_return_val_if_fail(fetch_data != NULL, FALSE);
    g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
    CURLMcode res;
    gchar ebuf[CURL_ERROR_SIZE];
    struct curl_data *cd = fetch_data->private_data;
    CURLM *curlm = cd->curlm;
    CURL *curl = curl_easy_init();

    fetch_data->istream = g_memory_input_stream_new();
    curl_easy_setopt(curl, CURLOPT_URL, fetch_data->url->uri);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cwrite_callback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fetch_data->istream);
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ebuf);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);

    if (fetch_data->ssl_verify == FALSE) {
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    }

    res = curl_multi_add_handle(curlm, curl);

    if (res != CURLM_OK) {
        g_set_error(error, RESTRAINT_FETCH_LIBARCHIVE_ERROR, 0,
                "Failed to fetch url: %s", ebuf);
        return FALSE;
    }

    return TRUE;
}
static gboolean
sysroot_setup_stdout_redirect (RpmostreedSysroot *self,
                               GError **error)
{
  g_autoptr(GInputStream) stream = NULL;
  g_autoptr(GSource) source = NULL;
  StdoutClosure *closure;
  gint pipefd[2];
  gboolean ret = FALSE;

  /* XXX libostree logs messages to systemd's journal and also to stdout.
   *     Redirect our own stdout back to ourselves so we can capture those
   *     messages and pass them on to clients.  Admittedly hokey but avoids
   *     hacking libostree directly (for now). */

  closure = g_slice_new0 (StdoutClosure);
  g_weak_ref_set (&closure->sysroot, self);

  /* Save the real stdout before overwriting its file descriptor. */
  closure->real_stdout = g_unix_output_stream_new (dup (STDOUT_FILENO), FALSE);

  if (pipe (pipefd) < 0)
    {
      glnx_set_prefix_error_from_errno (error, "%s", "pipe() failed");
      goto out;
    }

  if (dup2 (pipefd[1], STDOUT_FILENO) < 0)
    {
      glnx_set_prefix_error_from_errno (error, "%s", "dup2() failed");
      goto out;
    }

  stream = g_memory_input_stream_new ();
  closure->data_stream = g_data_input_stream_new (stream);
  g_clear_object (&stream);

  stream = g_unix_input_stream_new (pipefd[0], FALSE);

  source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (stream),
                                                  NULL);
  /* Transfer ownership of the StdoutClosure. */
  g_source_set_callback (source,
                         (GSourceFunc) sysroot_stdout_ready_cb,
                         closure,
                         (GDestroyNotify) stdout_closure_free);
  closure = NULL;

  self->stdout_source_id = g_source_attach (source, NULL);

  ret = TRUE;

out:
  if (closure != NULL)
    stdout_closure_free (closure);

  return ret;
}
Beispiel #6
0
static GIOStream*
get_memory_stream (void)
{
  GInputStream *istream = g_memory_input_stream_new ();
  GOutputStream *ostream = g_memory_output_stream_new_resizable ();

  GIOStream *stream = g_simple_io_stream_new (istream, ostream);

  g_object_unref (istream);
  g_object_unref (ostream);

  return stream;
}
Beispiel #7
0
static GInputStream *
soup_request_data_send (SoupRequest   *request,
			GCancellable  *cancellable,
			GError       **error)
{
	SoupRequestData *data = SOUP_REQUEST_DATA (request);
	SoupURI *uri = soup_request_get_uri (request);
	GInputStream *memstream;
	const char *comma, *start, *end;
	gboolean base64 = FALSE;
	char *uristr;

	uristr = soup_uri_to_string (uri, FALSE);
	start = uristr + 5;
	comma = strchr (start, ',');
	if (comma && comma != start) {
		/* Deal with MIME type / params */
		if (comma >= start + BASE64_INDICATOR_LEN && !g_ascii_strncasecmp (comma - BASE64_INDICATOR_LEN, BASE64_INDICATOR, BASE64_INDICATOR_LEN)) {
			end = comma - BASE64_INDICATOR_LEN;
			base64 = TRUE;
		} else
			end = comma;

		if (end != start)
			data->priv->content_type = soup_uri_decoded_copy (start, end - start, NULL);
	}

	memstream = g_memory_input_stream_new ();

	if (comma)
		start = comma + 1;

	if (*start) {
		int decoded_length = 0;
		guchar *buf = (guchar *) soup_uri_decoded_copy (start, strlen (start),
								&decoded_length);

		if (base64)
			buf = g_base64_decode_inplace ((gchar*) buf, &data->priv->content_length);
		else
			data->priv->content_length = decoded_length;

		g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (memstream),
						buf, data->priv->content_length,
						g_free);
	}
	g_free (uristr);

	return memstream;
}
    static void uriSchemeRequestCallback(WebKitURISchemeRequest* request, gpointer userData)
    {
        URISchemeTest* test = static_cast<URISchemeTest*>(userData);
        test->m_uriSchemeRequest = request;
        test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request));

        g_assert(webkit_uri_scheme_request_get_web_view(request) == test->m_webView);

        const char* scheme = webkit_uri_scheme_request_get_scheme(request);
        g_assert(scheme);
        g_assert(test->m_handlersMap.contains(String::fromUTF8(scheme)));

        const URISchemeHandler& handler = test->m_handlersMap.get(String::fromUTF8(scheme));

        GRefPtr<GInputStream> inputStream = adoptGRef(g_memory_input_stream_new());
        test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(inputStream.get()));

        const gchar* requestPath = webkit_uri_scheme_request_get_path(request);

        if (!g_strcmp0(scheme, "error")) {
            if (!g_strcmp0(requestPath, "before-response")) {
                GUniquePtr<GError> error(g_error_new_literal(g_quark_from_string(errorDomain), errorCode, beforeReceiveResponseErrorMessage));
                // We call finish() and then finish_error() to make sure that not even
                // the didReceiveResponse message is processed at the time of failing.
                webkit_uri_scheme_request_finish(request, G_INPUT_STREAM(inputStream.get()), handler.replyLength, handler.mimeType.data());
                webkit_uri_scheme_request_finish_error(request, error.get());
            } else if (!g_strcmp0(requestPath, "after-first-chunk")) {
                g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(inputStream.get()), handler.reply.data(), handler.reply.length(), 0);
                webkit_uri_scheme_request_finish(request, inputStream.get(), handler.replyLength, handler.mimeType.data());
                // We need to wait until we reach the load-committed state before calling webkit_uri_scheme_request_finish_error(),
                // so we rely on the test using finishOnCommittedAndWaitUntilLoadFinished() to actually call it from loadCommitted().
            } else {
                GUniquePtr<GError> error(g_error_new_literal(g_quark_from_string(errorDomain), errorCode, genericErrorMessage));
                webkit_uri_scheme_request_finish_error(request, error.get());
            }
            return;
        }

        if (!g_strcmp0(scheme, "echo")) {
            char* replyHTML = g_strdup_printf(handler.reply.data(), requestPath);
            g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(inputStream.get()), replyHTML, strlen(replyHTML), g_free);
        } else if (!g_strcmp0(scheme, "closed"))
            g_input_stream_close(inputStream.get(), 0, 0);
        else if (!handler.reply.isNull())
            g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(inputStream.get()), handler.reply.data(), handler.reply.length(), 0);

        webkit_uri_scheme_request_finish(request, inputStream.get(), handler.replyLength, handler.mimeType.data());
    }
static VALUE
rg_initialize(int argc, VALUE *argv, VALUE self)
{
        VALUE data;

        rb_scan_args(argc, argv, "01", &data);
        if (NIL_P(data)) {
                G_INITIALIZE(self, g_memory_input_stream_new());
                return Qnil;
        }

        StringValue(data);
        G_RELATIVE(self, data);
        G_INITIALIZE(self, g_memory_input_stream_new_from_data(RSTRING_PTR(data),
                                                               RSTRING_LEN(data),
                                                               NULL));

        return Qnil;
}
void CustomProtocolManagerImpl::didLoadData(uint64_t customProtocolID, const IPC::DataReference& dataReference)
{
    WebSoupRequestAsyncData* data = m_customProtocolMap.get(customProtocolID);
    // The data might have been removed from the request map if a previous chunk failed
    // and a new message was sent by the UI process before being notified about the failure.
    if (!data)
        return;

    if (!data->stream) {
        GRefPtr<GTask> task = data->releaseTask();
        ASSERT(task.get());

        goffset soupContentLength = soup_request_get_content_length(SOUP_REQUEST(g_task_get_source_object(task.get())));
        uint64_t contentLength = soupContentLength == -1 ? 0 : static_cast<uint64_t>(soupContentLength);
        if (!dataReference.size()) {
            // Empty reply, just create and empty GMemoryInputStream.
            data->stream = g_memory_input_stream_new();
        } else if (dataReference.size() == contentLength) {
            // We don't expect more data, so we can just create a GMemoryInputStream with all the data.
            data->stream = g_memory_input_stream_new_from_data(g_memdup(dataReference.data(), dataReference.size()), contentLength, g_free);
        } else {
            // We expect more data chunks from the UI process.
            data->stream = webkitSoupRequestInputStreamNew(contentLength);
            webkitSoupRequestInputStreamAddData(WEBKIT_SOUP_REQUEST_INPUT_STREAM(data->stream.get()), dataReference.data(), dataReference.size());
        }
        g_task_return_pointer(task.get(), data->stream.get(), g_object_unref);
        return;
    }

    if (data->requestFailed()) {
        // ResourceRequest failed or it was cancelled. It doesn't matter here the error or if it was cancelled,
        // because that's already handled by the resource handle client, we just want to notify the UI process
        // to stop reading data from the user input stream. If UI process already sent all the data we simply
        // finish silently.
        if (!webkitSoupRequestInputStreamFinished(WEBKIT_SOUP_REQUEST_INPUT_STREAM(data->stream.get())))
            m_childProcess->send(Messages::CustomProtocolManagerProxy::StopLoading(customProtocolID), 0);

        return;
    }

    webkitSoupRequestInputStreamAddData(WEBKIT_SOUP_REQUEST_INPUT_STREAM(data->stream.get()), dataReference.data(), dataReference.size());
}
Beispiel #11
0
static void ekg_gnutls_async_handshake(struct ekg_gnutls_connection_starter *gcs) {
	gint ret = gnutls_handshake(gcs->conn->session);

	switch (ret) {
		case GNUTLS_E_SUCCESS:
			{
				struct ekg_gnutls_connection *gc = gcs->conn;
				struct ekg_connection_starter *cs = gcs->parent;

				GInputStream *mi = g_memory_input_stream_new();
				GOutputStream *mo = g_memory_output_stream_new(
						NULL, 0, g_realloc, g_free);

					/* set streams */
				gc->instream = G_MEMORY_INPUT_STREAM(mi);
				gc->outstream = G_MEMORY_OUTPUT_STREAM(mo);

					/* switch handlers */
				gc->connection->callback = ekg_gnutls_handle_data;
				gc->connection->failure_callback = ekg_gnutls_handle_data_failure;
				gc->connection->priv_data = gc;
				gc->connection->flush_handler = ekg_gnutls_flush;

					/* this cleans up the socket, and cs */
				succeeded_async_connect(gcs->sockclient, gc->connection->conn,
						cs, mi, mo);
					/* and this cleans up gcs */
				ekg_gnutls_free_connection_starter(gcs);
			}
			break;
		case GNUTLS_E_AGAIN:
		case GNUTLS_E_INTERRUPTED:
			break;
		default:
			{
				GError *err = g_error_new_literal(EKG_GNUTLS_ERROR,
						ret, gnutls_strerror(ret));
				ekg_gnutls_handle_handshake_failure(NULL, err, gcs);
				g_error_free(err);
			}
	}
}
static gboolean
fr_command_unarchiver_list (FrCommand  *comm)
{
	FrCommandUnarchiver *unar_comm = FR_COMMAND_UNARCHIVER (comm);

	_g_object_unref (unar_comm->stream);
	unar_comm->stream = g_memory_input_stream_new ();

	fr_process_set_out_line_func (comm->process, process_line, comm);

	fr_process_begin_command (comm->process, "lsar");
	fr_process_set_end_func (comm->process, list_command_completed, comm);
	fr_process_add_arg (comm->process, "-j");
	if ((FR_ARCHIVE (comm)->password != NULL) && (FR_ARCHIVE (comm)->password[0] != '\0'))
		fr_process_add_arg_concat (comm->process, "-password=", FR_ARCHIVE (comm)->password, NULL);
	fr_process_add_arg (comm->process, comm->filename);
	fr_process_end_command (comm->process);

	return TRUE;
}
Beispiel #13
0
static GdkPixbuf*
load_pixbuf_from_archive(const char* archive, const char* file)
{
  if (archive == NULL || file == NULL) {
    return NULL;
  }

  struct archive* a = archive_read_new();
  if (a == NULL) {
    return NULL;
  }

  archive_read_support_filter_all(a);
  archive_read_support_format_all(a);
  int r = archive_read_open_filename(a, archive, LIBARCHIVE_BUFFER_SIZE);
  if (r != ARCHIVE_OK) {
    return NULL;
  }

  struct archive_entry* entry = NULL;
  while ((r = archive_read_next_header(a, &entry)) != ARCHIVE_EOF) {
    if (r < ARCHIVE_WARN) {
      archive_read_close(a);
      archive_read_free(a);
      return NULL;
    }

    const char* path = archive_entry_pathname(entry);
    if (compare_path(path, file) != 0) {
      continue;
    }

    GInputStream* is = g_memory_input_stream_new();
    if (is == NULL) {
      archive_read_close(a);
      archive_read_free(a);
      return NULL;
    }
    GMemoryInputStream* mis = G_MEMORY_INPUT_STREAM(is);

    size_t size = 0;
    const void* buf = NULL;
    off_t offset = 0;
    while ((r = archive_read_data_block(a, &buf, &size, &offset)) != ARCHIVE_EOF) {
      if (r < ARCHIVE_WARN) {
        archive_read_close(a);
        archive_read_free(a);
        g_object_unref(mis);
        return NULL;
      }

      if (size == 0) {
        continue;
      }

      void* tmp = g_malloc0(size);
      if (tmp == NULL) {
        archive_read_close(a);
        archive_read_free(a);
        g_object_unref(mis);
        return NULL;
      }

      memcpy(tmp, buf, size);
      g_memory_input_stream_add_data(mis, tmp, size, g_free);
    }

    GdkPixbuf* pixbuf = gdk_pixbuf_new_from_stream(is, NULL, NULL);
    if (pixbuf == NULL) {
      archive_read_close(a);
      archive_read_free(a);
      g_object_unref(mis);
      return NULL;
    }

    archive_read_close(a);
    archive_read_free(a);
    g_object_unref(mis);
    return pixbuf;
  }

  archive_read_close(a);
  archive_read_free(a);
  return NULL;
}
Beispiel #14
0
static GInputStream *
soup_request_data_send (SoupRequest   *request,
			GCancellable  *cancellable,
			GError       **error)
{
	SoupRequestData *data = SOUP_REQUEST_DATA (request);
	SoupURI *uri = soup_request_get_uri (request);
	GInputStream *memstream;
	const char *comma, *start, *end;
	gboolean base64 = FALSE;
	char *uristr;

	uristr = soup_uri_to_string (uri, FALSE);
	start = uristr + 5;
	comma = strchr (start, ',');
	if (comma && comma != start) {
		/* Deal with MIME type / params */
		if (comma > start + BASE64_INDICATOR_LEN && !g_ascii_strncasecmp (comma - BASE64_INDICATOR_LEN, BASE64_INDICATOR, BASE64_INDICATOR_LEN)) {
			end = comma - BASE64_INDICATOR_LEN;
			base64 = TRUE;
		} else
			end = comma;

		if (end != start) {
			char *encoded_content_type = g_strndup (start, end - start);

			if (base64)
				data->priv->content_type = encoded_content_type;
			else {
				data->priv->content_type = soup_uri_decode (encoded_content_type);
				g_free (encoded_content_type);
			}
		}
	}

	memstream = g_memory_input_stream_new ();

	if (comma)
		start = comma + 1;

	if (*start) {
		guchar *buf;

		if (base64) {
			int inlen, state = 0;
			guint save = 0;

			inlen = strlen (start);
			buf = g_malloc0 (inlen * 3 / 4 + 3);
			data->priv->content_length =
				g_base64_decode_step (start, inlen, buf,
						      &state, &save);
			if (state != 0) {
				g_free (buf);
				goto fail;
			}
		} else {
			buf = (guchar *) soup_uri_decode (start);
			data->priv->content_length = strlen ((const char *) buf);
		}

		g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (memstream),
						buf, data->priv->content_length,
						g_free);
	}
	g_free (uristr);

	return memstream;

 fail:
	g_free (uristr);
	g_set_error (error, SOUP_REQUESTER_ERROR, SOUP_REQUESTER_ERROR_BAD_URI,
		     _("Unable to decode URI: %s"), start);
	g_object_unref (memstream);
	return NULL;
}
static gboolean
log_load (GIOSchedulerJob *io_job,
          GCancellable *cancellable,
          gpointer user_data)
{
  /* this runs in a separate i/o thread */
  LoadJob *job = user_data;
  LogviewLog *log = job->log;
  GFile *f = log->priv->file;
  GFileInfo *info;
  GInputStream *is;
  const char *peeked_buffer;
  const char * parse_data[2];
  GSList *days;
  const char *content_type;
  GFileType type;
  GError *err = NULL;
  GTimeVal timeval;
  gboolean is_archive, can_read;

  info = g_file_query_info (f,
                            G_FILE_ATTRIBUTE_ACCESS_CAN_READ ","
                            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
                            G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
                            G_FILE_ATTRIBUTE_STANDARD_TYPE ","
                            G_FILE_ATTRIBUTE_STANDARD_SIZE ","
                            G_FILE_ATTRIBUTE_TIME_MODIFIED ",",
                            0, NULL, &err);
  if (err) {
    if (err->code == G_IO_ERROR_PERMISSION_DENIED) {
      /* TODO: PolicyKit integration */
    }
    goto out;
  }

  can_read = g_file_info_get_attribute_boolean (info,
                                                G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
  if (!can_read) {
    /* TODO: PolicyKit integration */
    err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_PERMISSION_DENIED,
                               _("You don't have enough permissions to read the file."));
    g_object_unref (info);

    goto out;
  }

  type = g_file_info_get_file_type (info);
  content_type = g_file_info_get_content_type (info);

  is_archive = g_content_type_equals (content_type, "application/x-gzip");

  if (type != (G_FILE_TYPE_REGULAR || G_FILE_TYPE_SYMBOLIC_LINK) ||
      (!g_content_type_is_a (content_type, "text/plain") && !is_archive))
  {
    err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_A_LOG,
                               _("The file is not a regular file or is not a text file."));
    g_object_unref (info);

    goto out;
  }

  log->priv->file_size = g_file_info_get_size (info);
  g_file_info_get_modification_time (info, &timeval);
  log->priv->file_time = timeval.tv_sec;
  log->priv->display_name = g_strdup (g_file_info_get_display_name (info));

  g_object_unref (info);

  /* initialize the stream */
  is = G_INPUT_STREAM (g_file_read (f, NULL, &err));

  if (err) {
    if (err->code == G_IO_ERROR_PERMISSION_DENIED) {
      /* TODO: PolicyKit integration */
    }

    goto out;
  }

  if (is_archive) {
#ifdef HAVE_ZLIB
    GZHandle *gz;
    gboolean res;
    guchar * buffer;
    gsize bytes_read;
    GInputStream *real_is;
    time_t mtime; /* seconds */

    /* this also skips the header from |is| */
    res = read_gzip_header (is, &mtime);

    if (!res) {
      g_object_unref (is);

      err = create_zlib_error ();
      goto out;
    }

    log->priv->file_time = mtime;

    gz = gz_handle_new (f, is);
    res = gz_handle_init (gz);

    if (!res) {
      g_object_unref (is);
      gz_handle_free (gz);

      err = create_zlib_error ();
      goto out;
    }

    real_is = g_memory_input_stream_new ();

    do {
      buffer = g_malloc (1024);
      res = gz_handle_read (gz, buffer, 1024, &bytes_read);
      g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (real_is),
                                      buffer, bytes_read, g_free);
    } while (res == TRUE && bytes_read > 0);

    if (!res) {
      gz_handle_free (gz);
      g_object_unref (real_is);
      g_object_unref (is);

      err = create_zlib_error ();
      goto out;
    }
 
    g_object_unref (is);
    is = real_is;

    gz_handle_free (gz);
#else /* HAVE_ZLIB */
    g_object_unref (is);

    err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_SUPPORTED,
                               _("This version of System Log does not support GZipped logs."));
    goto out;
#endif /* HAVE_ZLIB */
  }

  log->priv->stream = g_data_input_stream_new (is);

  /* sniff into the stream for a timestamped line */
  g_buffered_input_stream_fill (G_BUFFERED_INPUT_STREAM (log->priv->stream),
                                (gssize) g_buffered_input_stream_get_buffer_size (G_BUFFERED_INPUT_STREAM (log->priv->stream)),
                                NULL, &err);
  if (err == NULL) {
    peeked_buffer = g_buffered_input_stream_peek_buffer
        (G_BUFFERED_INPUT_STREAM (log->priv->stream), NULL);
    parse_data[0] = peeked_buffer;
    parse_data[1] = NULL;

    if ((days = log_read_dates (parse_data, time (NULL))) != NULL) {
      log->priv->has_days = TRUE;
      g_slist_foreach (days, (GFunc) logview_utils_day_free, NULL);
      g_slist_free (days);
    } else {
      log->priv->has_days = FALSE;
    }
  } else {
    log->priv->has_days = FALSE;
    g_clear_error (&err);
  }

  g_object_unref (is);

out:
  if (err) {
    job->err = err;
  }

  g_io_scheduler_job_send_to_mainloop_async (io_job,
                                             log_load_done,
                                             job, NULL);
  return FALSE;
}