/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Authors: Michael Zucchi <notzed@ximian.com>
 *
 * Copyright (C) 2001 Ximian Inc (www.ximian.com/)
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of version 2 of the GNU General Public 
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

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

#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#include "camel-spool-store.h"
#include "camel-spool-folder.h"
#include "camel-exception.h"
#include "camel-url.h"
#include "camel-private.h"

#define d(x)

/* Returns the class for a CamelSpoolStore */
#define CSPOOLS_CLASS(so) CAMEL_SPOOL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))

static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex);
static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex);
static char *get_name(CamelService *service, gboolean brief);
static CamelFolder *get_inbox (CamelStore *store, CamelException *ex);
static void rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex);
static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex);
static void free_folder_info (CamelStore *store, CamelFolderInfo *fi);

static void delete_folder(CamelStore *store, const char *folder_name, CamelException *ex);
static void rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex);

static CamelStoreClass *parent_class = NULL;

static void
camel_spool_store_class_init (CamelSpoolStoreClass *camel_spool_store_class)
{
	CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_spool_store_class);
	CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS (camel_spool_store_class);
	
	parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_store_get_type ()));

	/* virtual method overload */
	camel_service_class->construct = construct;
	camel_service_class->get_name = get_name;
	camel_store_class->get_folder = get_folder;
	camel_store_class->get_inbox = get_inbox;
	camel_store_class->get_folder_info = get_folder_info;
	camel_store_class->free_folder_info = free_folder_info;

	camel_store_class->delete_folder = delete_folder;
	camel_store_class->rename_folder = rename_folder;
}

CamelType
camel_spool_store_get_type (void)
{
	static CamelType camel_spool_store_type = CAMEL_INVALID_TYPE;
	
	if (camel_spool_store_type == CAMEL_INVALID_TYPE)	{
		camel_spool_store_type = camel_type_register (CAMEL_STORE_TYPE, "CamelSpoolStore",
							     sizeof (CamelSpoolStore),
							     sizeof (CamelSpoolStoreClass),
							     (CamelObjectClassInitFunc) camel_spool_store_class_init,
							     NULL,
							     NULL,
							     NULL);
	}
	
	return camel_spool_store_type;
}

static void
construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
{
	struct stat st;

	d(printf("constructing store of type %s '%s:%s'\n",
		 camel_type_to_name(((CamelObject *)service)->s.type), url->protocol, url->path));

	CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
	if (camel_exception_is_set (ex))
		return;

	if (service->url->path[0] != '/') {
		camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
				     _("Store root %s is not an absolute path"), service->url->path);
		return;
	}

	if (stat(service->url->path, &st) == -1 || !S_ISREG(st.st_mode)) {
		camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
				     _("Spool `%s' does not exist or is not a regular file"),
				     service->url->path);
		return;
	}
}

const char *
camel_spool_store_get_toplevel_dir (CamelSpoolStore *store)
{
	CamelURL *url = CAMEL_SERVICE (store)->url;

	g_assert (url != NULL);
	return url->path;
}

static CamelFolder *
get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex)
{
	char *path = ((CamelService *)store)->url->path;
	CamelFolder *folder;

	d(printf("opening folder %s on path %s\n", folder_name, path));

	/* we only support an 'INBOX' */
	if (strcmp(folder_name, "INBOX") != 0) {
		camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
				     _("Folder `%s/%s' does not exist."),
				     path, folder_name);
		return NULL;
	}

	folder = camel_spool_folder_new(store, folder_name, flags, ex);

	return folder;
}

static CamelFolder *
get_inbox(CamelStore *store, CamelException *ex)
{
	return get_folder (store, "INBOX", CAMEL_STORE_FOLDER_CREATE, ex);
}

static char *
get_name (CamelService *service, gboolean brief)
{
	if (brief)
		return g_strdup (service->url->path);
	else
		return g_strdup_printf (_("Spool mail file %s"), service->url->path);
}

static CamelFolderInfo *
get_folder_info (CamelStore *store, const char *top,
		 guint32 flags, CamelException *ex)
{
	CamelFolderInfo *fi = NULL;
	CamelService *service = (CamelService *)store;
	CamelFolder *folder;

	if (top == NULL || strcmp(top, "INBOX") == 0) {
		/* FIXME: if the folder is opened we could look it up? */
		fi = g_malloc0(sizeof(*fi));
		fi->full_name = "INBOX";
		fi->name = "INBOX";
		fi->url = g_strdup_printf("spool:%s#%s", service->url->path, fi->name);

		CAMEL_STORE_LOCK(store, cache_lock);
		folder = g_hash_table_lookup(store->folders, fi->full_name);
		if (folder)
			fi->unread_message_count = camel_folder_get_message_count(folder);
		else
			fi->unread_message_count = -1;
		CAMEL_STORE_UNLOCK(store, cache_lock);

		camel_folder_info_build_path(fi, '/');
	}

	return fi;
}

static void free_folder_info (CamelStore *store, CamelFolderInfo *fi)
{
	if (fi) {
		g_free(fi->url);
		g_free(fi);
	}
}


/* default implementation, rename all */
static void
rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex)
{
	camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
			     _("Spool folders cannot be renamed"));
}

/* default implementation, only delete metadata */
static void
delete_folder(CamelStore *store, const char *folder_name, CamelException *ex)
{
	camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
			     _("Spool folders cannot be deleted"));
}
/octave-forge-geometry/Makefile?h=gnome-3.24&amp;showmsg=1'>Makefile</a></div><div class='content'><table class='list nowrap'><tr class='nohover'><th></th><th class='left'>Commit message (<a href='/~lantw44/cgit/cgit.cgi/freebsd-ports-gnome/log/math/octave-forge-geometry/Makefile?h=gnome-3.24'>Collapse</a>)</th><th class='left'>Author</th><th class='left'>Age</th><th class='left'>Files</th><th class='left'>Lines</th></tr>
<tr class='logheader'><td class='commitgraph'>* </td><td class='logsubject'><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports-gnome/commit/math/octave-forge-geometry/Makefile?h=gnome-3.24&amp;id=a8659f2c3a739594f865ddb2381c38d14c4d611e'>Bump PORTREVISION for ports depending on the canonical version of GCC</a></td><td>gerald</td><td><span title='2017-09-11 04:55:38 +0800'>2017-09-11</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr class='nohover-highlight'><td class='commitgraph'><span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> </td>
<td colspan='5' class='logmsg'>
(via Mk/bsd.default-versions.mk and lang/gcc) which has moved from
GCC 5.4 to GCC 6.4 under most circumstances.

This includes ports
 - with USE_GCC=yes or USE_GCC=any,
 - with USES=fortran,
 - using Mk/bsd.octave.mk which in turn features USES=fortran, and
 - with USES=compiler specifying openmp, nestedfct, c++11-lib, c++11-lang,
   c++14-lang, c++0x, c11, or gcc-c++11-lib.

PR:		219275


</td></tr>
<tr class='logheader'><td class='commitgraph'>* </td><td class='logsubject'><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports-gnome/commit/math/octave-forge-geometry/Makefile?h=gnome-3.24&amp;id=d38a5ce3e159d069182b0e3f57f2244954f7741c'>- Update to 3.0.0.</a></td><td>stephen</td><td><span title='2017-06-20 09:18:24 +0800'>2017-06-20</span></td><td>1</td><td><span class='deletions'>-6</span>/<span class='insertions'>+2</span></td></tr>
<tr class='nohover-highlight'><td class='commitgraph'><span class='column1'>|</span> </td>
<td colspan='5' class='logmsg'>
</td></tr>
<tr class='logheader'><td class='commitgraph'>* </td><td class='logsubject'><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports-gnome/commit/math/octave-forge-geometry/Makefile?h=gnome-3.24&amp;id=8047a240e1cbbe6481930d3ec780c9c92fccd00c'>Bump PORTREVISIONs for ports depending on the canonical version of GCC and</a></td><td>gerald</td><td><span title='2017-04-01 23:23:30 +0800'>2017-04-01</span></td><td>1</td><td><span class='deletions'>-1</span>/<span class='insertions'>+1</span></td></tr>
<tr class='nohover-highlight'><td class='commitgraph'><span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> </td>
<td colspan='5' class='logmsg'>
lang/gcc which have moved from GCC 4.9.4 to GCC 5.4 (at least under some
circumstances such as versions of FreeBSD or platforms).

This includes ports
 - with USE_GCC=yes or USE_GCC=any,
 - with USES=fortran,
 - using using Mk/bsd.octave.mk which in turn has USES=fortran, and
 - with USES=compiler specifying openmp, nestedfct, c++11-lib, c++14-lang,
   c++11-lang, c++0x, c11, or gcc-c++11-lib.

PR:		216707


</td></tr>
<tr class='logheader'><td class='commitgraph'>* </td><td class='logsubject'><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports-gnome/commit/math/octave-forge-geometry/Makefile?h=gnome-3.24&amp;id=62ddc3e0d540c5e473189ec319669a989aaffa08'>Bump PORTREVISIONS for ports depending on the canonical version of GCC and</a></td><td>gerald</td><td><span title='2016-12-07 21:24:56 +0800'>2016-12-07</span></td><td>1</td><td><span class='deletions'>-0</span>/<span class='insertions'>+1</span></td></tr>
<tr class='nohover-highlight'><td class='commitgraph'><span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> 
<span class='column1'>|</span> </td>
<td colspan='5' class='logmsg'>
lang/gcc which have moved from GCC 4.8.5 to GCC 4.9.4 (at least under some
circumstances such as versions of FreeBSD or platforms), part II.

The first part covered  ports with USE_GCC=yes, USE_GCC=any, or one of
gcc-c++11-lib, openmp, nestedfct, c++11-lib as well as c++14-lang,
c++11-lang, c++0x, c11 requested via USES=compiler.

This adds ports with USES=fortran and ports using Mk/bsd.octave.mk
which in turn has USES=fortran.

PR:		214965
Reported by:	thierry


</td></tr>
<tr class='logheader'><td class='commitgraph'>* </td><td class='logsubject'><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports-gnome/commit/math/octave-forge-geometry/Makefile?h=gnome-3.24&amp;id=e67b12d60fff62296ab06f8ef06bba6b123592e2'>- Update to 2.1.1.</a></td><td>stephen</td><td><span title='2016-04-02 05:31:21 +0800'>2016-04-02</span></td><td>1</td><td><span class='deletions'>-2</span>/<span class='insertions'>+2</span></td></tr>
<tr class='nohover-highlight'><td class='commitgraph'><span class='column1'>|</span> </td>
<td colspan='5' class='logmsg'>
</td></tr>
<tr class='logheader'><td class='commitgraph'>* </td><td class='logsubject'><a href='/~lantw44/cgit/cgit.cgi/freebsd-ports-gnome/commit/math/octave-forge-geometry/Makefile?h=gnome-3.24&amp;id=c60c1d09235abbfd733e901b1872b86adc82027c'>Remove ${PORTSDIR}/ from dependencies, categories m, n, o, and p.</a></td><td>mat</td><td><span title='2016-04-01 22:16:16 +0800'>2016-04-01</span>