void
camel_nntp_grouplist_save (CamelNNTPGroupList *group_list, CamelException *ex)
{
	FILE *fp;
	gchar *root_dir = camel_nntp_store_get_toplevel_dir(CAMEL_NNTP_STORE(group_list->store));
	gchar *grouplist_file = g_strdup_printf ("%s/grouplist", root_dir);

	g_free (root_dir);
	fp = g_fopen (grouplist_file, "w");
	g_free (grouplist_file);

	if (fp == NULL) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
				      _("Unable to save grouplist file for %s: %s"),
				      CAMEL_SERVICE(group_list->store)->url->host,
				      strerror(errno));
		return;
	}

	fprintf (fp, "%lu\n", (long)group_list->time);

	g_list_foreach (group_list->group_list, (GFunc)save_entry, fp);

	fclose (fp);
}
static gchar *
nntp_get_filename (CamelFolder *folder,
                   const gchar *uid,
                   GError **error)
{
	CamelStore *parent_store;
	CamelDataCache *nntp_cache;
	CamelNNTPStore *nntp_store;
	gchar *article, *msgid;
	gsize article_len;
	gchar *filename;

	parent_store = camel_folder_get_parent_store (folder);
	nntp_store = CAMEL_NNTP_STORE (parent_store);

	article_len = strlen (uid) + 1;
	article = alloca (article_len);
	g_strlcpy (article, uid, article_len);
	msgid = strchr (article, ',');
	if (msgid == NULL) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Internal error: UID in invalid format: %s"), uid);
		return NULL;
	}
	*msgid++ = 0;

	nntp_cache = camel_nntp_store_ref_cache (nntp_store);
	filename = camel_data_cache_get_filename (nntp_cache, "cache", msgid);
	g_clear_object (&nntp_cache);

	return filename;
}
static gboolean
nntp_folder_refresh_info_sync (CamelFolder *folder,
                               GCancellable *cancellable,
                               GError **error)
{
	CamelStore *parent_store;
	CamelNNTPStore *nntp_store;
	CamelFolderChangeInfo *changes = NULL;
	CamelNNTPFolder *nntp_folder;
	gchar *line;
	gboolean success;

	parent_store = camel_folder_get_parent_store (folder);

	nntp_folder = CAMEL_NNTP_FOLDER (folder);
	nntp_store = CAMEL_NNTP_STORE (parent_store);

	/* When invoked with no fmt, camel_nntp_command() just selects the folder
	 * and should return zero. */
	success = !camel_nntp_command (
		nntp_store, cancellable, error, nntp_folder, &line, NULL);

	if (camel_folder_change_info_changed (nntp_folder->changes)) {
		changes = nntp_folder->changes;
		nntp_folder->changes = camel_folder_change_info_new ();
	}

	if (changes) {
		camel_folder_changed (folder, changes);
		camel_folder_change_info_free (changes);
	}

	return success;
}
gboolean
camel_nntp_folder_selected (CamelNNTPFolder *nntp_folder,
                            gchar *line,
                            GCancellable *cancellable,
                            GError **error)
{
	CamelFolder *folder;
	CamelStore *parent_store;
	gboolean res;

	folder = CAMEL_FOLDER (nntp_folder);
	parent_store = camel_folder_get_parent_store (folder);

	res = camel_nntp_summary_check (
		CAMEL_NNTP_SUMMARY (folder->summary),
		CAMEL_NNTP_STORE (parent_store),
		line, nntp_folder->changes,
		cancellable, error);

	if (camel_folder_change_info_changed (nntp_folder->changes)) {
		CamelFolderChangeInfo *changes;

		changes = nntp_folder->changes;
		nntp_folder->changes = camel_folder_change_info_new ();

		camel_folder_changed (CAMEL_FOLDER (nntp_folder), changes);
		camel_folder_change_info_free (changes);
	}

	return res;
}
static CamelNNTPGroupList*
camel_nntp_get_grouplist_from_file (CamelNNTPStore *store, CamelException *ex)
{
	gchar *root_dir = camel_nntp_store_get_toplevel_dir(CAMEL_NNTP_STORE(store));
	gchar *grouplist_file = g_strdup_printf ("%s/grouplist", root_dir);
	CamelNNTPGroupList *list;
	FILE *fp;
	char buf[300];
	unsigned long time;

	g_free (root_dir);
	fp = g_fopen (grouplist_file, "r");
	g_free (grouplist_file);

	if (fp == NULL) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
				      _("Unable to load grouplist file for %s: %s"),
				      CAMEL_SERVICE(store)->url->host,
				      strerror(errno));
		return NULL;
	}

	/* read the time */
	if (!fgets (buf, sizeof (buf), fp)) {
		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
				      _("Unable to load grouplist file for %s: %s"),
				      CAMEL_SERVICE(store)->url->host,
				      strerror(errno));
		fclose (fp);
		return NULL;
	}


	list = g_new0 (CamelNNTPGroupList, 1);
	list->store = store;
	sscanf (buf, "%lu", &time);
	list->time = time;

	while (fgets (buf, sizeof (buf), fp)) {
		CamelNNTPGroupListEntry *entry = g_new (CamelNNTPGroupListEntry, 1);
		char **split_line = g_strsplit (buf, " ", 4);

		entry->group_name = g_strdup (split_line[0]);
		entry->high = atoi (split_line[1]);
		entry->low = atoi (split_line[2]);

		g_strfreev (split_line);

		list->group_list = g_list_prepend (list->group_list, entry);
	}

	fclose (fp);

	list->group_list = g_list_reverse(list->group_list);
	return list;
}
static void
nntp_folder_dispose (GObject *object)
{
	CamelFolder *folder;
	CamelStore *store;

	folder = CAMEL_FOLDER (object);
	camel_folder_summary_save_to_db (folder->summary, NULL);

	store = camel_folder_get_parent_store (folder);
	if (store != NULL) {
		CamelNNTPStoreSummary *nntp_store_summary;

		nntp_store_summary = camel_nntp_store_ref_summary (
			CAMEL_NNTP_STORE (store));
		camel_store_summary_disconnect_folder_summary (
			CAMEL_STORE_SUMMARY (nntp_store_summary),
			folder->summary);
		g_clear_object (&nntp_store_summary);
	}

	/* Chain up to parent's dispose() method. */
	G_OBJECT_CLASS (camel_nntp_folder_parent_class)->dispose (object);
}
static CamelMimeMessage *
nntp_folder_get_message_sync (CamelFolder *folder,
                              const gchar *uid,
                              GCancellable *cancellable,
                              GError **error)
{
	CamelStore *parent_store;
	CamelMimeMessage *message = NULL;
	CamelDataCache *nntp_cache;
	CamelNNTPStore *nntp_store;
	CamelFolderChangeInfo *changes;
	CamelNNTPFolder *nntp_folder;
	CamelStream *stream = NULL;
	GIOStream *base_stream;
	gchar *article, *msgid;
	gsize article_len;

	parent_store = camel_folder_get_parent_store (folder);

	nntp_folder = CAMEL_NNTP_FOLDER (folder);
	nntp_store = CAMEL_NNTP_STORE (parent_store);

	article_len = strlen (uid) + 1;
	article = alloca (article_len);
	g_strlcpy (article, uid, article_len);
	msgid = strchr (article, ',');
	if (msgid == NULL) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Internal error: UID in invalid format: %s"), uid);
		return NULL;
	}
	*msgid++ = 0;

	/* Lookup in cache, NEWS is global messageid's so use a global cache path */
	nntp_cache = camel_nntp_store_ref_cache (nntp_store);
	base_stream = camel_data_cache_get (nntp_cache, "cache", msgid, NULL);
	g_clear_object (&nntp_cache);

	if (base_stream != NULL) {
		stream = camel_stream_new (base_stream);
		g_object_unref (base_stream);
	} else {
		CamelServiceConnectionStatus connection_status;

		connection_status = camel_service_get_connection_status (
			CAMEL_SERVICE (parent_store));

		if (connection_status != CAMEL_SERVICE_CONNECTED) {
			g_set_error (
				error, CAMEL_SERVICE_ERROR,
				CAMEL_SERVICE_ERROR_UNAVAILABLE,
				_("This message is not currently available"));
			goto fail;
		}

		stream = nntp_folder_download_message (nntp_folder, article, msgid, cancellable, error);
		if (stream == NULL)
			goto fail;
	}

	message = camel_mime_message_new ();
	if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error)) {
		g_prefix_error (error, _("Cannot get message %s: "), uid);
		g_object_unref (message);
		message = NULL;
	}

	g_object_unref (stream);
fail:
	if (camel_folder_change_info_changed (nntp_folder->changes)) {
		changes = nntp_folder->changes;
		nntp_folder->changes = camel_folder_change_info_new ();
	} else {
		changes = NULL;
	}

	if (changes) {
		camel_folder_changed (folder, changes);
		camel_folder_change_info_free (changes);
	}

	return message;
}
static gboolean
nntp_folder_append_message_sync (CamelFolder *folder,
                                 CamelMimeMessage *message,
                                 CamelMessageInfo *info,
                                 gchar **appended_uid,
                                 GCancellable *cancellable,
                                 GError **error)
{
	CamelStore *parent_store;
	CamelNNTPStore *nntp_store;
	CamelNNTPStream *nntp_stream = NULL;
	CamelStream *filtered_stream;
	CamelMimeFilter *crlffilter;
	gint ret;
	guint u;
	struct _camel_header_raw *header, *savedhdrs, *n, *tail;
	const gchar *full_name;
	gchar *group, *line;
	gboolean success = TRUE;
	GError *local_error = NULL;

	full_name = camel_folder_get_full_name (folder);
	parent_store = camel_folder_get_parent_store (folder);

	nntp_store = CAMEL_NNTP_STORE (parent_store);

	/* send 'POST' command */
	ret = camel_nntp_command (
		nntp_store, cancellable, error, NULL, &line, "post");
	if (ret != 340) {
		if (ret == 440) {
			g_set_error (
				error, CAMEL_FOLDER_ERROR,
				CAMEL_FOLDER_ERROR_INSUFFICIENT_PERMISSION,
				_("Posting failed: %s"), line);
			success = FALSE;
		} else if (ret != -1) {
			g_set_error (
				error, CAMEL_ERROR,
				CAMEL_ERROR_GENERIC,
				_("Posting failed: %s"), line);
			success = FALSE;
		}
		goto exit;
	}

	/* the 'Newsgroups: ' header */
	group = g_strdup_printf ("Newsgroups: %s\r\n", full_name);

	/* remove mail 'To', 'CC', and 'BCC' headers */
	savedhdrs = NULL;
	tail = (struct _camel_header_raw *) &savedhdrs;

	header = (struct _camel_header_raw *) &CAMEL_MIME_PART (message)->headers;
	n = header->next;
	while (n != NULL) {
		if (!g_ascii_strcasecmp (n->name, "To") || !g_ascii_strcasecmp (n->name, "Cc") || !g_ascii_strcasecmp (n->name, "Bcc")) {
			header->next = n->next;
			tail->next = n;
			n->next = NULL;
			tail = n;
		} else {
			header = n;
		}

		n = header->next;
	}

	nntp_stream = camel_nntp_store_ref_stream (nntp_store);

	/* setup stream filtering */
	filtered_stream = camel_stream_filter_new (CAMEL_STREAM (nntp_stream));
	crlffilter = camel_mime_filter_crlf_new (
		CAMEL_MIME_FILTER_CRLF_ENCODE,
		CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
	camel_stream_filter_add (
		CAMEL_STREAM_FILTER (filtered_stream), crlffilter);
	g_object_unref (crlffilter);

	/* write the message */
	if (local_error == NULL)
		camel_stream_write (
			CAMEL_STREAM (nntp_stream),
			group, strlen (group),
			cancellable, &local_error);
	if (local_error == NULL)
		camel_data_wrapper_write_to_stream_sync (
			CAMEL_DATA_WRAPPER (message),
			filtered_stream, cancellable, &local_error);
	if (local_error == NULL)
		camel_stream_flush (
			filtered_stream, cancellable, &local_error);
	if (local_error == NULL)
		camel_stream_write (
			CAMEL_STREAM (nntp_stream),
			"\r\n.\r\n", 5,
			cancellable, &local_error);
	if (local_error == NULL)
		camel_nntp_stream_line (
			nntp_stream, (guchar **) &line,
			&u, cancellable, &local_error);
	if (local_error == NULL && atoi (line) != 240)
		local_error = g_error_new_literal (
			CAMEL_ERROR, CAMEL_ERROR_GENERIC, line);

	if (local_error != NULL) {
		g_propagate_prefixed_error (
			error, local_error, _("Posting failed: "));
		success = FALSE;
	}

	g_object_unref (filtered_stream);
	g_free (group);
	header->next = savedhdrs;

exit:
	g_clear_object (&nntp_stream);

	return success;
}
static CamelStream *
nntp_folder_download_message (CamelNNTPFolder *nntp_folder,
                              const gchar *id,
                              const gchar *msgid,
                              GCancellable *cancellable,
                              GError **error)
{
	CamelFolder *folder;
	CamelStore *parent_store;
	CamelDataCache *nntp_cache;
	CamelNNTPStore *nntp_store;
	CamelNNTPStream *nntp_stream = NULL;
	CamelStream *stream = NULL;
	gint ret;
	gchar *line;

	folder = CAMEL_FOLDER (nntp_folder);
	parent_store = camel_folder_get_parent_store (folder);

	nntp_store = CAMEL_NNTP_STORE (parent_store);
	nntp_cache = camel_nntp_store_ref_cache (nntp_store);

	ret = camel_nntp_command (
		nntp_store, cancellable, error,
		nntp_folder, &line, "article %s", id);

	if (ret == 220) {
		GIOStream *base_stream;

		nntp_stream = camel_nntp_store_ref_stream (nntp_store);

		base_stream = camel_data_cache_add (
			nntp_cache, "cache", msgid, NULL);
		if (base_stream != NULL) {
			gboolean success;

			stream = camel_stream_new (base_stream);
			g_object_unref (base_stream);

			success = (camel_stream_write_to_stream (
				CAMEL_STREAM (nntp_stream),
				stream, cancellable, error) != -1);
			if (!success)
				goto fail;

			success = g_seekable_seek (
				G_SEEKABLE (stream), 0,
				G_SEEK_SET, cancellable, error);
			if (!success)
				goto fail;
		} else {
			stream = g_object_ref (nntp_stream);
		}

	} else if (ret == 423 || ret == 430) {
		g_set_error (
			error, CAMEL_FOLDER_ERROR,
			CAMEL_FOLDER_ERROR_INVALID_UID,
			_("Cannot get message %s: %s"), msgid, line);

	} else if (ret != -1) {
		g_set_error (
			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
			_("Cannot get message %s: %s"), msgid, line);
	}

	goto exit;

fail:
	camel_data_cache_remove (nntp_cache, "cache", msgid, NULL);
	g_prefix_error (error, _("Cannot get message %s: "), msgid);

	g_clear_object (&stream);

exit:
	g_clear_object (&nntp_cache);
	g_clear_object (&nntp_stream);

	return stream;
}