aboutsummaryrefslogblamecommitdiffstats
path: root/modules/tnef-attachment/e-mail-parser-tnef-attachment.c
blob: 3de54e627fb8ddf3e10bd44ab69521d2ca332cf7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
  










                                                                    
                                                                             
   

                    
                   

      
                   


                         

                  






                                                


                      
                  
                  
                   
                   
                  

                                   
      
 
                          

                            































                                                                                                 
                                                                       


                                                                   


                          
                        



                                                           
 
                      








                                                                                                     
 
              











                                                                         





                                                            
 
                             





                                  
                 
                        
                      
 
                                                      
                           
                            
 
                                                                       
 
                                                                                 

                          
                        
         
                                                                  


                                     
                            
         

                                                                                     
                                     
                              
                            
         
                             

                                        
                               
                             
                                                
                                               
         
                                    
 
                         

                             
                               


                                 
                        
         
 
                                          
 
                                    
                                                                                      
                                                
 
                                                                                     
 
                                     


                                          

                                  
 


                                                                   
                             
 
                                                                  
 

                                                                                 

                                                               
                                        
 

                                                                                    
 
                                                                         
                                         
 
                                                     
                         
                                                                                       
 
                                                               
 
                              
 
                                                    
                                      
         
 
                       
 
                           
                                                  
 
                     
                                                  


                                                             

                                             

                                                 


                                                        

                                      
         
 

                                         


                                                                   
 

                                  
 

                        

























                                                                                    

 







                                                                       
 



                                                                                 
                                                                                
 

                                         
 
                                              

                                                                              
                                                    



                                                                                 
                                                                                    





                                                                      

 



                                 


                             

                        


                              
                      

               
 

                                                                        
                                      
                                                              

                                     
                                                           

                                     
                                                                  


                                         
     
 
                                                              
                                                                         
                                                              
                                                                                       



                                             

     
                                                                      
                                                         
                              
                                                                      
                                                                                    



                                                                                         

                                   
                                                                   
                                                                      

                                         
 

                                                                      
                            

                                         







                                              



                                     
                                   

                       
                
                                      

                                   
 

                                                                   




                                                                              

                                                    



                                              
                                                         

                               

                                                                



                                                                         
                                                              













                                                                        
                                                              










                                                                   
                                  

                                                                










                                                                                        
                                                                


                                                                 


                                                                         
                                     
 

                                                                  

                                      




                                                    
                            




                                               
                     
                                  
                 


                         
                          
                       

 



                               
                     
                                     



                                                                  
                 
 
                                                                                                                      

                                                                                                                          
                                                             


                                                                 
                  
                                                         
             
                                                


                                                             
         
            
                                            


                                                         
     



                                                             
 

                                                   
            

                                        
                                   
                                                
         




                                                                                             

                            



                                                                                                                          
                                                      
                                                                                                                                         
                                                       
                     
                                         


                 
 



                                                                                               
                                  
                                                     
                                               
                                
         
 
                              



















                                                                                                                                  
                                                         


                                           
                                 


                                            
                                


                                          
                                


                                           
                                


                                         
                                


                                             
                                
                                                                                                                     
                                                               
                                        
                                    

             

                          



















                                                                                                                                               
                                                         


                                           
                                 


                                            
                                


                                          
                                


                                           
                                


                                         
                                


                                             
                                
                                                                                                                     
                                                               
                                        
                                    

             

                           



















                                                                                                                                                
                                                          


                                           
                                 


                                            
                                


                                          
                                


                                           
                                


                                         
                                


                                             
                                

         


















                                                                                                                 
 
                             




                                                                                                                 
                                                       





                                                                                                                 
                                                       





                                                                                                                 
                                                       
         
 

                                                                                   
 
                      
                                                                                                                      
                                    
                                                             
                                                                                          
         

                         
                                                                                                                                 
                                                       
                                                             
                                                                                          
         
                                      
                      
     
                       

 
                                           


                          
                                              




                             
                               

                             
                               

                             
                                





                             
                               

                             
                               





                             
                               

                             
                               





                             
                               




                            
                           




                            
                           




                            
                            



                            
                            



                
               

 
                                    
                               



                   
                                  

                   
                                  

                   
                                  

                   
                                  

                   
                                  

                   
                                  

                   
                                  

     

                                              

     
                       

 
                                                                            
 


                             
               

     
                                  

                                   
                                
 

                                                                   
                                                                      
                                                                   
                                                                  

                                                                       


                                                                            

                                              
                                                    
                                                                       


                                                                            

             
                                          


                                                                      
                                                                   
                                       

                                                                    
                                          
                                  
                                       
                                                                          

                                                                       


                                                                           

                                              
                                                               



                                                                       


                                                                           

             
                                          

                                          

                                                                       
                                                               
                                              
                                                   



                                                                   
                                                                        

                                   
     
                         

 
                                                            
                     
                             
                              
               
               
                     

                
                                                                
                               
 

                                                   
            
                                            
                                         

                                          





                                       

                                                     
                    
                                                   

                
                                               
         

                                         
 
              

                                                                         

                                                                           

                                                                              
                        
                                                                  
                                                                        
                                                                      
                                                                             


                                
                               
                                   
                                                              
                                                                      
             
                                



                        
                                                                  
                                                                         
                                                 
                                                               
         
                                                                  
                                                                    

                                     
                                             
                                 


                                   
                                                             



                                        

                                                                            
                                                          

                                     
                                             

                                         
                                                     


                                           
                                           
                                  


                                                                      




                                                  

                                                                                

                                                           
                                                 

                                             
                                                         


                                               
                                               
                                      


                                                                          




                                                  

                                                                            
                                     
                                             

                                         
                                                     


                                           
                                           
                                  


                                                                      







                                                  
                                                                  
                                                                      
                                    
                                       
                                          
                                 


                         
                                                                  
                                                                         
                                    
                               
                                                                                     
                                               

                                      
             

         


                        
                                                                  
                                                                            
                                                                      
                                                                                



                                
                                                            


                        
                                                                  
                                                                            
                                                                      
                                                                                
                                


                               
                                       
                                                                   
                                                         




                                                                     
                                                                  
                                                                            
                                                                      
                                                                                
                                


                               
                                     
                                                                   
                                                         




                                                                     
                                                                  
                                                                            
                                       
                                                                   
                                                         




                                                                     
                                                                  
                                                                            
                                                 
                                     
                                  
                                           
                    
                                          



                        
                                                                  

                                                                           


                        

                                          
                      
     
                       

 
                                                        

                             

                     
                              
                              

                
                     
 
                                                                                                  




                               
                              
                                  

                                  







                                                             
                               
 

                                                   
            


                                            

                        
                                        
                                      
                                                       
         

                                                               
                                         
                                                             
         
 

                                                                                                                              

                                                                   
                                         

                                     
                                                 


                                       
                                       
                              
                                                                                             



                                   
                                     
                                      
                                                 
                                

         
                                  
                                          
                                              
                                

         

                                                               
                                         
                                       
                                                                   
                                                         



                                                                     

                                                               
                                         
                                   
                                                                   
                                                         


                                                                     

                                                                      
                                         
                                             
                                                                   
                                                         



                                                                     

                                                               
                                         
                                                 
                                     
                                  
                                           
                    
                                          

             

                                          
                      
     
                       

 
                                                                                                      
                       
                                                                                                           
                           
                                                        
                    
                                               
             
         


     
                                                                                                      
                       
                                                                                                           
                           
                                                        
                    
                                               
             
         


     
                                                    
               
 
                                                    
                                      
                                  

                                             
                                                  
         


     
                                                    
               
 
                                                    
                                      
                                  
                                             

                                            
                                  
                                            
                                  
                                             
                                 
                
                                                  
         


     
                                                



                  



                 
                                                                         











                            
                              


                                            
                                
                                      
                                       

                                      
                                      
                                      
                                      
                                       
                                     
                    
                                            
             

         
                         
 
/*
 * 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/>
 */

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

#include <string.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gprintf.h>
#include <stdio.h>

#include "e-mail-parser-tnef-attachment.h"

#include <em-format/e-mail-extension-registry.h>
#include <em-format/e-mail-parser-extension.h>
#include <em-format/e-mail-part.h>
#include <em-format/e-mail-part-utils.h>

#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef HAVE_YTNEF_H
#include <ytnef.h>
#elif defined HAVE_LIBYTNEF_YTNEF_H
#include <libytnef/ytnef.h>
#endif

#include <mail/em-utils.h>
#include <e-util/e-mktemp.h>

#include <libebackend/libebackend.h>

#define d(x)

typedef struct _EMailParserTnefAttachment {
    EExtension parent;

    GSettings *settings;
    gint mode;
    gboolean show_suppressed;
} EMailParserTnefAttachment;

typedef struct _EMailParserTnefAttachmentClass {
    EExtensionClass parent_class;
} EMailParserTnefAttachmentClass;

GType e_mail_parser_tnef_attachment_get_type (void);
static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);

G_DEFINE_DYNAMIC_TYPE_EXTENDED (
    EMailParserTnefAttachment,
    e_mail_parser_tnef_attachment,
    E_TYPE_EXTENSION,
    0,
    G_IMPLEMENT_INTERFACE_DYNAMIC (
        E_TYPE_MAIL_EXTENSION,
        e_mail_parser_mail_extension_interface_init)
    G_IMPLEMENT_INTERFACE_DYNAMIC (
        E_TYPE_MAIL_PARSER_EXTENSION,
        e_mail_parser_parser_extension_interface_init));

static const gchar * parser_mime_types[] = { "application/vnd.ms-tnef",
                        "application/ms-tnefl",
                        NULL };

gint verbose = 0;
gint saveRTF = 0;
gint saveintermediate = 0;
gboolean loaded = FALSE;
void processTnef (TNEFStruct *tnef, const gchar *tmpdir);
void saveVCalendar (TNEFStruct *tnef, const gchar *tmpdir);
void saveVCard (TNEFStruct *tnef, const gchar *tmpdir);
void saveVTask (TNEFStruct *tnef, const gchar *tmpdir);

/* Other Prototypes */
void fprintProperty (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]);
void fprintUserProp (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]);
void quotedfprint (FILE *fptr, variableLength *vl);
void cstylefprint (FILE *fptr, variableLength *vl);
void printRtf (FILE *fptr, variableLength *vl);
void printRrule (FILE *fptr, gchar *recur_data, gint size, TNEFStruct *tnef);
guchar getRruleCount (guchar a, guchar b);
guchar getRruleMonthNum (guchar a, guchar b);
gchar * getRruleDayname (guchar a);

static gchar *
sanitize_filename (const gchar *filename)
{
    gchar * sanitized_name;
    sanitized_name = g_path_get_basename (filename);
    if (sanitized_name == NULL || !g_strcmp0 (sanitized_name, ".")) {
        g_free (sanitized_name);
        return NULL;
    } else {
        return g_strdelimit (sanitized_name, " ", '_');
    }
}

static GSList *
empe_tnef_attachment_parse (EMailParserExtension *extension,
                            EMailParser *parser,
                            CamelMimePart *part,
                            GString *part_id,
                            GCancellable *cancellable)
{
    gchar *tmpdir, *name;
    CamelStream *out;
    struct dirent *d;
    DIR *dir;
    CamelMultipart *mp;
    CamelMimePart *mainpart;
    CamelDataWrapper *content;
    gint len;
    TNEFStruct tnef;
    GSList *parts;

    tmpdir = e_mkdtemp ("tnef-attachment-XXXXXX");
    if (tmpdir == NULL)
        return NULL;

    name = g_build_filename (tmpdir, ".evo-attachment.tnef", NULL);

    out = camel_stream_fs_new_with_name (name, O_RDWR | O_CREAT, 0666, NULL);
    if (out == NULL) {
        g_free (name);
        return NULL;
    }
    content = camel_medium_get_content ((CamelMedium *) part);
    if (content == NULL) {
        g_free (name);
        g_object_unref (out);
        return NULL;
    }
    if (camel_data_wrapper_decode_to_stream_sync (content, out, NULL, NULL) == -1
        || camel_stream_close (out, NULL, NULL) == -1) {
        g_object_unref (out);
        g_free (name);
        return NULL;
    }
    g_object_unref (out);

    /* Extracting the winmail.dat */
    TNEFInitialize (&tnef);
    tnef.Debug = verbose;
    if (TNEFParseFile (name, &tnef) == -1) {
        printf ("ERROR processing file\n");
    }
    processTnef (&tnef, tmpdir);

    TNEFFree (&tnef);
    /* Extraction done */

    dir = opendir (tmpdir);
    if (dir == NULL) {
        g_object_unref (out);
        g_free (name);
        return NULL;
    }

    mainpart = camel_mime_part_new ();

    mp = camel_multipart_new ();
    camel_data_wrapper_set_mime_type ((CamelDataWrapper *) mp, "multipart/mixed");
    camel_multipart_set_boundary (mp, NULL);

    camel_medium_set_content ((CamelMedium *) mainpart, (CamelDataWrapper *) mp);

    while ((d = readdir (dir))) {
        CamelMimePart *part;
        CamelDataWrapper *content;
        CamelStream *stream;
        gchar *path;
        const gchar *type;

        if (!strcmp (d->d_name, ".")
            || !strcmp (d->d_name, "..")
            || !strcmp (d->d_name, ".evo-attachment.tnef"))
            continue;

        path = g_build_filename (tmpdir, d->d_name, NULL);

        stream = camel_stream_fs_new_with_name (path, O_RDONLY, 0, NULL);
        content = camel_data_wrapper_new ();
        camel_data_wrapper_construct_from_stream_sync (
            content, stream, NULL, NULL);
        g_object_unref (stream);

        part = camel_mime_part_new ();
        camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BINARY);

        camel_medium_set_content ((CamelMedium *) part, content);
        g_object_unref (content);

        type = e_mail_part_snoop_type (part);
        if (type)
            camel_data_wrapper_set_mime_type ((CamelDataWrapper *) part, type);

        camel_mime_part_set_filename (part, d->d_name);

        g_free (path);

        camel_multipart_add_part (mp, part);
        g_object_unref (part);
    }

    closedir (dir);

    len = part_id->len;
    g_string_append_printf (part_id, ".tnef");

    parts = NULL;
    if (camel_multipart_get_number (mp) > 0) {

        CamelMimePart *part = camel_mime_part_new ();

        camel_medium_set_content (
            (CamelMedium *) part,
            CAMEL_DATA_WRAPPER (mp));

        parts = e_mail_parser_parse_part_as (
            parser, part, part_id,
            "multipart/mixed", cancellable);

        g_object_unref (part);
    }

    g_string_truncate (part_id, len);

    if (parts)
        parts = e_mail_parser_wrap_as_attachment (
            parser, part, parts, part_id, cancellable);

    g_object_unref (mp);
    g_object_unref (mainpart);

    g_free (name);
    g_free (tmpdir);

    return parts;
}

static const gchar **
empe_mime_types (EMailExtension *extension)
{
    return parser_mime_types;
}

void
e_mail_parser_tnef_attachment_type_register (GTypeModule *type_module)
{
    e_mail_parser_tnef_attachment_register_type (type_module);
}

static void
e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
{
    iface->mime_types = empe_mime_types;
}

static void
e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
{
    iface->parse = empe_tnef_attachment_parse;
}

static void
e_mail_parser_tnef_attachment_constructed (GObject *object)
{
    EExtensible *extensible;
    EMailExtensionRegistry *reg;

    extensible = e_extension_get_extensible (E_EXTENSION (object));
    reg = E_MAIL_EXTENSION_REGISTRY (extensible);

    e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object));
}

static void
e_mail_parser_tnef_attachment_class_init (EMailParserTnefAttachmentClass *class)
{
    GObjectClass *object_class;
    EExtensionClass *extension_class;

    object_class = G_OBJECT_CLASS (class);
    object_class->constructed = e_mail_parser_tnef_attachment_constructed;

    extension_class = E_EXTENSION_CLASS (class);
    extension_class->extensible_type = E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY;
}

void
e_mail_parser_tnef_attachment_class_finalize (EMailParserTnefAttachmentClass *class)
{
}

static void
e_mail_parser_tnef_attachment_init (EMailParserTnefAttachment *parser)
{
}

void
processTnef (TNEFStruct *tnef,
             const gchar *tmpdir)
{
    variableLength *filename;
    variableLength *filedata;
    Attachment *p;
    gint RealAttachment;
    gint object;
    gchar *ifilename = NULL;
    gchar *absfilename, *file;
    gint count;
    gint foundCal = 0;

    FILE *fptr;

    /* First see if this requires special processing. */
    /* ie: it's a Contact Card, Task, or Meeting request (vCal/vCard) */
    if (tnef->messageClass[0] != 0)  {
    if (strcmp (tnef->messageClass, "IPM.Contact") == 0) {
        saveVCard (tnef, tmpdir);
    }
    if (strcmp (tnef->messageClass, "IPM.Task") == 0) {
        saveVTask (tnef, tmpdir);
    }
    if (strcmp (tnef->messageClass, "IPM.Appointment") == 0) {
        saveVCalendar (tnef, tmpdir);
        foundCal = 1;
    }
    }

    if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
            PROP_TAG (PT_STRING8,0x24))) != MAPI_UNDEFINED) {
    if (strcmp (filename->data, "IPM.Appointment") == 0) {
             /* If it's "indicated" twice, we don't want to save 2 calendar entries. */
        if (foundCal == 0) {
        saveVCalendar (tnef, tmpdir);
        }
    }
    }

    if (strcmp (tnef->messageClass, "IPM.Microsoft Mail.Note") == 0) {
    if ((saveRTF == 1) && (tnef->subject.size > 0)) {
            /*  Description */
        if ((filename = MAPIFindProperty (&(tnef->MapiProperties),
                       PROP_TAG (PT_BINARY, PR_RTF_COMPRESSED)))
            != MAPI_UNDEFINED) {
        variableLength buf;
        if ((buf.data = (gchar *) DecompressRTF (filename, &buf.size)) != NULL) {
            file = sanitize_filename (tnef->subject.data);
            if (!file)
                return;
            absfilename = g_strconcat (file, ".rtf", NULL);
            ifilename = g_build_filename (tmpdir, file, NULL);
            g_free (absfilename);
            g_free (file);

            if ((fptr = fopen (ifilename, "wb")) == NULL) {
            printf ("ERROR: Error writing file to disk!");
            } else {
            fwrite (
                buf.data,
                sizeof (BYTE),
                buf.size,
                fptr);
            fclose (fptr);
            }
            free (buf.data);
        }
        }
    }
    }

    /* Now process each attachment */
    p = tnef->starting_attach.next;
    count = 0;
    while (p != NULL) {
    count++;
        /* Make sure it has a size. */
    if (p->FileData.size > 0) {
        object = 1;

            /* See if the contents are stored as "attached data" */
        /* Inside the MAPI blocks. */
        if ((filedata = MAPIFindProperty (&(p->MAPI),
                    PROP_TAG (PT_OBJECT, PR_ATTACH_DATA_OBJ)))
            == MAPI_UNDEFINED) {
        if ((filedata = MAPIFindProperty (&(p->MAPI),
                    PROP_TAG (PT_BINARY, PR_ATTACH_DATA_OBJ)))
           == MAPI_UNDEFINED) {
                    /* Nope, standard TNEF stuff. */
            filedata = &(p->FileData);
            object = 0;
        }
        }
            /* See if this is an embedded TNEF stream. */
        RealAttachment = 1;
        if (object == 1) {
                /*  This is an "embedded object", so skip the */
                /* 16-byte identifier first. */
        TNEFStruct emb_tnef;
        DWORD signature;
        memcpy (&signature, filedata->data + 16, sizeof (DWORD));
        if (TNEFCheckForSignature (signature) == 0) {
                    /* Has a TNEF signature, so process it. */
            TNEFInitialize (&emb_tnef);
            emb_tnef.Debug = tnef->Debug;
            if (TNEFParseMemory ((guchar *) filedata->data + 16,
                 filedata->size - 16, &emb_tnef) != -1) {
            processTnef (&emb_tnef, tmpdir);
            RealAttachment = 0;
            }
            TNEFFree (&emb_tnef);
        }
        } else {
        TNEFStruct emb_tnef;
        DWORD signature;
        memcpy (&signature, filedata->data, sizeof (DWORD));
        if (TNEFCheckForSignature (signature) == 0) {
                    /* Has a TNEF signature, so process it. */
            TNEFInitialize (&emb_tnef);
            emb_tnef.Debug = tnef->Debug;
            if (TNEFParseMemory ((guchar *) filedata->data,
                filedata->size, &emb_tnef) != -1) {
            processTnef (&emb_tnef, tmpdir);
            RealAttachment = 0;
            }
            TNEFFree (&emb_tnef);
        }
        }
        if ((RealAttachment == 1) || (saveintermediate == 1)) {
        gchar tmpname[20];
                /* Ok, it's not an embedded stream, so now we */
        /* process it. */
        if ((filename = MAPIFindProperty (&(p->MAPI),
                    PROP_TAG (PT_STRING8, PR_ATTACH_LONG_FILENAME)))
            == MAPI_UNDEFINED) {
            if ((filename = MAPIFindProperty (&(p->MAPI),
                    PROP_TAG (PT_STRING8, PR_DISPLAY_NAME)))
                == MAPI_UNDEFINED) {
            filename = &(p->Title);
            }
        }
        if (filename->size == 1) {
            filename->size = 20;
            g_sprintf (tmpname, "file_%03i.dat", count);
            filename->data = tmpname;
        }
        absfilename = sanitize_filename (filename->data);
        if (!absfilename)
            return;
        ifilename = g_build_filename (tmpdir, absfilename, NULL);
        g_free (absfilename);

        if ((fptr = fopen (ifilename, "wb")) == NULL) {
            printf ("ERROR: Error writing file to disk!");
        } else {
            if (object == 1) {
            fwrite (
                filedata->data + 16,
                sizeof (BYTE),
                filedata->size - 16,
                fptr);
            } else {
            fwrite (
                filedata->data,
                sizeof (BYTE),
                filedata->size,
                fptr);
            }
            fclose (fptr);
        }
        }
    } /* if size>0 */
    p = p->next;
    } /* while p!= null */
    g_free (ifilename);
}

void
saveVCard (TNEFStruct *tnef,
           const gchar *tmpdir)
{
    gchar *ifilename;
    gchar *absfilename, *file = NULL;
    FILE *fptr;
    variableLength *vl;
    variableLength *pobox, *street, *city, *state, *zip, *country;
    dtr thedate;
    gint boolean;

    if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_DISPLAY_NAME))) == MAPI_UNDEFINED) {
    if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_COMPANY_NAME))) == MAPI_UNDEFINED) {
        if (tnef->subject.size > 0) {
           file = sanitize_filename (tnef->subject.data);
        if (!file)
            return;
        absfilename = g_strconcat (file, ".vcard", NULL);
        } else
        absfilename = g_strdup ("unknown.vcard");
     } else {
        file = sanitize_filename (vl->data);
        if (!file)
        return;
        absfilename = g_strconcat (file, ".vcard", NULL);
    }
    } else {
    file = sanitize_filename (vl->data);
    if (!file)
        return;
    absfilename = g_strconcat (file, ".vcard", NULL);
    }

    ifilename = g_build_filename (tmpdir, absfilename, NULL);
    g_free (file);
    g_free (absfilename);

    if ((fptr = fopen (ifilename, "wb")) == NULL) {
        printf ("Error writing file to disk!");
    } else {
    fprintf (fptr, "BEGIN:VCARD\n");
    fprintf (fptr, "VERSION:2.1\n");
    if (vl != MAPI_UNDEFINED) {
        fprintf (fptr, "FN:%s\n", vl->data);
    }
    fprintProperty (tnef, fptr, PT_STRING8, PR_NICKNAME, "NICKNAME:%s\n");
    fprintUserProp (tnef, fptr, PT_STRING8, 0x8554, "MAILER:Microsoft Outlook %s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_SPOUSE_NAME, "X-EVOLUTION-SPOUSE:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_MANAGER_NAME, "X-EVOLUTION-MANAGER:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_ASSISTANT, "X-EVOLUTION-ASSISTANT:%s\n");

        /* Organizational */
    if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_COMPANY_NAME))) != MAPI_UNDEFINED) {
        if (vl->size > 0) {
        if ((vl->size == 1) && (vl->data[0] == 0)) {
        } else {
            fprintf (fptr,"ORG:%s", vl->data);
            if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_DEPARTMENT_NAME))) != MAPI_UNDEFINED) {
            fprintf (fptr,";%s", vl->data);
            }
            fprintf (fptr, "\n");
        }
        }
    }

    fprintProperty (tnef, fptr, PT_STRING8, PR_OFFICE_LOCATION, "X-EVOLUTION-OFFICE:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_TITLE, "TITLE:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_PROFESSION, "ROLE:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_BODY, "NOTE:%s\n");
    if (tnef->body.size > 0) {
        fprintf (fptr, "NOTE;QUOTED-PRINTABLE:");
        quotedfprint (fptr, &(tnef->body));
        fprintf (fptr,"\n");
    }

        /* Business Address */
    boolean = 0;
    if ((pobox = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_POST_OFFICE_BOX))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((street = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_STREET_ADDRESS))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((city = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_LOCALITY))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((state = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((zip = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_POSTAL_CODE))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((country = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_COUNTRY))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if (boolean == 1) {
        fprintf (fptr, "ADR;QUOTED-PRINTABLE;WORK:");
        if (pobox != MAPI_UNDEFINED) {
        quotedfprint (fptr, pobox);
        }
        fprintf (fptr, ";;");
        if (street != MAPI_UNDEFINED) {
        quotedfprint (fptr, street);
        }
        fprintf (fptr, ";");
        if (city != MAPI_UNDEFINED) {
        quotedfprint (fptr, city);
        }
        fprintf (fptr, ";");
        if (state != MAPI_UNDEFINED) {
        quotedfprint (fptr, state);
        }
        fprintf (fptr, ";");
        if (zip != MAPI_UNDEFINED) {
        quotedfprint (fptr, zip);
        }
        fprintf (fptr, ";");
        if (country != MAPI_UNDEFINED) {
        quotedfprint (fptr, country);
        }
        fprintf (fptr,"\n");
        if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x801b))) != MAPI_UNDEFINED) {
        fprintf (fptr, "LABEL;QUOTED-PRINTABLE;WORK:");
        quotedfprint (fptr, vl);
        fprintf (fptr,"\n");
        }
    }

        /* Home Address */
    boolean = 0;
    if ((pobox = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_POST_OFFICE_BOX))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((street = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_STREET))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((city = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_CITY))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((state = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((zip = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_POSTAL_CODE))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((country = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_HOME_ADDRESS_COUNTRY))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if (boolean == 1) {
        fprintf (fptr, "ADR;QUOTED-PRINTABLE;HOME:");
        if (pobox != MAPI_UNDEFINED) {
        quotedfprint (fptr, pobox);
        }
        fprintf (fptr, ";;");
        if (street != MAPI_UNDEFINED) {
        quotedfprint (fptr, street);
        }
        fprintf (fptr, ";");
        if (city != MAPI_UNDEFINED) {
        quotedfprint (fptr, city);
        }
        fprintf (fptr, ";");
        if (state != MAPI_UNDEFINED) {
        quotedfprint (fptr, state);
        }
        fprintf (fptr, ";");
        if (zip != MAPI_UNDEFINED) {
        quotedfprint (fptr, zip);
        }
        fprintf (fptr, ";");
        if (country != MAPI_UNDEFINED) {
        quotedfprint (fptr, country);
        }
        fprintf (fptr,"\n");
        if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x801a))) != MAPI_UNDEFINED) {
        fprintf (fptr, "LABEL;QUOTED-PRINTABLE;WORK:");
        quotedfprint (fptr, vl);
        fprintf (fptr,"\n");
        }
    }

        /* Other Address */
    boolean = 0;
    if ((pobox = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_POST_OFFICE_BOX))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((street = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_STREET))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((city = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_CITY))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((state = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_STATE_OR_PROVINCE))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((zip = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_POSTAL_CODE))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if ((country = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_OTHER_ADDRESS_COUNTRY))) != MAPI_UNDEFINED) {
        boolean = 1;
    }
    if (boolean == 1) {
        fprintf (fptr, "ADR;QUOTED-PRINTABLE;OTHER:");
        if (pobox != MAPI_UNDEFINED) {
        quotedfprint (fptr, pobox);
        }
        fprintf (fptr, ";;");
        if (street != MAPI_UNDEFINED) {
        quotedfprint (fptr, street);
        }
        fprintf (fptr, ";");
        if (city != MAPI_UNDEFINED) {
        quotedfprint (fptr, city);
        }
        fprintf (fptr, ";");
        if (state != MAPI_UNDEFINED) {
        quotedfprint (fptr, state);
        }
        fprintf (fptr, ";");
        if (zip != MAPI_UNDEFINED) {
        quotedfprint (fptr, zip);
        }
        fprintf (fptr, ";");
        if (country != MAPI_UNDEFINED) {
        quotedfprint (fptr, country);
        }
        fprintf (fptr,"\n");
    }

    fprintProperty (tnef, fptr, PT_STRING8, PR_CALLBACK_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-CALLBACK:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_PRIMARY_TELEPHONE_NUMBER, "TEL;PREF:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_MOBILE_TELEPHONE_NUMBER, "TEL;CELL:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_RADIO_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-RADIO:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_CAR_TELEPHONE_NUMBER, "TEL;CAR:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_OTHER_TELEPHONE_NUMBER, "TEL;VOICE:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_PAGER_TELEPHONE_NUMBER, "TEL;PAGER:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_TELEX_NUMBER, "TEL;X-EVOLUTION-TELEX:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_ISDN_NUMBER, "TEL;ISDN:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_HOME2_TELEPHONE_NUMBER, "TEL;HOME:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_TTYTDD_PHONE_NUMBER, "TEL;X-EVOLUTION-TTYTDD:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_HOME_TELEPHONE_NUMBER, "TEL;HOME;VOICE:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_ASSISTANT_TELEPHONE_NUMBER, "TEL;X-EVOLUTION-ASSISTANT:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_COMPANY_MAIN_PHONE_NUMBER, "TEL;WORK:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_BUSINESS_TELEPHONE_NUMBER, "TEL;WORK:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_BUSINESS2_TELEPHONE_NUMBER, "TEL;WORK;VOICE:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_PRIMARY_FAX_NUMBER, "TEL;PREF;FAX:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_BUSINESS_FAX_NUMBER, "TEL;WORK;FAX:%s\n");
    fprintProperty (tnef, fptr, PT_STRING8, PR_HOME_FAX_NUMBER, "TEL;HOME;FAX:%s\n");

        /* Email addresses */
    if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8083))) == MAPI_UNDEFINED) {
        vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8084));
    }
    if (vl != MAPI_UNDEFINED) {
        if (vl->size > 0)
        fprintf (fptr, "EMAIL:%s\n", vl->data);
    }
    if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8093))) == MAPI_UNDEFINED) {
        vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x8094));
    }
    if (vl != MAPI_UNDEFINED) {
        if (vl->size > 0)
        fprintf (fptr, "EMAIL:%s\n", vl->data);
    }
    if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x80a3))) == MAPI_UNDEFINED) {
        vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x80a4));
    }
    if (vl != MAPI_UNDEFINED) {
        if (vl->size > 0)
        fprintf (fptr, "EMAIL:%s\n", vl->data);
    }

    fprintProperty (tnef, fptr, PT_STRING8, PR_BUSINESS_HOME_PAGE, "URL:%s\n");
    fprintUserProp (tnef, fptr, PT_STRING8, 0x80d8, "FBURL:%s\n");

        /* Birthday */
    if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, PR_BIRTHDAY))) != MAPI_UNDEFINED) {
        fprintf (fptr, "BDAY:");
        MAPISysTimetoDTR ((guchar *) vl->data, &thedate);
        fprintf (fptr, "%i-%02i-%02i\n", thedate.wYear, thedate.wMonth, thedate.wDay);
    }

        /* Anniversary */
    if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_SYSTIME, PR_WEDDING_ANNIVERSARY))) != MAPI_UNDEFINED) {
        fprintf (fptr, "X-EVOLUTION-ANNIVERSARY:");
        MAPISysTimetoDTR ((guchar *) vl->data, &thedate);
        fprintf (fptr, "%i-%02i-%02i\n", thedate.wYear, thedate.wMonth, thedate.wDay);
    }
    fprintf (fptr, "END:VCARD\n");
    fclose (fptr);
    }
    g_free (ifilename);
}

guchar getRruleCount (guchar a, guchar b) {
    return ((a << 8) | b);
}

guchar getRruleMonthNum (guchar a, guchar b) {
    switch (a) {
        case 0x00:
            switch (b) {
                case 0x00:
                    /* Jan */
                    return (1);
                case 0xA3:
                    /* May */
                    return (5);
                case 0xAE:
                    /* Nov */
                    return (11);
            }
            break;
        case 0x60:
            switch (b) {
                case 0xAE:
                    /* Feb */
                    return (2);
                case 0x51:
                    /* Jun */
                    return (6);
            }
            break;
        case 0xE0:
            switch (b) {
                case 0x4B:
                    /* Mar */
                    return (3);
                case 0x56:
                    /* Sep */
                    return (9);
            }
            break;
        case 0x40:
            switch (b) {
                case 0xFA:
                    /* Apr */
                    return (4);
            }
            break;
        case 0x20:
            if (b == 0xFA) {
                /* Jul */
                return (7);
            }
            break;
        case 0x80:
            if (b == 0xA8) {
                /* Aug */
                return (8);
            }
            break;
        case 0xA0:
            if (b == 0xFF) {
                /* Oct */
                return (10);
            }
            break;
        case 0xC0:
            if (b == 0x56) {
                return (12);
            }
    }

    /*  Error */
    return (0);
}

gchar * getRruleDayname (guchar a) {
    static gchar daystring[25];

    *daystring = 0;

    if (a & 0x01) {
        strcat (daystring, "SU,");
    }
    if (a & 0x02) {
        strcat (daystring, "MO,");
    }
    if (a & 0x04) {
        strcat (daystring, "TU,");
    }
    if (a & 0x08) {
        strcat (daystring, "WE,");
    }
    if (a & 0x10) {
        strcat (daystring, "TH,");
    }
    if (a & 0x20) {
        strcat (daystring, "FR,");
    }
    if (a & 0x40) {
        strcat (daystring, "SA,");
    }

    if (strlen (daystring)) {
        daystring[strlen (daystring) - 1] = 0;
    }

    return (daystring);
}

void printRrule (FILE *fptr, gchar *recur_data, gint size, TNEFStruct *tnef)
{
    variableLength *filename;

    if (size < 0x1F) {
    return;
    }

    fprintf (fptr, "RRULE:FREQ=");

    if (recur_data[0x04] == 0x0A) {
    fprintf (fptr, "DAILY");

    if (recur_data[0x16] == 0x23 || recur_data[0x16] == 0x22 ||
        recur_data[0x16] == 0x21) {
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
            PROP_TAG (PT_I2, 0x0011))) != MAPI_UNDEFINED) {
        fprintf (fptr, ";INTERVAL=%d", *(filename->data));
        }
        if (recur_data[0x16] == 0x22 || recur_data[0x16] == 0x21) {
        fprintf (
            fptr, ";COUNT=%d",
            getRruleCount (recur_data[0x1B], recur_data[0x1A]));
        }
    } else if (recur_data[0x16] == 0x3E) {
        fprintf (fptr, ";BYDAY=MO,TU,WE,TH,FR");
        if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) {
        fprintf (
            fptr, ";COUNT=%d",
            getRruleCount (recur_data[0x1F], recur_data[0x1E]));
        }
    }
    } else if (recur_data[0x04] == 0x0B) {
    fprintf (
        fptr, "WEEKLY;INTERVAL=%d;BYDAY=%s",
        recur_data[0x0E], getRruleDayname (recur_data[0x16]));
    if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) {
        fprintf (fptr, ";COUNT=%d",
        getRruleCount (recur_data[0x1F], recur_data[0x1E]));
    }
    } else if (recur_data[0x04] == 0x0C) {
    fprintf (fptr, "MONTHLY");
    if (recur_data[0x06] == 0x02) {
        fprintf (fptr, ";INTERVAL=%d;BYMONTHDAY=%d", recur_data[0x0E],
        recur_data[0x16]);
        if (recur_data[0x1A] == 0x22 || recur_data[0x1A] == 0x21) {
        fprintf (
            fptr, ";COUNT=%d", getRruleCount (recur_data[0x1F],
            recur_data[0x1E]));
        }
    } else if (recur_data[0x06] == 0x03) {
        fprintf (fptr, ";BYDAY=%s;BYSETPOS=%d;INTERVAL=%d",
        getRruleDayname (recur_data[0x16]),
        recur_data[0x1A] == 0x05 ? -1 : recur_data[0x1A],
        recur_data[0x0E]);
        if (recur_data[0x1E] == 0x22 || recur_data[0x1E] == 0x21) {
        fprintf (
            fptr, ";COUNT=%d", getRruleCount (recur_data[0x23],
            recur_data[0x22]));
        }
    }
    } else if (recur_data[0x04] == 0x0D) {
    fprintf (
        fptr, "YEARLY;BYMONTH=%d",
        getRruleMonthNum (recur_data[0x0A], recur_data[0x0B]));
    if (recur_data[0x06] == 0x02) {
        fprintf (fptr, ";BYMONTHDAY=%d", recur_data[0x16]);
    } else if (recur_data[0x06] == 0x03) {
        fprintf (fptr, ";BYDAY=%s;BYSETPOS=%d",
        getRruleDayname (recur_data[0x16]),
        recur_data[0x1A] == 0x05 ? -1 : recur_data[0x1A]);
    }
    if (recur_data[0x1E] == 0x22 || recur_data[0x1E] == 0x21) {
        fprintf (fptr, ";COUNT=%d", getRruleCount (recur_data[0x23],
        recur_data[0x22]));
    }
    }
    fprintf (fptr, "\n");
}

void saveVCalendar (TNEFStruct *tnef, const gchar *tmpdir) {
    gchar *ifilename;
    variableLength *filename;
    gchar *charptr, *charptr2;
    FILE *fptr;
    gint index;
    DWORD *dword_ptr;
    dtr thedate;

    ifilename = g_build_filename (tmpdir, "calendar.vcf", NULL);
    printf ("%s\n", ifilename);

    if ((fptr = fopen (ifilename, "wb")) == NULL) {
            printf ("Error writing file to disk!");
    } else {
        fprintf (fptr, "BEGIN:VCALENDAR\n");
        if (tnef->messageClass[0] != 0) {
            charptr2 = tnef->messageClass;
            charptr = charptr2;
            while (*charptr != 0) {
                if (*charptr == '.') {
                    charptr2 = charptr;
                }
                charptr++;
            }
            if (strcmp (charptr2, ".MtgCncl") == 0) {
                fprintf (fptr, "METHOD:CANCEL\n");
            } else {
                fprintf (fptr, "METHOD:REQUEST\n");
            }
        } else {
            fprintf (fptr, "METHOD:REQUEST\n");
        }
        fprintf (fptr, "VERSION:2.0\n");
        fprintf (fptr, "BEGIN:VEVENT\n");

    /* UID
     * After alot of comparisons, I'm reasonably sure this is totally
     * wrong.  But it's not really necessary. */

    /* I think it only exists to connect future modification entries to
     * this entry. so as long as it's incorrectly interpreted the same way
     * every time, it should be ok :) */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_BINARY, 0x3))) == MAPI_UNDEFINED) {
            if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                            PROP_TAG (PT_BINARY, 0x23))) == MAPI_UNDEFINED) {
                filename = NULL;
            }
        }
        if (filename != NULL) {
            fprintf (fptr, "UID:");
            for (index = 0; index < filename->size; index++) {
                fprintf (fptr,"%02X", (guchar) filename->data[index]);
            }
            fprintf (fptr,"\n");
        }

        /* Sequence */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_LONG, 0x8201))) != MAPI_UNDEFINED) {
            dword_ptr = (DWORD *) filename->data;
            fprintf (fptr, "SEQUENCE:%i\n", (gint) *dword_ptr);
        }
        if ((filename = MAPIFindProperty (&(tnef->MapiProperties),
                        PROP_TAG (PT_BINARY, PR_SENDER_SEARCH_KEY)))
                != MAPI_UNDEFINED) {
            charptr = filename->data;
            charptr2 = strstr (charptr, ":");
            if (charptr2 == NULL)
                charptr2 = charptr;
            else
                charptr2++;
            fprintf (fptr, "ORGANIZER;CN=\"%s\":MAILTO:%s\n",
                    charptr2, charptr2);
        }

        /* Required Attendees */
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_STRING8, 0x823b))) != MAPI_UNDEFINED) {
        /* We have a list of required participants, so
           write them out. */
            if (filename->size > 1) {
                charptr = filename->data - 1;
                while (charptr != NULL) {
                    charptr++;
                    charptr2 = strstr (charptr, ";");
                    if (charptr2 != NULL) {
                        *charptr2 = 0;
                    }
                    while (*charptr == ' ')
                        charptr++;
                    fprintf (fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;");
                    fprintf (fptr, "ROLE=REQ-PARTICIPANT;RSVP=TRUE;");
                    fprintf (fptr, "CN=\"%s\":MAILTO:%s\n",
                                charptr, charptr);
                    charptr = charptr2;
                }
            }
            /* Optional attendees */
            if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                            PROP_TAG (PT_STRING8, 0x823c))) != MAPI_UNDEFINED) {
                    /* The list of optional participants */
                if (filename->size > 1) {
                    charptr = filename->data - 1;
                    while (charptr != NULL) {
                        charptr++;
                        charptr2 = strstr (charptr, ";");
                        if (charptr2 != NULL) {
                            *charptr2 = 0;
                        }
                        while (*charptr == ' ')
                            charptr++;
                        fprintf (fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;");
                        fprintf (fptr, "ROLE=OPT-PARTICIPANT;RSVP=TRUE;");
                        fprintf (fptr, "CN=\"%s\":MAILTO:%s\n",
                                charptr, charptr);
                        charptr = charptr2;
                    }
                }
            }
        } else if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_STRING8, 0x8238))) != MAPI_UNDEFINED) {
            if (filename->size > 1) {
                charptr = filename->data - 1;
                while (charptr != NULL) {
                    charptr++;
                    charptr2 = strstr (charptr, ";");
                    if (charptr2 != NULL) {
                        *charptr2 = 0;
                    }
                    while (*charptr == ' ')
                        charptr++;
                    fprintf (fptr, "ATTENDEE;PARTSTAT=NEEDS-ACTION;");
                    fprintf (fptr, "ROLE=REQ-PARTICIPANT;RSVP=TRUE;");
                    fprintf (fptr, "CN=\"%s\":MAILTO:%s\n",
                                charptr, charptr);
                    charptr = charptr2;
                }
            }

        }
        /* Summary */
        filename = NULL;
        if ((filename = MAPIFindProperty (&(tnef->MapiProperties),
                        PROP_TAG (PT_STRING8, PR_CONVERSATION_TOPIC)))
                != MAPI_UNDEFINED) {
            fprintf (fptr, "SUMMARY:");
            cstylefprint (fptr, filename);
            fprintf (fptr, "\n");
        }

        /* Description */
        if ((filename = MAPIFindProperty (&(tnef->MapiProperties),
                                PROP_TAG (PT_BINARY, PR_RTF_COMPRESSED)))
                != MAPI_UNDEFINED) {
            variableLength buf;
            if ((buf.data = (gchar *) DecompressRTF (filename, &buf.size)) != NULL) {
                fprintf (fptr, "DESCRIPTION:");
                printRtf (fptr, &buf);
                free (buf.data);
            }

        }

        /* Location */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_STRING8, 0x0002))) == MAPI_UNDEFINED) {
            if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                            PROP_TAG (PT_STRING8, 0x8208))) == MAPI_UNDEFINED) {
                filename = NULL;
            }
        }
        if (filename != NULL) {
            fprintf (fptr,"LOCATION: %s\n", filename->data);
        }
        /* Date Start */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_SYSTIME, 0x820d))) == MAPI_UNDEFINED) {
            if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                            PROP_TAG (PT_SYSTIME, 0x8516))) == MAPI_UNDEFINED) {
                filename = NULL;
            }
        }
        if (filename != NULL) {
            fprintf (fptr, "DTSTART:");
            MAPISysTimetoDTR ((guchar *) filename->data, &thedate);
            fprintf (fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
                    thedate.wYear, thedate.wMonth, thedate.wDay,
                    thedate.wHour, thedate.wMinute, thedate.wSecond);
        }
        /* Date End */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_SYSTIME, 0x820e))) == MAPI_UNDEFINED) {
            if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                            PROP_TAG (PT_SYSTIME, 0x8517))) == MAPI_UNDEFINED) {
                filename = NULL;
            }
        }
        if (filename != NULL) {
            fprintf (fptr, "DTEND:");
            MAPISysTimetoDTR ((guchar *) filename->data, &thedate);
            fprintf (fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
                    thedate.wYear, thedate.wMonth, thedate.wDay,
                    thedate.wHour, thedate.wMinute, thedate.wSecond);
        }
        /* Date Stamp */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_SYSTIME, 0x8202))) != MAPI_UNDEFINED) {
            fprintf (fptr, "CREATED:");
            MAPISysTimetoDTR ((guchar *) filename->data, &thedate);
            fprintf (fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
                    thedate.wYear, thedate.wMonth, thedate.wDay,
                    thedate.wHour, thedate.wMinute, thedate.wSecond);
        }
        /* Class */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_BOOLEAN, 0x8506))) != MAPI_UNDEFINED) {
            dword_ptr = (DWORD *) filename->data;
            fprintf (fptr, "CLASS:");
            if (*dword_ptr == 1) {
                fprintf (fptr,"PRIVATE\n");
            } else {
                fprintf (fptr,"PUBLIC\n");
            }
        }
        /* Recurrence */
        filename = NULL;
        if ((filename = MAPIFindUserProp (&(tnef->MapiProperties),
                        PROP_TAG (PT_BINARY, 0x8216))) != MAPI_UNDEFINED) {
            printRrule (fptr, filename->data, filename->size, tnef);
        }

        /* Wrap it up */
        fprintf (fptr, "END:VEVENT\n");
        fprintf (fptr, "END:VCALENDAR\n");
        fclose (fptr);
    }
    g_free (ifilename);
}

void saveVTask (TNEFStruct *tnef, const gchar *tmpdir) {
    variableLength *vl;
    variableLength *filename;
    gint index;
    gchar *ifilename;
    gchar *absfilename, *file;
    gchar *charptr, *charptr2;
    dtr thedate;
    FILE *fptr;
    DWORD *dword_ptr;

    vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_CONVERSATION_TOPIC));

    if (vl == MAPI_UNDEFINED) {
        return;
    }

    index = strlen (vl->data);
    while (vl->data[index] == ' ')
            vl->data[index--] = 0;

    file = sanitize_filename (vl->data);
    if (!file)
    return;
    absfilename = g_strconcat (file, ".vcf", NULL);
    ifilename = g_build_filename (tmpdir, absfilename, NULL);
    g_free (file);
    g_free (absfilename);

    printf ("%s\n", ifilename);

    if ((fptr = fopen (ifilename, "wb")) == NULL) {
            printf ("Error writing file to disk!");
    } else {
        fprintf (fptr, "BEGIN:VCALENDAR\n");
        fprintf (fptr, "VERSION:2.0\n");
        fprintf (fptr, "METHOD:PUBLISH\n");
        filename = NULL;

        fprintf (fptr, "BEGIN:VTODO\n");
        if (tnef->messageID[0] != 0) {
            fprintf (fptr,"UID:%s\n", tnef->messageID);
        }
        filename = MAPIFindUserProp (&(tnef->MapiProperties), \
                        PROP_TAG (PT_STRING8, 0x8122));
        if (filename != MAPI_UNDEFINED) {
            fprintf (fptr, "ORGANIZER:%s\n", filename->data);
        }

        if ((filename = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, PR_DISPLAY_TO))) != MAPI_UNDEFINED) {
            filename = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (PT_STRING8, 0x811f));
        }
        if ((filename != MAPI_UNDEFINED) && (filename->size > 1)) {
            charptr = filename->data - 1;
            while (charptr != NULL) {
                charptr++;
                charptr2 = strstr (charptr, ";");
                if (charptr2 != NULL) {
                    *charptr2 = 0;
                }
                while (*charptr == ' ')
                    charptr++;
                fprintf (fptr, "ATTENDEE;CN=%s;ROLE=REQ-PARTICIPANT:%s\n", charptr, charptr);
                charptr = charptr2;
            }
        }

        if (tnef->subject.size > 0) {
            fprintf (fptr,"SUMMARY:");
            cstylefprint (fptr,&(tnef->subject));
            fprintf (fptr,"\n");
        }

        if (tnef->body.size > 0) {
            fprintf (fptr,"DESCRIPTION:");
            cstylefprint (fptr,&(tnef->body));
            fprintf (fptr,"\n");
        }

        filename = MAPIFindProperty (&(tnef->MapiProperties), \
                    PROP_TAG (PT_SYSTIME, PR_CREATION_TIME));
        if (filename != MAPI_UNDEFINED) {
            fprintf (fptr, "DTSTAMP:");
            MAPISysTimetoDTR ((guchar *) filename->data, &thedate);
            fprintf (fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
                    thedate.wYear, thedate.wMonth, thedate.wDay,
                    thedate.wHour, thedate.wMinute, thedate.wSecond);
        }

        filename = MAPIFindUserProp (&(tnef->MapiProperties), \
                    PROP_TAG (PT_SYSTIME, 0x8517));
        if (filename != MAPI_UNDEFINED) {
            fprintf (fptr, "DUE:");
            MAPISysTimetoDTR ((guchar *) filename->data, &thedate);
            fprintf (fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
                    thedate.wYear, thedate.wMonth, thedate.wDay,
                    thedate.wHour, thedate.wMinute, thedate.wSecond);
        }
        filename = MAPIFindProperty (&(tnef->MapiProperties), \
                    PROP_TAG (PT_SYSTIME, PR_LAST_MODIFICATION_TIME));
        if (filename != MAPI_UNDEFINED) {
            fprintf (fptr, "LAST-MODIFIED:");
            MAPISysTimetoDTR ((guchar *) filename->data, &thedate);
            fprintf (fptr,"%04i%02i%02iT%02i%02i%02iZ\n",
                    thedate.wYear, thedate.wMonth, thedate.wDay,
                    thedate.wHour, thedate.wMinute, thedate.wSecond);
        }
        /* Class */
        filename = MAPIFindUserProp (&(tnef->MapiProperties), \
                        PROP_TAG (PT_BOOLEAN, 0x8506));
        if (filename != MAPI_UNDEFINED) {
            dword_ptr = (DWORD *) filename->data;
            fprintf (fptr, "CLASS:");
            if (*dword_ptr == 1) {
                fprintf (fptr,"PRIVATE\n");
            } else {
                fprintf (fptr,"PUBLIC\n");
            }
        }
        fprintf (fptr, "END:VTODO\n");
        fprintf (fptr, "END:VCALENDAR\n");
        fclose (fptr);
    }
    g_free (ifilename);
}

void fprintProperty (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]) {
    variableLength *vl;
    if ((vl = MAPIFindProperty (&(tnef->MapiProperties), PROP_TAG (proptype, propid))) != MAPI_UNDEFINED) {
        if (vl->size > 0) {
            if ((vl->size == 1) && (vl->data[0] == 0)) {
            } else {
                fprintf (fptr, text, vl->data);
            }
    }
    }
}

void fprintUserProp (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]) {
    variableLength *vl;
    if ((vl = MAPIFindUserProp (&(tnef->MapiProperties), PROP_TAG (proptype, propid))) != MAPI_UNDEFINED) {
        if (vl->size > 0) {
            if ((vl->size == 1) && (vl->data[0] == 0)) {
            } else {
                fprintf (fptr, text, vl->data);
            }
    }
    }
}

void quotedfprint (FILE *fptr, variableLength *vl) {
    gint index;

    for (index = 0; index < vl->size - 1; index++) {
        if (vl->data[index] == '\n') {
            fprintf (fptr, "=0A");
        } else if (vl->data[index] == '\r') {
        } else {
            fprintf (fptr, "%c", vl->data[index]);
        }
    }
}

void cstylefprint (FILE *fptr, variableLength *vl) {
    gint index;

    for (index = 0; index < vl->size - 1; index++) {
        if (vl->data[index] == '\n') {
            fprintf (fptr, "\\n");
        } else if (vl->data[index] == '\r') {
            /* Print nothing. */
        } else if (vl->data[index] == ';') {
            fprintf (fptr, "\\;");
        } else if (vl->data[index] == ',') {
            fprintf (fptr, "\\,");
        } else if (vl->data[index] == '\\') {
            fprintf (fptr, "\\");
        } else {
            fprintf (fptr, "%c", vl->data[index]);
        }
    }
}

void printRtf (FILE *fptr, variableLength *vl) {
    gint index;
    gchar *byte;
    gint brace_ct;
    gint key;

    key = 0;
    brace_ct = 0;

    for (index = 0, byte = vl->data; index < vl->size; index++, byte++) {
        if (*byte == '}') {
            brace_ct--;
            key = 0;
            continue;
        }
        if (*byte == '{') {
            brace_ct++;
            continue;
        }
        if (*byte == '\\') {
            key = 1;
        }
        if (isspace (*byte)) {
            key = 0;
        }
        if ((brace_ct == 1) && (key == 0)) {
            if (*byte == '\n') {
                fprintf (fptr, "\\n");
            } else if (*byte == '\r') {
        /* Print nothing. */
            } else if (*byte == ';') {
                fprintf (fptr, "\\;");
            } else if (*byte == ',') {
                fprintf (fptr, "\\,");
            } else if (*byte == '\\') {
                fprintf (fptr, "\\");
            } else {
                fprintf (fptr, "%c", *byte);
            }
        }
    }
    fprintf (fptr, "\n");
}