Re: [Evolution-hackers] EPlugin, export mail folder, now does recursive!



On Thu, 2004-11-18 at 17:07 +0100, smurfd wrote:
So, after a while of hacking. I have Finally got things working. Also
doing it, recursive!

One thing that keeps bothering me : 
It opens up a "save messages" dialog for each subfolder at the same
time. Gives you alot of windows, and makes it hard to know wich folder
each window represents.
Hrm, right.  Hmm.  Do you want it to save all the folders into one folder, or alternatively create all the trees for it, or do you really want to just pop up a new save requester each time?

Each has different solutions.

The last one for example you probably want to do serialisation a bit differently, that is, copy the folder-info you get from the first call (see below for more info on what first call is), and then iterate through it in the folder_got callback rather than in the first callback.
One idea i had to give that an nicer look would be to cut and paste the
'static' functions that "em_utils_save_messages" needs. NOT a nice
sollution, but that way, i could atleast get the title of the  window to
say what folder one is saving.

Anyone got a nicer sollution, i'd be glad for some input!
Well it depends on what you're after I guess.
Best regards

/Nicklas
---- the plugin code ------
/*
 * Author : Nicklas Boman <smurfd smurfnet homelinux net>
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <glib.h>
#include <glib/gi18n.h>

#include <camel/camel-session.h>
#include <camel/camel-store.h>
#include <camel/camel-url.h>

#include "mail/em-popup.h"
#include "mail/mail-mt.h"
#include "mail/mail-ops.h"
#include "mail/em-utils.h"

void org_gnome_export_mail_folder (EPlugin *ep, EMPopupTargetFolder
*target);
void do_export_mail_folder (char *uri);

extern CamelSession *session;

static void
export_mail_folder (char *uri, CamelFolder *folder, gpointer data) {
        GPtrArray *pids;

        if (folder) {
                camel_object_ref (folder);
you don't need to ref/unref here.

It is reffed by the caller, and em_utils_save_messages will ref it if it needs to too.
                pids = g_ptr_array_new();
                pids = camel_folder_get_uids((CamelFolder *)folder);
Stylistically, 'pids' means something totally different in unix, i'd stick to 'uids'.  You're also doing it wrong, you don't allocate your own array, get_uids will return one, above you're just leaking the first one you allocate (losing it in memory).
                em_utils_save_messages(0, folder, pids);
        
		camel_object_unref (folder);
	}
}


static void 
export_mail_folder_recursive (char *uri, CamelFolder *folder, gpointer
data) {
	guint32  flags = CAMEL_STORE_FOLDER_INFO_FAST |
CAMEL_STORE_FOLDER_INFO_RECURSIVE;
	CamelFolderInfo *fi;
	CamelException ex;
	CamelStore *fromstore;
	CamelURL *url;
	GList *pending = NULL;
	
	camel_exception_init (&ex);
	
	if (camel_store_supports_subscriptions (fromstore)) 
		flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
fromstore isn't set yet, you can't access it like this.

	
	if (!(fromstore = camel_session_get_store (session, uri, &ex))) {
		printf("Error getting 'fromstore'\n");
		return;
	}
you don't need to do this, folder->parent_store is the folder's store, if it has one.
	
	url = "" (uri, NULL);
	
	if(!(fi = camel_store_get_folder_info (fromstore, url->fragment,flags,
&ex))){
url->fragment is only set for local stores, imap uses url->path.  Yeah its a hack.  In most code we just do url->fragment?url->fragment: url->path, although strictly you need to check the provider flags (store->provider->url_flags or something).

		printf("Error getting store folder info\n");
		return;
	}

	pending = g_list_append (pending, fi);
	
	while (pending) {
		CamelFolderInfo *info = pending->data;
		
		pending = g_list_remove_link (pending, pending);

		while (info) {
			CamelFolder *fromfolder = NULL;

			if (info->child)
				pending = g_list_append (pending, info->child);
			if ((info->flags & CAMEL_FOLDER_NOSELECT) == 0) {
				if (!(fromfolder = camel_store_get_folder (fromstore,
info->full_name, 0, &ex))) {
					printf("Error getting store folder\n");
					return;
				
				}

				printf("Name = %s\n", info->full_name); // DEBUG PURPOSES

				export_mail_folder(url,fromfolder, data);
			}
			info = info->next;
		}
	}
You forgot to free the folderinfo.  And the CamelURL, and you need to camel_exception_clear the exception when you're done.  C doesn't do garbage collection (at least evolution doesn't) so you have to manage that yourself.
}

void 
do_export_mail_folder(char *uri) 
{
	CamelURL *camelurl;
	int fid;
	
	camelurl = camel_url_new(uri, NULL);
	
	fid =
mail_get_folder(uri,0,export_mail_folder_recursive,camelurl,mail_thread_queued_slow);
}

Ok some of the seqeuences above are a bit wrong:
- you really want to use "mail_get_store" first, to get the store, you can use the same uri, since it ignores the folder path part automagically (actually the store will always be loaded, so you can probably do that without mail_get_store, but for consistency you should stick to that, some camel ops in the mian thread can cause deadlocks).
- you need to use mail_get_folderinfo too, the 'done' callback will be invoked back in the main thread, you want this potentially long-running stuff to run in the background.
- then you can iterate the results of mail_get_folderinfo in its done callback, and call the mail_get_folder as appropriate.

All of the 'mail_*' functions run in another thread then return the processing to the main thread, and then call your callbacks.  So if they need to do more camel ops they should do more threading stuff.  Since this might need to alternate to gui and camel ops its probably easist to stick to above, if you could just do it all in a non-gui thread you'd just setup a new 'mail op' thing, and just use direct camel codes in the other thread.


Maybe some of what i'm saying doesn't make immediate sense, but there are reasons for doing it this way.

--
Michael Zucchi <notzed ximian com>
"Free Software, putting the Free back in Free Market."
Novell's Evolution and Free Software Developer


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