aboutsummaryrefslogblamecommitdiffstats
path: root/addressbook/util/eab-book-util.c
blob: d7c0941c694ce0c802d701ed4c68a7cccf1e6509 (plain) (tree)
1
2
3
4
5
6
7
8

                                                                


                                                               
  

                                                                  



                                                                    
                                                                             






                                                        
  

   
                    
                   

      
                   
 
                          
                          
 
                                  
              

                                      

                                                             
                         
                  
 

                                                      
 


                                    
 
                     
                                          
 

                                                             
                                             
 


                    
        
                                               
 
                                
                                            
                            
                                 
                 
 











                                                                          

                                                             
 


                    
                                                       
 
                                        
          
                                                            






                                                                                        
 
                                                                                                 
                                
 

                               
 
                                                                                                   
                                    
 

                                 

                                                                 
 
                                                                                            






                                                                       
                                                                                           

                                  
 
                              
 
                                          

 
       
                                                   

                                         
                        


                                            

                                 
                                                              

                                                                


                                                 
                                                          




                                          
        



                                                                   
 
                        
                             
                   
                                 
 
                                                                      
                                                  
 




                                                            











                                                
                       
                             
 


                                                              

                                                            
                                        
                               

                     
 



                                                                   

 
       

                                                              
 
                       




                                                   
                                  







                                                                   
              





                                   
                                
    


                                               
 

                                                
                








                                     
    

                                           


                                                            






















































                                                                                                                                    
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the program; if not, see <http://www.gnu.org/licenses/>
 *
 *
 * Authors:
 *      Jon Trowbridge <trow@ximian.com>
 *      Chris Toshok <toshok@ximian.com>
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

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

#include <string.h>

#include "e-util/e-util.h"
#include "eab-book-util.h"

/* Copied from camel_strstrcase */
static gchar *
eab_strstrcase (const gchar *haystack,
                const gchar *needle)
{
    /* find the needle in the haystack neglecting case */
    const gchar *ptr;
    guint len;

    g_return_val_if_fail (haystack != NULL, NULL);
    g_return_val_if_fail (needle != NULL, NULL);

    len = strlen (needle);
    if (len > strlen (haystack))
        return NULL;

    if (len == 0)
        return (gchar *) haystack;

    for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
        if (!g_ascii_strncasecmp (ptr, needle, len))
            return (gchar *) ptr;

    return NULL;
}

GSList *
eab_contact_list_from_string (const gchar *str)
{
    GSList *contacts = NULL;
    GString *gstr = g_string_new (NULL);
    gchar *str_stripped;
    gchar *p = (gchar *) str;
    gchar *q;

    if (!p)
        return NULL;

    if (!strncmp (p, "Book: ", 6)) {
        p = strchr (p, '\n');
        if (!p) {
            g_warning (G_STRLOC ": Got book but no newline!");
            return NULL;
        }
        p++;
    }

    while (*p) {
        if (*p != '\r') g_string_append_c (gstr, *p);

        p++;
    }

    p = str_stripped = g_string_free (gstr, FALSE);

    /* Note: The vCard standard says
     *
     * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
     *         items *CRLF "END" [ws] ":" [ws] "VCARD"
     *
     * which means we can have whitespace (e.g. "BEGIN : VCARD"). So we're not being
     * fully compliant here, although I'm not sure it matters. The ideal solution
     * would be to have a vcard parsing function that returned the end of the vcard
     * parsed. Arguably, contact list parsing should all be in libebook's e-vcard.c,
     * where we can do proper parsing and validation without code duplication. */

    for (p = eab_strstrcase (p, "BEGIN:VCARD"); p; p = eab_strstrcase (q, "\nBEGIN:VCARD")) {
        gchar *card_str;

        if (*p == '\n')
            p++;

        for (q = eab_strstrcase (p, "END:VCARD"); q; q = eab_strstrcase (q, "END:VCARD")) {
            gchar *temp;

            q += 9;
            temp = q;
            if (*temp)
                temp += strspn (temp, "\r\n\t ");

            if (*temp == '\0' || !g_ascii_strncasecmp (temp, "BEGIN:VCARD", 11))
                break;  /* Found the outer END:VCARD */
        }

        if (!q)
            break;

        card_str = g_strndup (p, q - p);
        contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (card_str));
        g_free (card_str);
    }

    g_free (str_stripped);

    return g_slist_reverse (contacts);
}

gchar *
eab_contact_list_to_string (const GSList *contacts)
{
    GString *str = g_string_new ("");
    const GSList *l;

    for (l = contacts; l; l = l->next) {
        EContact *contact = l->data;
        gchar *vcard_str;

        e_contact_inline_local_photos (contact, NULL);
        vcard_str = e_vcard_to_string (
            E_VCARD (contact), EVC_FORMAT_VCARD_30);

        g_string_append (str, vcard_str);
        if (l->next)
            g_string_append (str, "\r\n\r\n");
    }

    return g_string_free (str, FALSE);
}

gboolean
eab_source_and_contact_list_from_string (ESourceRegistry *registry,
                                         const gchar *str,
                                         ESource **out_source,
                                         GSList **out_contacts)
{
    ESource *source;
    const gchar *s0, *s1;
    gchar *uid;
    gboolean success = FALSE;

    g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
    g_return_val_if_fail (str != NULL, FALSE);

    if (out_source != NULL)
        *out_source = NULL;  /* in case we fail */

    if (out_contacts != NULL)
        *out_contacts = NULL;  /* in case we fail */

    if (!strncmp (str, "Book: ", 6)) {
        s0 = str + 6;
        s1 = strchr (str, '\r');

        if (!s1)
            s1 = strchr (str, '\n');
    } else {
        s0 = NULL;
        s1 = NULL;
    }

    if (!s0 || !s1)
        return FALSE;

    uid = g_strndup (s0, s1 - s0);
    source = e_source_registry_ref_source (registry, uid);
    if (source != NULL) {
        if (out_source != NULL)
            *out_source = g_object_ref (source);
        g_object_unref (source);
        success = TRUE;
    }
    g_free (uid);

    if (success && out_contacts != NULL)
        *out_contacts = eab_contact_list_from_string (str);

    return success;
}

gchar *
eab_book_and_contact_list_to_string (EBookClient *book_client,
                                     const GSList *contacts)
{
    gchar *s0, *s1;

    s0 = eab_contact_list_to_string (contacts);
    if (!s0)
        s0 = g_strdup ("");

    if (book_client != NULL) {
        EClient *client;
        ESource *source;
        const gchar *uid;

        client = E_CLIENT (book_client);
        source = e_client_get_source (client);
        uid = e_source_get_uid (source);
        s1 = g_strconcat ("Book: ", uid, "\r\n", s0, NULL);
    } else
        s1 = g_strdup (s0);

    g_free (s0);
    return s1;
}

/* bad place for this i know. */
gint
e_utf8_casefold_collate_len (const gchar *str1,
                             const gchar *str2,
                             gint len)
{
    gchar *s1 = g_utf8_casefold (str1, len);
    gchar *s2 = g_utf8_casefold (str2, len);
    gint rv;

    rv = g_utf8_collate (s1, s2);

    g_free (s1);
    g_free (s2);

    return rv;
}

gint
e_utf8_casefold_collate (const gchar *str1,
                         const gchar *str2)
{
    return e_utf8_casefold_collate_len (str1, str2, -1);
}

/* To parse something like...
 * =?UTF-8?Q?=E0=A4=95=E0=A4=95=E0=A4=AC=E0=A5=82=E0=A5=8B=E0=A5=87?=\t\n=?UTF-8?Q?=E0=A4=B0?=\t\n<aa@aa.ccom>
 * and return the decoded representation of name & email parts. */
gboolean
eab_parse_qp_email (const gchar *string,
                    gchar **name,
                    gchar **email)
{
    struct _camel_header_address *address;
    gboolean res = FALSE;

    address = camel_header_address_decode (string, "UTF-8");

    if (!address)
        return FALSE;

    /* report success only when we have filled both name and email address */
    if (address->type == CAMEL_HEADER_ADDRESS_NAME  && address->name && *address->name && address->v.addr && *address->v.addr) {
        *name = g_strdup (address->name);
        *email = g_strdup (address->v.addr);
        res = TRUE;
    }

    camel_header_address_unref (address);

    return res;
}

/* This is only wrapper to parse_qp_mail, it decodes string and if returned TRUE,
 * then makes one string and returns it, otherwise returns NULL.
 * Returned string is usable to place directly into GtkHtml stream.
 * Returned value should be freed with g_free. */
gchar *
eab_parse_qp_email_to_html (const gchar *string)
{
    gchar *name = NULL, *mail = NULL;
    gchar *html_name, *html_mail;
    gchar *value;

    if (!eab_parse_qp_email (string, &name, &mail))
        return NULL;

    html_name = e_text_to_html (name, 0);
    html_mail = e_text_to_html (mail, E_TEXT_TO_HTML_CONVERT_ADDRESSES);

    value = g_strdup_printf ("%s &lt;%s&gt;", html_name, html_mail);

    g_free (html_name);
    g_free (html_mail);
    g_free (name);
    g_free (mail);

    return value;
}