aboutsummaryrefslogblamecommitdiffstats
path: root/camel/providers/imap4/camel-imap4-store-summary.c
blob: 7c08469acf528901aee356d6e9738cfc8d617371 (plain) (tree)

















































                                                                                      


                                                                                   


































                                                                                                            


                                                   































                                                                                  
                                 














                                                                      

















                                                                                  














































                                                                    
                                 











                                            















                                                                                
























                                                                        


                                                
                                                     




                                                                       
                                                            




                                                            
                                                
 
 



























































                                                                                                       










                                                                                      




























                                                                                                     







                                                         
                                                                                                
















                                                                                                        
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  Authors: Jeffrey Stedfast <fejj@novell.com>
 *
 *  Copyright 2004 Novell, Inc. (www.novell.com)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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 Street #330, Boston, MA 02111-1307, USA.
 *
 */


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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <camel/camel-store.h>
#include <camel/camel-file-utils.h>

#include "camel-imap4-utils.h"
#include "camel-imap4-store-summary.h"


#define CAMEL_IMAP4_STORE_SUMMARY_VERSION_0 (0)
#define CAMEL_IMAP4_STORE_SUMMARY_VERSION (0)

static void camel_imap4_store_summary_class_init (CamelIMAP4StoreSummaryClass *klass);
static void camel_imap4_store_summary_init (CamelIMAP4StoreSummary *obj);
static void camel_imap4_store_summary_finalize (CamelObject *obj);

static int summary_header_load (CamelStoreSummary *s, FILE *in);
static int summary_header_save (CamelStoreSummary *s, FILE *out);

static CamelStoreInfo *store_info_load (CamelStoreSummary *s, FILE *in);
static int store_info_save (CamelStoreSummary *s, FILE *out, CamelStoreInfo *info);
static void store_info_free (CamelStoreSummary *s, CamelStoreInfo *info);


static CamelStoreSummaryClass *parent_class = NULL;


CamelType
camel_imap4_store_summary_get_type (void)
{
    static CamelType type = CAMEL_INVALID_TYPE;
    
    if (type == CAMEL_INVALID_TYPE) {
        type = camel_type_register (camel_store_summary_get_type (),
                        "CamelIMAP4StoreSummary",
                        sizeof (CamelIMAP4StoreSummary),
                        sizeof (CamelIMAP4StoreSummaryClass),
                        (CamelObjectClassInitFunc) camel_imap4_store_summary_class_init,
                        NULL,
                        (CamelObjectInitFunc) camel_imap4_store_summary_init,
                        (CamelObjectFinalizeFunc) camel_imap4_store_summary_finalize);
    }
    
    return type;
}


static void
camel_imap4_store_summary_class_init (CamelIMAP4StoreSummaryClass *klass)
{
    CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *) klass;
    
    parent_class = (CamelStoreSummaryClass *) camel_store_summary_get_type ();
    
    ssklass->summary_header_load = summary_header_load;
    ssklass->summary_header_save = summary_header_save;
    
    ssklass->store_info_load = store_info_load;
    ssklass->store_info_save = store_info_save;
    ssklass->store_info_free = store_info_free;
}

static void
camel_imap4_store_summary_init (CamelIMAP4StoreSummary *s)
{
    ((CamelStoreSummary *) s)->store_info_size = sizeof (CamelIMAP4StoreInfo);
    s->version = CAMEL_IMAP4_STORE_SUMMARY_VERSION;
    s->namespaces = NULL;
}

static void
camel_imap4_store_summary_finalize (CamelObject *obj)
{
    CamelIMAP4StoreSummary *s = (CamelIMAP4StoreSummary *) obj;
    
    if (s->namespaces)
        camel_imap4_namespace_list_free (s->namespaces);
}


static CamelIMAP4NamespaceList *
load_namespaces (FILE *in)
{
    CamelIMAP4Namespace *ns, *tail;
    CamelIMAP4NamespaceList *nsl;
    guint32 i, j, n;
    
    nsl = g_malloc (sizeof (CamelIMAP4NamespaceList));
    nsl->personal = NULL;
    nsl->shared = NULL;
    nsl->other = NULL;
    
    for (j = 0; j < 3; j++) {
        switch (j) {
        case 0:
            tail = (CamelIMAP4Namespace *) &nsl->personal;
            break;
        case 1:
            tail = (CamelIMAP4Namespace *) &nsl->shared;
            break;
        case 2:
            tail = (CamelIMAP4Namespace *) &nsl->other;
            break;
        }
        
        if (camel_file_util_decode_fixed_int32 (in, &n) == -1)
            goto exception;
        
        for (i = 0; i < n; i++) {
            guint32 sep;
            char *path;
            
            if (camel_file_util_decode_string (in, &path) == -1)
                goto exception;
            
            if (camel_file_util_decode_uint32 (in, &sep) == -1) {
                g_free (path);
                goto exception;
            }
            
            tail->next = ns = g_malloc (sizeof (CamelIMAP4Namespace));
            ns->sep = sep & 0xff;
            ns->path = path;
            ns->next = NULL;
            tail = ns;
        }
    }
    
    return nsl;
    
 exception:
    
    camel_imap4_namespace_list_free (nsl);
    
    return NULL;
}

static int
summary_header_load (CamelStoreSummary *s, FILE *in)
{
    CamelIMAP4StoreSummary *is = (CamelIMAP4StoreSummary *) s;
    guint32 version, capa;
    
    if (parent_class->summary_header_load (s, in) == -1)
        return -1;
    
    if (camel_file_util_decode_fixed_int32 (in, &version) == -1)
        return -1;
    
    is->version = version;
    if (version < CAMEL_IMAP4_STORE_SUMMARY_VERSION_0) {
        g_warning ("Store summary header version too low");
        errno = EINVAL;
        return -1;
    }
    
    if (camel_file_util_decode_fixed_int32 (in, &capa) == -1)
        return -1;
    
    is->capa = capa;
    
    if (!(is->namespaces = load_namespaces (in)))
        return -1;
    
    return 0;
}

static int
save_namespaces (FILE *out, CamelIMAP4NamespaceList *nsl)
{
    CamelIMAP4Namespace *cur, *ns;
    guint32 i, n;
    
    for (i = 0; i < 3; i++) {
        switch (i) {
        case 0:
            cur = nsl->personal;
            break;
        case 1:
            cur = nsl->shared;
            break;
        case 2:
            cur = nsl->other;
            break;
        }
        
        for (ns = cur, n = 0; ns; n++)
            ns = ns->next;
        
        if (camel_file_util_encode_fixed_int32 (out, n) == -1)
            return -1;
        
        ns = cur;
        while (ns != NULL) {
            if (camel_file_util_encode_string (out, ns->path) == -1)
                return -1;
            
            if (camel_file_util_encode_uint32 (out, ns->sep) == -1)
                return -1;
            
            ns = ns->next;
        }
    }
    
    return 0;
}

static int
summary_header_save (CamelStoreSummary *s, FILE *out)
{
    CamelIMAP4StoreSummary *is = (CamelIMAP4StoreSummary *) s;
    
    if (parent_class->summary_header_save (s, out) == -1)
        return -1;
    
    if (camel_file_util_encode_fixed_int32 (out, is->version) == -1)
        return -1;
    
    if (camel_file_util_encode_fixed_int32 (out, is->capa) == -1)
        return -1;
    
    if (save_namespaces (out, is->namespaces) == -1)
        return -1;
    
    return 0;
}

static CamelStoreInfo *
store_info_load (CamelStoreSummary *s, FILE *in)
{
    return parent_class->store_info_load (s, in);
}

static int
store_info_save (CamelStoreSummary *s, FILE *out, CamelStoreInfo *info)
{
    return parent_class->store_info_save (s, out, info);
}

static void
store_info_free (CamelStoreSummary *s, CamelStoreInfo *info)
{
    parent_class->store_info_free (s, info);
}


/**
 * camel_imap4_store_summary_new:
 *
 * Create a new CamelIMAP4StoreSummary object.
 * 
 * Returns a new CamelIMAP4StoreSummary object.
 **/
CamelIMAP4StoreSummary *
camel_imap4_store_summary_new (void)
{
    return (CamelIMAP4StoreSummary *) camel_object_new (camel_imap4_store_summary_get_type ());
}


void
camel_imap4_store_summary_set_capabilities (CamelIMAP4StoreSummary *s, guint32 capa)
{
    s->capa = capa;
}


void
camel_imap4_store_summary_set_namespaces (CamelIMAP4StoreSummary *s, const CamelIMAP4NamespaceList *ns)
{
    if (s->namespaces)
        camel_imap4_namespace_list_free (s->namespaces);
    s->namespaces = camel_imap4_namespace_list_copy (ns);
}


void
camel_imap4_store_summary_note_info (CamelIMAP4StoreSummary *s, CamelFolderInfo *fi)
{
    CamelStoreSummary *ss = (CamelStoreSummary *) s;
    CamelStoreInfo *si;
    
    if ((si = camel_store_summary_path (ss, fi->full_name))) {
        if (fi->unread != -1) {
            si->unread = fi->unread;
            ss->flags |= CAMEL_STORE_SUMMARY_DIRTY;
        }
        
        if (fi->total != -1) {
            si->total = fi->total;
            ss->flags |= CAMEL_STORE_SUMMARY_DIRTY;
        }
        
        camel_store_summary_info_free (ss, si);
        return;
    }
    
    si = camel_store_summary_info_new (ss);
    si->path = g_strdup (fi->full_name);
    si->uri = g_strdup (fi->uri);
    si->flags = fi->flags;
    si->unread = fi->unread;
    si->total = fi->total;
    
    camel_store_summary_add (ss, si);
    
    /* FIXME: should this be recursive? */
}


void
camel_imap4_store_summary_unnote_info (CamelIMAP4StoreSummary *s, CamelFolderInfo *fi)
{
    CamelStoreSummary *ss = (CamelStoreSummary *) s;
    
    camel_store_summary_remove_path (ss, fi->full_name);
}


static CamelFolderInfo *
store_info_to_folder_info (CamelStoreSummary *s, CamelStoreInfo *si)
{
    CamelFolderInfo *fi;
    
    fi = g_malloc0 (sizeof (CamelFolderInfo));
    fi->full_name = g_strdup (camel_store_info_path (s, si));
    fi->name = g_strdup (camel_store_info_name (s, si));
    fi->uri = g_strdup (camel_store_info_uri (s, si));
    fi->flags = si->flags;
    fi->unread = si->unread;
    fi->total = si->total;
    
    return fi;
}

CamelFolderInfo *
camel_imap4_store_summary_get_folder_info (CamelIMAP4StoreSummary *s, const char *top, guint32 flags)
{
    CamelStoreSummary *ss = (CamelStoreSummary *) s;
    CamelFolderInfo *fi;
    GPtrArray *folders;
    CamelStoreInfo *si;
    size_t toplen, len;
    int i;
    
    toplen = strlen (top);
    folders = g_ptr_array_new ();
    
    for (i = 0; i < ss->folders->len; i++) {
        si = ss->folders->pdata[i];
        if (strncmp (si->path, top, toplen) != 0)
            continue;
        
        if (toplen > 0 && (len = strlen (si->path)) > toplen && si->path[toplen] != '/')
            continue;
        
        if (len == toplen) {
            /* found toplevel folder */
            g_ptr_array_add (folders, store_info_to_folder_info (ss, si));
            continue;
        }
        
        if ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) || !strchr (si->path + toplen + 1, '/'))
            g_ptr_array_add (folders, store_info_to_folder_info (ss, si));
    }
    
    fi = camel_folder_info_build (folders, top, '/', TRUE);
    g_ptr_array_free (folders, TRUE);
    
    return fi;
}