Re: [Evolution-hackers] Reviewing imap_update_summary



With "UID FETCH %d:%d FLAGS" being something not all IMAP servers don't
correctly support, I was a little bit forced to rewrite the
imap_update_summary function into these two ones:

I also simplified it a little bit. And removed one of the two/three
GPtrArrays (that are being synchronized and other funny stuff).

ps. I still need to test this one, and recheck for problems, etc etc ...


static guint32 
imap_get_uids (CamelFolder *folder, CamelImapStore *store, CamelException *ex, GPtrArray *needheaders, int size, int got)
{
	char *resp;
	CamelImapResponseType type;
	guint32 cnt = 0;
	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
	GData *data;
 
	camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
	while ((type = camel_imap_command_response (store, &resp, ex)) ==
			CAMEL_IMAP_RESPONSE_UNTAGGED) 
	{
		cnt++;
		data = parse_fetch_response (imap_folder, resp);
		g_free (resp);
		if (!data)
			continue;
		g_ptr_array_add (needheaders, g_datalist_get_data (&data, "UID"));
		if (size > 0)
			camel_operation_progress (NULL, got * 100 / size);
	}
	camel_operation_end (NULL);
	g_free (resp);
	return cnt;

}

static void
imap_update_summary (CamelFolder *folder, int exists,
		     CamelFolderChangeInfo *changes,
		     CamelException *ex)
{
   CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
   CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
   GPtrArray *fetch_data = NULL, *messages = NULL, *needheaders;
   guint32 flags, uidval;
   int i, seq, first, size, got;
   CamelImapResponseType type;
   const char *header_spec;
   CamelImapMessageInfo *mi, *info;
   CamelStream *stream;
   char *uid, *resp;
   GData *data;
   gboolean more = TRUE;
   unsigned int nextn = 1, cnt=0, tcnt=0;

   if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
   	header_spec = "HEADER.FIELDS (" CAMEL_MESSAGE_INFO_HEADERS MAILING_LIST_HEADERS ")";
   else
   	header_spec = "0";

   /* Used as a way to fetch all Headers instead of the selective headers.
      Support for fetching custom headers could be done in a better way,
      using CamelURL and EPlugins. */

   if( g_getenv ("EVO_IMAP_FETCH_ALL_HEADERS") )
   	header_spec = "HEADER";

   tcnt = 0;
   while (more)
   {
	seq = camel_folder_summary_count (folder->summary);
	first = seq + 1;
	if (seq > 0) {
		mi = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, seq - 1);
		uidval = strtoul(camel_message_info_uid (mi), NULL, 10);
		camel_message_info_free(&mi->info);
	} else
		uidval = 0;

	size = (exists - seq) * (IMAP_PRETEND_SIZEOF_FLAGS + IMAP_PRETEND_SIZEOF_SIZE + IMAP_PRETEND_SIZEOF_HEADERS);
	got = 0;

	if (!camel_imap_command_start (store, folder, ex,
		"UID FETCH %d:%d FLAGS", uidval + 1, uidval + 1 + nextn))
		return;

	more = FALSE; 
	needheaders = g_ptr_array_new ();
	cnt = imap_get_uids (folder, store, ex, needheaders, size, got);
	tcnt += cnt;

	if (tcnt >= (exists - seq))
		more = FALSE;
	else
		more = TRUE;

	if (more && (((exists - seq) > nextn) && (cnt < nextn)))
	{
		if (!camel_imap_command_start (store, folder, ex,
			"UID FETCH %d:* FLAGS", uidval + 1))
			return;
		cnt = imap_get_uids (folder, store, ex, needheaders, size, got);
		tcnt += cnt;
		more = FALSE;
	}

	if (nextn < 1000)
		nextn += (nextn+5);
	else
		nextn = 1000;

	messages = g_ptr_array_new ();
	if (needheaders->len) 
	{
		char *uidset;
		int uid = 0;

		qsort (needheaders->pdata, needheaders->len,
			sizeof (void *), uid_compar);

		camel_operation_start (NULL, _("Fetching summary information for new messages in %s"), folder->name);
		while (uid < needheaders->len) 
		{
			uidset = imap_uid_array_to_set (folder->summary, needheaders, uid, UID_SET_LIMIT, &uid);
			if (!camel_imap_command_start (store, folder, ex,
						       "UID FETCH %s (FLAGS INTERNALDATE BODY.PEEK[%s])",
						       uidset, header_spec)) {
				g_ptr_array_free (needheaders, TRUE);
				camel_operation_end (NULL);
				g_free (uidset);
				goto lose;
			}
			g_free (uidset);

			while ((type = camel_imap_command_response (store, &resp, ex))
				== CAMEL_IMAP_RESPONSE_UNTAGGED) 
			{
				gchar *muid;

				data = parse_fetch_response (imap_folder, resp);
				g_free (resp);
				if (!data)
					continue;

				stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
				if (stream) {
					mi = add_message_from_data (folder, messages, first, data);

					if (mi) 
					{
					  flags = GPOINTER_TO_INT (g_datalist_get_data (&data, "FLAGS"));
					  if (flags) {
						mi->server_flags = flags;
						mi->info.flags |= flags;
						flags_to_label(folder, mi);
					  }

					  muid = g_datalist_get_data (&data, "UID");
					  if (muid) {
						mi->info.uid = g_strdup (muid);
						mi->info.uid_needs_free = TRUE;
					  }
					}

					got += IMAP_PRETEND_SIZEOF_HEADERS;
					if (size > 0)
						camel_operation_progress (NULL, got * 100 / size);
				}
				g_datalist_clear (&data);
			}
			
			if (type == CAMEL_IMAP_RESPONSE_ERROR) {
				g_ptr_array_free (needheaders, TRUE);
				camel_operation_end (NULL);
				goto lose;
			}
		}
		g_ptr_array_free (needheaders, TRUE);
		camel_operation_end (NULL);
	}


	/* And add the entries to the summary, etc. */
	for (i = 0; i < messages->len; i++) 
	{

		mi = messages->pdata[i];
		if (!mi)
			continue;

		uid = (char *)camel_message_info_uid(mi);
		if (uid[0] == 0) {
			g_warning("Server provided no uid: message %d", i + first);
			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
					      _("Incomplete server response: no UID provided for message %d"),
					      i + first);
			break;
		}

		info = (CamelImapMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
		if (info) 
		{
			for (seq = 0; seq < camel_folder_summary_count (folder->summary); seq++) {
				if (folder->summary->messages->pdata[seq] == info)
					break;
			}
			
			g_warning("Message already present? %s", camel_message_info_uid(mi));
			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
					      _("Unexpected server response: Identical UIDs provided for messages %d and %d"),
					      seq + 1, i + first);
			
			camel_message_info_free(&info->info);
			break;
		}

		camel_folder_summary_add (folder->summary, (CamelMessageInfo *)mi);
		camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi));

		if ((mi->info.flags & CAMEL_IMAP_MESSAGE_RECENT))
			camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi));
	}

	camel_folder_summary_dump_mmap (folder->summary);

	for ( ; i < messages->len; i++) {
		if ((mi = messages->pdata[i]))
			camel_message_info_free(&mi->info);
	}
	g_ptr_array_free (messages, TRUE);

	goto endbmore;

 lose:
	if (fetch_data) {
		for (i = 0; i < fetch_data->len; i++) {
			data = fetch_data->pdata[i];
			g_datalist_clear (&data);
		}
		g_ptr_array_free (fetch_data, TRUE);
	}
	if (messages) {
		for (i = 0; i < messages->len; i++) {
			if (messages->pdata[i])
				camel_message_info_free(messages->pdata[i]);
		}
		g_ptr_array_free (messages, TRUE);
	}

	endbmore:
	i++; i--;
   } /* more */
   
}

-- 
Philip Van Hoof, software developer at x-tend 
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
work: vanhoof at x-tend dot be 
http://www.pvanhoof.be - http://www.x-tend.be




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]