"Fossies" - the Fresh Open Source Software Archive

Member "evolution-brutus-1.2.35/camel/camel-brutus-folder-summary.c" (18 Dec 2008, 70619 Bytes) of archive /linux/misc/old/evolution-brutus-1.2.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "camel-brutus-folder-summary.c" see the Fossies "Dox" file reference documentation.

    1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
    2 
    3 /*
    4  *    Authors: Jules Colding <colding@42tools.com>
    5  *
    6  *    Camel Brutus folder summary class.
    7  *
    8  *    Copyright (C) 2005-2007 OMC Denmark ApS.
    9  *
   10  *    This program is free software; you can redistribute it and/or
   11  *    modify it under the terms of the GNU General Public License as
   12  *    published by the Free Software Foundation; either version 2 of
   13  *    the License, or (at your option) any later version.
   14  *
   15  *    This program is distributed in the hope that it will be useful,
   16  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   18  *    GNU General Public License for more details.
   19  *
   20  *    You should have received a copy of the GNU General Public License
   21  *    along with this program; if not, write to the Free Software
   22  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   23  *    MA 02111-1307 USA
   24  */
   25 
   26 #ifdef HAVE_CONFIG_H
   27 #include <config.h>
   28 #endif
   29 
   30 /* system includes */
   31 #include <ctype.h>
   32 #include <string.h>
   33 
   34 /* Camel includes */
   35 #include <camel/camel-i18n.h>
   36 #include <camel/camel-operation.h>
   37 #include <camel/camel-file-utils.h>
   38 #include <camel/camel-mime-utils.h>
   39 #include <camel/camel-string-utils.h>
   40 
   41 #include <libedataserver/e-iconv.h>
   42 #include <libedataserver/md5-utils.h>
   43 
   44 /* camel-brutus includes */
   45 #include "camel-brutus-folder-summary.h"
   46 #include "camel-brutus-store.h"
   47 #include "camel-brutus-folder.h"
   48 #include "camel-brutus-private.h"
   49 
   50 /* pure brutus includes */
   51 #include <idl_output/IMAPIFolder.h>
   52 #include <idl_output/return_codes.h>
   53 #include <idl_output/types.h>
   54 
   55 /* evolution-brutus includes */
   56 #include <server/brutus_corba.h>
   57 #include <server/brutus_mapi.h>
   58 #include <server/brutus_smtp.h>
   59 #include <server/brutus_cpid.h>
   60 #include <server/brutus_util.h>
   61 #include <server/brutus_conv.h>
   62 #include <server/brutus.h>
   63 
   64 #define CAMEL_BRUTUS_SUMMARY_VERSION (2)
   65 
   66 static CamelFolderSummaryClass *camel_brutus_summary_parent;
   67 
   68 // for the summary update thread pool
   69 struct _folder_data {
   70     CamelStore *store;
   71     char *full_name;
   72 };
   73 
   74 /*
   75  * Will free all internally allocated memory from "info"
   76  */
   77 static void
   78 brutus_message_info_empty(CamelFolderSummary *s,
   79               CamelMessageInfoBase *mi)
   80 {
   81     g_async_queue_ref(wait_mem_queue);
   82     g_async_queue_push(wait_mem_queue, (gpointer)mi->uid);
   83     mi->uid = NULL;
   84     g_async_queue_unref(wait_mem_queue);
   85 
   86     camel_pstring_free(mi->subject);
   87     mi->subject = NULL;
   88 
   89     camel_pstring_free(mi->from);
   90     mi->from = NULL;
   91 
   92     camel_pstring_free(mi->to);
   93     mi->to = NULL;
   94 
   95     camel_pstring_free(mi->cc);
   96     mi->cc = NULL;
   97 
   98     camel_pstring_free(mi->mlist);
   99     mi->mlist = NULL;
  100 
  101     g_free(mi->references);
  102     mi->references = NULL;
  103 
  104     camel_flag_list_free(&mi->user_flags);
  105 
  106     camel_tag_list_free(&mi->user_tags);
  107 
  108     if (s && mi->content)
  109         camel_folder_summary_content_info_free(s, mi->content);
  110     mi->content = NULL;
  111 }
  112 
  113 /*
  114  * Adapted from "camel-folder-summary.c".
  115  * The return value is un-casted gchar* on pupose to detect any
  116  * difference between char and gchar at compile time. The original
  117  * e-d-s code is a mess between gchar returning functions and char
  118  * return values :-(
  119  */
  120 static gchar*
  121 brutus_camel_summary_format_string(struct _camel_header_raw *header,
  122                    const char *name,
  123                    const char *charset)
  124 {
  125     const gchar *text;
  126 
  127     text = camel_header_raw_find(&header, name, NULL);
  128     if (!text)
  129         return NULL;
  130 
  131     while (isspace((int)*text))
  132         text++;
  133 
  134     return camel_header_decode_string(text, charset);
  135 }
  136 
  137 /*
  138  * Adapted from "camel-folder-summary.c"
  139  */
  140 static gchar*
  141 brutus_camel_summary_format_address(struct _camel_header_raw *header,
  142                     const char *name,
  143                     const char *charset)
  144 {
  145     struct _camel_header_address *addr_list;
  146     const gchar *text;
  147     gchar *retv;
  148 
  149     text = camel_header_raw_find(&header, name, NULL);
  150     addr_list = camel_header_address_decode(text, charset);
  151     if (addr_list) {
  152         retv = camel_header_address_list_format(addr_list);
  153         camel_header_address_list_clear(&addr_list);
  154     } else {
  155         retv = g_strdup(text);
  156     }
  157 
  158     return retv;
  159 }
  160 
  161 static int
  162 brutus_summary_header_load(CamelFolderSummary *s,
  163                FILE *in)
  164 {
  165     char *tmp = NULL;
  166     CamelBrutusSummary *cbs = CAMEL_BRUTUS_SUMMARY(s);
  167 
  168     if (-1 == camel_brutus_summary_parent->summary_header_load(s, in))
  169         return -1;
  170 
  171     if (-1 == camel_file_util_decode_uint32(in, &cbs->version))
  172         return -1;
  173 
  174     if (1 == cbs->version)
  175         return 0; // no more to load
  176 
  177     /*
  178      * version 2 or later...
  179      */
  180 
  181     // flags
  182     if (-1 == camel_file_util_decode_uint32(in, &cbs->flags))
  183         return -1;
  184 
  185     // get session key
  186     if (-1 == camel_file_util_decode_string(in, &tmp))
  187         return -1;
  188 
  189     memcpy((void*)cbs->session_key, (const void*)tmp, sizeof(cbs->session_key));
  190     g_free(tmp);
  191 
  192     if (2 == cbs->version)
  193         return 0; // no more to load
  194 
  195     return -1;
  196 }
  197 
  198 static int
  199 brutus_summary_header_save(CamelFolderSummary *s,
  200                FILE *out)
  201 {
  202     CamelBrutusSummary *cbs = CAMEL_BRUTUS_SUMMARY(s);
  203 
  204     if (-1 == camel_brutus_summary_parent->summary_header_save(s, out))
  205         return -1;
  206 
  207     if (-1 == camel_file_util_encode_uint32(out, CAMEL_BRUTUS_SUMMARY_VERSION))
  208         return -1;
  209 
  210     if (-1 == camel_file_util_encode_uint32(out, cbs->flags))
  211         return -1;
  212 
  213     if (-1 == camel_file_util_encode_string(out, cbs->session_key))
  214         return -1;
  215 
  216     return 0;
  217 }
  218 
  219 static CamelMessageInfo *
  220 brutus_message_info_clone(CamelFolderSummary *s,
  221               const CamelMessageInfo *mi)
  222 {
  223     CamelBrutusMessageInfo *to;
  224     const CamelBrutusMessageInfo *from = (CamelBrutusMessageInfo*)mi;
  225 
  226     to = (CamelBrutusMessageInfo*)camel_brutus_summary_parent->message_info_clone(s, mi);
  227     to->pr_record_key = g_strdup(from->pr_record_key);
  228 
  229     return (CamelMessageInfo*)to;
  230 }
  231 
  232 static CamelMessageInfo*
  233 brutus_message_info_load(CamelFolderSummary *s,
  234              FILE *in)
  235 {
  236     CamelMessageInfo *info;
  237     CamelBrutusMessageInfo *brutus_info;
  238 
  239     info = camel_brutus_summary_parent->message_info_load(s, in);
  240     if (!info)
  241         goto err;
  242 
  243     brutus_info = (CamelBrutusMessageInfo*)info;
  244     brutus_info->pr_record_key = NULL;
  245 
  246     if (-1 == camel_file_util_decode_string(in, &brutus_info->pr_record_key))
  247         goto err;
  248 
  249     return info;
  250 
  251 err:
  252     if (info)
  253         camel_message_info_free(info);
  254 
  255     return NULL;
  256 }
  257 
  258 static int
  259 brutus_message_info_save(CamelFolderSummary *s,
  260              FILE *out,
  261              CamelMessageInfo *info)
  262 {
  263     CamelBrutusMessageInfo *brutus_info = (CamelBrutusMessageInfo*)info;
  264 
  265     if (-1 == camel_brutus_summary_parent->message_info_save(s, out, info))
  266         return -1;
  267 
  268     return camel_file_util_encode_string(out, brutus_info->pr_record_key);
  269 }
  270 
  271 static void
  272 brutus_message_info_free(CamelFolderSummary *s,
  273              CamelMessageInfo *mi)
  274 {
  275     CamelBrutusMessageInfo *bi = (CamelBrutusMessageInfo *)mi;
  276 
  277     g_free(bi->pr_record_key);
  278     ((CamelFolderSummaryClass*)camel_brutus_summary_parent)->message_info_free(s, mi);
  279 }
  280 
  281 /* static gboolean brutus_info_set_flags(CamelMessageInfo *mi,  */
  282 /*                    guint32 mask,  */
  283 /*                    guint32 set); */
  284 
  285 static void
  286 camel_brutus_summary_class_init(CamelBrutusSummaryClass *klass)
  287 {
  288     CamelFolderSummaryClass *parent_class = (CamelFolderSummaryClass*)klass;
  289 
  290     camel_brutus_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_type_get_global_classfuncs(camel_folder_summary_get_type()));
  291 
  292     parent_class->message_info_clone = brutus_message_info_clone ;
  293     parent_class->summary_header_load = brutus_summary_header_load;
  294     parent_class->summary_header_save = brutus_summary_header_save;
  295     parent_class->message_info_load = brutus_message_info_load;
  296     parent_class->message_info_save = brutus_message_info_save;
  297     parent_class->message_info_free = brutus_message_info_free;
  298 /*  parent_class->info_set_flags = brutus_info_set_flags;  */
  299 /*  parent_class->content_info_load = brutus_content_info_load; */
  300 /*  parent_class->content_info_save = brutus_content_info_save; */
  301 }
  302 
  303 static void
  304 camel_brutus_summary_init(CamelBrutusSummary *brutus_summary)
  305 {
  306     CamelFolderSummary *summary = (CamelFolderSummary *)brutus_summary;
  307 
  308     /* subclasses need to set the right instance data sizes */
  309     summary->message_info_size = sizeof(CamelBrutusMessageInfo);
  310     summary->content_info_size = 0; //sizeof(CamelBrutusMessageContentInfo);
  311 }
  312 
  313 CamelFolderSummary*
  314 camel_brutus_summary_new(CamelFolder *folder,
  315              const char *summary_filename)
  316 {
  317     CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY(camel_object_new(camel_brutus_summary_get_type()));
  318 
  319     summary->flags = 0;
  320     summary->folder = folder ;
  321     camel_folder_summary_set_build_content(summary, FALSE);
  322     camel_folder_summary_set_filename(summary, summary_filename);
  323 
  324     // create the file if it doesn't exist
  325     if (-1 == camel_folder_summary_load(summary)) {
  326         camel_folder_summary_clear(summary);
  327         camel_folder_summary_touch(summary);
  328     }
  329 
  330     return summary;
  331 }
  332 
  333 /*
  334  * This function will walk the folder summary and update all message
  335  * infos build during a previous run of brutus_update_folder_summary_light()
  336  */
  337 void
  338 brutus_update_folder_summary_post_light(gpointer data,
  339                     gpointer static_data)
  340 {
  341     CamelException *ex = camel_exception_new();
  342     struct _folder_data *folder_data = (struct _folder_data*)data;
  343     CamelStore *parent_store = folder_data->store;
  344     char *full_name = folder_data->full_name;
  345     CamelFolder *folder = NULL;
  346     CamelBrutusStore *brutus_store = NULL;
  347     CamelBrutusStorePrivate *priv = NULL;
  348     BrutusBaseClass *brutus_base = NULL;
  349     CamelBrutusFolder *brutus_folder = NULL;
  350     CamelBrutusSummary *cbs = NULL;
  351     CamelBrutusMessageInfo *msg_info_ptr = NULL;
  352     CamelBrutusMessageInfo *msg_info = NULL;
  353     CamelFolderChangeInfo *changes = NULL;
  354     GPtrArray *summary = NULL;
  355     struct _camel_header_raw *camel_header_raw = NULL;
  356     struct _camel_header_address *camel_addr_list = NULL;
  357     struct _camel_header_address *camel_addr = NULL;
  358     struct _camel_header_references *refs = NULL;
  359     struct _camel_header_references *irt = NULL;
  360     struct _camel_header_references *scan = NULL;
  361     CamelContentType *ct = NULL;
  362     const char *content = NULL;
  363     const char *charset = NULL;
  364     gboolean errors = TRUE;
  365     gboolean inbound = FALSE;
  366     gboolean aborted = FALSE;
  367     char *msg_id = NULL;
  368     char *smtp_header = NULL;
  369     char *tmp = NULL;
  370     guchar digest[16] = { 0 };
  371     int count = 0;
  372     CORBA_long n = 0;
  373     CORBA_unsigned_long r = 0;
  374     CORBA_unsigned_long k = 0;
  375     BRUTUS_BRESULT br = BRUTUS_BRUTUS_UNKNOWN_ERROR;
  376     BRUTUS_ENTRYID *eid = NULL;
  377     BRUTUS_ENTRYID *sender_eid = NULL;
  378     BRUTUS_SRowSet *recp_row_set = NULL;
  379     BRUTUS_SPropValue *pv = NULL;
  380     BRUTUS_seq_SPropValue *prop_values = NULL;
  381     BRUTUS_seq_SPropValue *ex_prop_values = NULL;
  382     CORBA_Environment ev[1];
  383     static BRUTUS_BDEFINE recp_props[3] = {               // for an recipients table
  384         /* 0 */ BRUTUS_BRUTUS_PR_RECIPIENT_TYPE,             // MAPI_TO, MAPI_CC, MAPI_BCC
  385         /* 1 */ BRUTUS_BRUTUS_PR_EMAIL_ADDRESS,              // if not there use PR_DISPLAY_NAME
  386         /* 2 */ BRUTUS_BRUTUS_PR_DISPLAY_NAME,               // display name, possibly email adress if recipient does not resolve in the Exchange address book
  387     };
  388     static BRUTUS_SPropTagArray recp_proptag_array = {    // for an recipients table
  389         ._maximum = 3,
  390         ._length = 3,
  391         ._buffer = recp_props,
  392     };
  393     static BRUTUS_BDEFINE msg_props[14] = {               // for a message object
  394         /* 0  */ BRUTUS_BRUTUS_PR_ENTRYID,                   // long-term entryid
  395         /* 1  */ BRUTUS_BRUTUS_PR_DISPLAY_CC,                // display name of CC recipients
  396         /* 2  */ BRUTUS_BRUTUS_PR_SENDER_EMAIL_ADDRESS,      // email address of sender
  397         /* 3  */ BRUTUS_BRUTUS_PR_TRANSPORT_MESSAGE_HEADERS, // smtp envelope of inbound messages
  398         /* 4  */ BRUTUS_BRUTUS_PR_INTERNET_CPID,             // Equivalent to RFC 2822 "Content-Type".
  399         /* 5  */ BRUTUS_BRUTUS_PR_SENDER_ADDRTYPE,           // MHS, PROFS, SMTP, X400 or EX
  400         /* 6  */ BRUTUS_BRUTUS_PR_CLIENT_SUBMIT_TIME,        // Equivalent to RFC 2822 "Date:" when inbound
  401         /* 7  */ BRUTUS_BRUTUS_PR_PROVIDER_SUBMIT_TIME,      // Equivalent to RFC 2822 "Date:" when outbound
  402         /* 8  */ BRUTUS_BRUTUS_PR_INTERNET_MESSAGE_ID,       // Equivalent to RFC 2822 "Message-Id:"
  403         /* 9  */ BRUTUS_BRUTUS_PR_INTERNET_REFERENCES,       // Equivalent to RFC 2822 "References:" (rarely seen)
  404         /* 10 */ BRUTUS_BRUTUS_PR_IN_REPLY_TO_ID,            // Equivalent to RFC 2822 "In-Reply-To:"
  405         /* 11 */ BRUTUS_BRUTUS_PR_RECEIVED_BY_ADDRTYPE,      // inbound if not found
  406         /* 12 */ BRUTUS_BRUTUS_PR_SENDER_ENTRYID,            // open and get PR_SMTP_ADDRESS if PR_SENDER_ADDRTYPE==EX
  407         /* 13 */ BRUTUS_BRUTUS_PR_SUBJECT,                   // subject
  408         /* 14 *//*  BRUTUS_BRUTUS_PR_, */
  409     };
  410     static BRUTUS_SPropTagArray msg_proptag_array = {     // for message object properties
  411         ._maximum = 14,
  412         ._length = 14,
  413         ._buffer = msg_props,
  414     };
  415     static BRUTUS_SPropTagArray ex_msg_proptag_array = {  // for message object properties
  416         ._maximum = 0,
  417         ._length = 0,
  418         ._buffer = NULL,
  419     };
  420 
  421     folder = camel_brutus_folder_new(parent_store, full_name, 0, ex);
  422     camel_object_unref(CAMEL_OBJECT(parent_store));
  423     parent_store = NULL;
  424     g_free(full_name);
  425     full_name = NULL;
  426     g_free(folder_data);
  427     folder_data = NULL;
  428     if (camel_exception_is_set(ex)) {
  429         d("Could not create camel folder");
  430         camel_exception_free(ex);
  431         return;
  432     }
  433     camel_exception_free(ex);
  434     brutus_folder = CAMEL_BRUTUS_FOLDER(folder);
  435 
  436     BRUTUS_FOLDER_LOCK(brutus_folder, summary_mutex);
  437 
  438     d(folder->full_name);
  439 
  440     CORBA_exception_init(ev);
  441 
  442     brutus_store = CAMEL_BRUTUS_STORE(camel_folder_get_parent_store(folder));
  443     priv = brutus_store->priv;
  444     brutus_base = BRUTUS_BASE_CLASS(priv);
  445     if (!brutus_is_likely_connected(brutus_base))
  446         goto out_err;
  447 
  448     summary = camel_folder_get_summary(folder);
  449     if (!summary)
  450         goto out;
  451 
  452     // iterate over summary content (columns)
  453     dfmt2("Number of messages to parse in \"%s\" = %llu", folder->full_name, (long long unsigned int)summary->len);
  454     for (r = 0; r < summary->len; r++) {
  455         if (!brutus_is_likely_connected(brutus_base)) { // kill the thread
  456             aborted = TRUE;
  457             goto out_err; // force a later update to commence from the dawn of times
  458         }
  459 
  460         changes = camel_folder_change_info_new();
  461         if (!changes)
  462             goto out_err;
  463 
  464         if (!folder_summary_update_is_a_go(folder->full_name)) {
  465             aborted = TRUE; // due to a delete that is underway
  466             break;
  467         }
  468 
  469         // to catch goto's
  470         errors = TRUE;
  471 
  472         // get the cached message info pointer to retrieve the uid
  473         msg_info_ptr = g_ptr_array_index(summary, r);
  474 
  475         // get the real message info
  476         msg_info = (CamelBrutusMessageInfo*)camel_folder_summary_uid(folder->summary, msg_info_ptr->info.uid);
  477         msg_info_ptr = NULL;
  478 
  479         // get the uid
  480         eid = brutus_string_to_entryid(msg_info->info.uid);
  481 
  482         // get properties from message object
  483         br = BRUTUS_IMAPISession_QueryMessage(brutus_folder->mapi_session,
  484                               eid,
  485                               &msg_proptag_array,
  486                               &ex_msg_proptag_array,
  487                               &recp_proptag_array,
  488                               &prop_values,
  489                               &ex_prop_values,
  490                               &recp_row_set,
  491                               ev);
  492         CORBA_free(ex_prop_values); // we are not asking for any additional properties
  493         ex_prop_values = NULL;
  494         CORBA_free(eid);
  495         eid = NULL;
  496         if (ORBIT2_EX(ev)) {
  497             PRINT_ORBIT2_EX(ev);
  498             goto next;
  499         }
  500         if ((BRUTUS_BRUTUS_MAPI_W_ERRORS_RETURNED != br) && (BRUTUS_BRUTUS_S_OK != br)) {
  501             d(brutus_bresult_to_str(br));
  502             goto next;
  503         }
  504 
  505         // inbound or outbound?
  506         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[11].ulPropTag)) // PR_RECEIVED_BY_ADDRTYPE
  507             inbound = TRUE;
  508         else
  509             inbound = FALSE; // draft, sent or being edited
  510 
  511         // get full SMTP header if present, alternatively check MSGFLAG_ORIGIN_INTERNET first
  512         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[3].ulPropTag)) { // PR_TRANSPORT_MESSAGE_HEADERS
  513             smtp_header = brutus_unfold_rfc822_header(prop_values->_buffer[3].Value._u.lpszA);
  514             if (smtp_header) {
  515                 camel_header_raw = brutus_get_camel_header_raw(smtp_header);
  516                 free(smtp_header);
  517                 smtp_header = NULL;
  518             } else
  519                 goto next;
  520         } else
  521             camel_header_raw = NULL;
  522 
  523         // get long-term ENTRYID
  524         brutus_sbinary_to_entryid(&prop_values->_buffer[0].Value._u.bin, &eid);
  525         if (!eid)
  526             goto next;
  527 
  528         msg_id = brutus_entryid_to_string(eid);
  529         CORBA_free(eid);
  530         eid = NULL;
  531         if (!msg_id)
  532             goto next;
  533 
  534         // charset and content type
  535         ct = NULL;
  536         content = NULL;
  537         charset = NULL;
  538         if (camel_header_raw) {
  539             if ((content = camel_header_raw_find(&camel_header_raw, "Content-Type", NULL))
  540                 && (ct = camel_content_type_decode(content))
  541                 && (charset = camel_content_type_param(ct, "charset"))
  542                 && (!g_ascii_strcasecmp(charset, "us-ascii")))
  543                 charset = NULL;
  544         } else {
  545             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[11].ulPropTag)) // PR_INTERNET_CPID
  546                 charset = brutus_cpid_to_label(prop_values->_buffer[11].Value._u.l);
  547         }
  548         charset = charset ? e_iconv_charset_name(charset) : NULL;
  549         camel_content_type_unref(ct);
  550 
  551         // push the uid to the delayed free queue
  552         g_async_queue_ref(wait_mem_queue);
  553         g_async_queue_push(wait_mem_queue, (gpointer)msg_info->info.uid);
  554         msg_info->info.uid = msg_id;
  555         msg_id = NULL;
  556         g_async_queue_unref(wait_mem_queue);
  557 
  558         // Message-Id:
  559         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[8].ulPropTag)) // PR_INTERNET_MESSAGE_ID
  560             msg_id = camel_header_msgid_decode(prop_values->_buffer[8].Value._u.lpszA);
  561         else if (camel_header_raw)
  562             msg_id = camel_header_msgid_decode(camel_header_raw_find(&camel_header_raw, "Message-Id", NULL));
  563         else {
  564             d("Invalid RFC 822 message header");
  565 #ifndef BRUTUS_SPY
  566             goto rollback;
  567 #endif
  568         }
  569         if (!msg_id) {
  570             d("No memory or invalid RFC 822 message header");
  571 #ifdef BRUTUS_SPY
  572             memset(&msg_info->info.message_id, 0, sizeof(CamelSummaryMessageID));
  573 #else
  574             goto rollback;
  575 #endif
  576         } else {
  577             md5_get_digest(msg_id, strlen(msg_id), digest);
  578             memcpy(msg_info->info.message_id.id.hash, digest, sizeof(msg_info->info.message_id.id.hash));
  579             g_free(msg_id);
  580             msg_id = NULL;
  581         }
  582 
  583         // Subject:
  584         tmp = NULL;
  585         camel_pstring_free(msg_info->info.subject);
  586         msg_info->info.subject = NULL;
  587         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[13].ulPropTag))
  588             tmp = camel_header_decode_string(prop_values->_buffer[13].Value._u.lpszA, charset);
  589         else if (camel_header_raw)
  590             tmp = brutus_camel_summary_format_string(camel_header_raw, "Subject", charset);
  591         if (tmp) {
  592             msg_info->info.subject = camel_pstring_strdup(tmp);
  593             g_free(tmp);
  594             tmp = NULL;
  595         }
  596 
  597         /*
  598          * Recipients. The recipient is BCC if neither "To:" nor "CC:" is present
  599          * in the recipient table.
  600          */
  601 
  602         // To:
  603         camel_header_address_list_clear(&camel_addr_list);
  604         if (camel_header_raw) {
  605             tmp = brutus_camel_summary_format_address(camel_header_raw, "To", charset);
  606         } else if ((recp_row_set->_length) && (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(recp_row_set->_buffer[0]._buffer[0].ulPropTag))) { // we don't know if STORE_SUBMIT_OK is set
  607             for (k = 0; k<recp_row_set->_length; k++) { // loop all recipients
  608                 if (BRUTUS_BRUTUS_MAPI_TO & recp_row_set->_buffer[k]._buffer[0].Value._u.l) {
  609                     n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_EMAIL_ADDRESS);
  610                     if (-1 == n) // no PR_EMAIL_ADDRESS
  611                         n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_DISPLAY_NAME);
  612 
  613                     camel_addr = camel_header_address_decode(recp_row_set->_buffer[k]._buffer[n].Value._u.lpszA, charset);
  614                     camel_header_address_list_append(&camel_addr_list, camel_addr);
  615                 }
  616             }
  617             if (camel_addr_list) {
  618                 tmp = camel_header_address_list_format(camel_addr_list);
  619                 camel_header_address_list_clear(&camel_addr_list);
  620             }
  621         }
  622         if (tmp) {
  623             camel_pstring_free(msg_info->info.to);
  624             msg_info->info.to = camel_pstring_strdup(tmp);
  625             g_free(tmp);
  626             tmp = NULL;
  627         }
  628 
  629         // CC:
  630         camel_header_address_list_clear(&camel_addr_list);
  631         camel_pstring_free(msg_info->info.cc);
  632         msg_info->info.cc = NULL;
  633         if (camel_header_raw) {
  634             tmp = brutus_camel_summary_format_address(camel_header_raw, "CC", charset);
  635         } else if ((recp_row_set->_length) && (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(recp_row_set->_buffer[0]._buffer[0].ulPropTag))) { // we don't know if STORE_SUBMIT_OK is set
  636             for (k = 0; k<recp_row_set->_length; k++) { // loop all recipients
  637                 if (BRUTUS_BRUTUS_MAPI_CC & recp_row_set->_buffer[k]._buffer[0].Value._u.l) {
  638                     n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_EMAIL_ADDRESS);
  639                     if (-1 == n) // no PR_EMAIL_ADDRESS
  640                         n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_DISPLAY_NAME);
  641 
  642                     camel_addr = camel_header_address_decode(recp_row_set->_buffer[k]._buffer[n].Value._u.lpszA, charset);
  643                     camel_header_address_list_append(&camel_addr_list, camel_addr);
  644                 }
  645             }
  646             if (camel_addr_list) {
  647                 tmp = camel_header_address_list_format(camel_addr_list);
  648                 camel_header_address_list_clear(&camel_addr_list);
  649             }
  650         }
  651         if (tmp) {
  652             msg_info->info.to = camel_pstring_strdup(tmp);
  653             g_free(tmp);
  654             tmp = NULL;
  655         }
  656 
  657         // From:
  658         camel_header_address_list_clear(&camel_addr_list);
  659         if (camel_header_raw) {
  660             tmp = brutus_camel_summary_format_address(camel_header_raw, "From", charset);
  661         } else { // check for sender addrtype: SMTP=>Get SENDER_EMAIL_ADDRESS. EX=>Open sender and get PR_SMTP_ADDRESS.
  662             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[5].ulPropTag)) { // PR_SENDER_ADDRTYPE
  663                 if (!g_ascii_strcasecmp("SMTP", prop_values->_buffer[5].Value._u.lpszA)) {
  664                     if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[2].ulPropTag)) { // PR_SENDER_EMAIL_ADDRESS
  665                         camel_addr_list = camel_header_address_decode(prop_values->_buffer[2].Value._u.lpszA, charset);
  666                         tmp = camel_header_address_list_format(camel_addr_list);
  667                         camel_header_address_list_clear(&camel_addr_list);
  668                     }
  669                 } else if (!g_ascii_strcasecmp("EX", prop_values->_buffer[5].Value._u.lpszA)) {
  670                     if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[12].ulPropTag)) { // PR_SENDER_ENTRYID
  671                         brutus_sbinary_to_entryid(&prop_values->_buffer[12].Value._u.bin, &sender_eid);
  672                         if (sender_eid) {
  673                             pv = brutus_open_object_get_one_prop(brutus_folder->mapi_session,
  674                                                  CORBA_OBJECT_NIL,
  675                                                  sender_eid,
  676                                                  BRUTUS_BRUTUS_PR_SMTP_ADDRESS);
  677                             if ((pv) && (BRUTUS_BRUTUS_PR_SMTP_ADDRESS == pv->ulPropTag)) {
  678                                 camel_addr_list = camel_header_address_decode(pv->Value._u.lpszA, charset);
  679                                 tmp = camel_header_address_list_format(camel_addr_list);
  680                                 camel_header_address_list_clear(&camel_addr_list);
  681                             }
  682                             CORBA_free(pv);
  683                             pv = NULL;
  684                             CORBA_free(sender_eid);
  685                             sender_eid = NULL;
  686                         }
  687                     }
  688                 }
  689             } else { // unknown address type
  690                 if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[2].ulPropTag)) { // PR_SENDER_EMAIL_ADDRESS
  691                     camel_addr_list = camel_header_address_decode(prop_values->_buffer[7].Value._u.lpszA, charset);
  692                     tmp = camel_header_address_list_format(camel_addr_list);
  693                     camel_header_address_list_clear(&camel_addr_list);
  694                 }
  695             }
  696         }
  697         if (tmp) {
  698             camel_pstring_free(msg_info->info.from);
  699             msg_info->info.from = camel_pstring_strdup(tmp);
  700             g_free(tmp);
  701             tmp = NULL;
  702         }
  703 
  704         // Received/Sent:
  705         if (inbound) {
  706             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[6].ulPropTag)) // PR_CLIENT_SUBMIT_TIME
  707                 msg_info->info.date_sent = brutus_filetime_to_time_t(prop_values->_buffer[6].Value._u.ft);
  708             else if (camel_header_raw)
  709                 msg_info->info.date_sent = camel_header_decode_date(camel_header_raw_find(&camel_header_raw, "Date", NULL), NULL);
  710             else
  711                 msg_info->info.date_sent = 0;
  712         } else {
  713             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[7].ulPropTag))        // PR_PROVIDER_SUBMIT_TIME
  714                 msg_info->info.date_sent = brutus_filetime_to_time_t(prop_values->_buffer[7].Value._u.ft);
  715             else if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[6].ulPropTag))   // PR_CLIENT_SUBMIT_TIME
  716                 msg_info->info.date_sent = brutus_filetime_to_time_t(prop_values->_buffer[6].Value._u.ft);
  717             else
  718                 msg_info->info.date_sent = msg_info->info.date_received;
  719         }
  720 
  721         // Mailing list:
  722         msg_info->info.mlist = NULL;
  723         if (camel_header_raw) {
  724             tmp = camel_header_raw_check_mailing_list(&camel_header_raw);
  725             if (tmp) {
  726                 msg_info->info.mlist = camel_pstring_strdup(tmp);
  727                 g_free(tmp);
  728                 tmp = NULL;
  729             }
  730         }
  731 
  732         // References:
  733         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[9].ulPropTag)) // PR_INTERNET_REFERENCES
  734             refs = camel_header_references_decode(prop_values->_buffer[9].Value._u.lpszA);
  735         else if (camel_header_raw)
  736             refs = camel_header_references_decode(camel_header_raw_find(&camel_header_raw, "References", NULL));
  737         else
  738             refs = NULL;
  739         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[10].ulPropTag)) // PR_IN_REPLY_TO_ID
  740             irt = camel_header_references_inreplyto_decode(prop_values->_buffer[10].Value._u.lpszA);
  741         else if (camel_header_raw)
  742             irt = camel_header_references_inreplyto_decode(camel_header_raw_find(&camel_header_raw, "In-Reply-To", NULL));
  743         else
  744             irt = NULL;
  745         if (refs || irt) { // straight from camel-folder-summary.c
  746             if (irt) {
  747                 /* The References field is populated from the ``References'' and/or ``In-Reply-To''
  748                    headers. If both headers exist, take the first thing in the In-Reply-To header
  749                    that looks like a Message-ID, and append it to the References header. */
  750                 if (refs)
  751                     irt->next = refs;
  752 
  753                 refs = irt;
  754             }
  755 
  756             count = camel_header_references_list_size(&refs);
  757             msg_info->info.references = g_malloc(sizeof(*msg_info->info.references) + ((count-1) * sizeof(msg_info->info.references->references[0])));
  758             count = 0;
  759             scan = refs;
  760             while (scan) {
  761                 md5_get_digest(scan->id, strlen(scan->id), digest);
  762                 memcpy(msg_info->info.references->references[count].id.hash, digest, sizeof(msg_info->info.message_id.id.hash));
  763                 count++;
  764                 scan = scan->next;
  765             }
  766             msg_info->info.references->size = count;
  767             camel_header_references_list_clear(&refs);
  768         }
  769 
  770         // all is well
  771         errors = FALSE;
  772 
  773         goto next;
  774 
  775 #ifndef BRUTUS_SPY
  776     rollback:
  777         d("*************  ROLLBACK * ROLLBACK * ROLLBACK  **************");
  778 
  779         // msg_id msg_info->info.uid
  780         if (msg_id) {
  781             camel_folder_summary_remove_uid(folder->summary, msg_id);
  782             free(msg_id);
  783             msg_id = NULL;
  784         } else
  785             camel_folder_summary_remove_uid(folder->summary, camel_message_info_uid(&msg_info->info));
  786 #endif
  787     next:
  788         camel_header_raw_clear(&camel_header_raw);
  789 
  790         CORBA_free(eid);
  791         eid = NULL;
  792 
  793         CORBA_free(prop_values);
  794         prop_values = NULL;
  795 
  796         CORBA_free(recp_row_set);
  797         recp_row_set = NULL;
  798 
  799         if (!errors) {
  800             camel_folder_change_info_change_uid(changes, camel_message_info_uid(&msg_info->info));
  801             camel_message_info_free(&msg_info->info);  // unref
  802 
  803             if (changes && camel_folder_change_info_changed(changes)) {
  804                 camel_folder_summary_touch(folder->summary);
  805                 camel_folder_summary_save(folder->summary);
  806 
  807                 camel_object_trigger_event(folder, "folder_changed", changes);
  808             }
  809         }
  810         if (changes) {
  811             camel_folder_change_info_free(changes);
  812             changes = NULL;
  813         }
  814     }
  815     goto out;
  816 
  817 out_err:
  818     folder->summary->time = 0;
  819 
  820 out:
  821     CORBA_exception_free(ev);
  822 
  823     if (summary)
  824         camel_folder_free_summary(folder, summary);
  825 
  826     if (!aborted) {
  827         cbs = CAMEL_BRUTUS_SUMMARY(folder->summary);
  828         cbs->flags |= BRUTUS_FOLDER_SUMMARY_HAS_LONG_TERM_ENTRYIDS;
  829         if (((CamelOfflineFolder*)folder)->sync_offline)
  830             cbs->flags |= BRUTUS_FOLDER_SYNC_OFFLINE;
  831         else
  832             cbs->flags &= ~BRUTUS_FOLDER_SYNC_OFFLINE;
  833 
  834         camel_folder_summary_touch(folder->summary);
  835         camel_folder_summary_save(folder->summary);
  836     }
  837     if (changes) // aborted
  838         camel_folder_change_info_free(changes);
  839 
  840     BRUTUS_FOLDER_UNLOCK(brutus_folder, summary_mutex);
  841 
  842     folder_is_done(folder->full_name);
  843     camel_object_unref(CAMEL_OBJECT(folder));
  844 }
  845 
  846 /*
  847  * This function is only invoked if the summary count is 0 (zero).
  848  */
  849 static void
  850 brutus_update_folder_summary_light(CamelFolder *folder,
  851                    CamelException *ex)
  852 {
  853     struct _folder_data *folder_data = NULL;
  854     CamelBrutusFolder *brutus_folder = CAMEL_BRUTUS_FOLDER(folder);
  855     CamelBrutusSummary *cbs = NULL;
  856     CamelBrutusMessageInfo *msg_info = NULL;
  857     CamelFolderChangeInfo *changes = NULL;
  858     gboolean errors = TRUE;
  859     gboolean do_break = FALSE;
  860     char *msg_id = NULL;
  861     char *tmp = NULL;
  862     CORBA_long n = 0;
  863     CORBA_unsigned_long r = 0;
  864     CORBA_unsigned_long processed = 0;
  865     CORBA_unsigned_long row_count = 0;
  866     BRUTUS_BRESULT br = BRUTUS_BRUTUS_UNKNOWN_ERROR;
  867     BRUTUS_ENTRYID *eid = NULL;
  868     BRUTUS_IMAPITable content_table = CORBA_OBJECT_NIL;    // folder content
  869     BRUTUS_SRowSet *row_set = NULL;
  870     CORBA_Environment ev[1];
  871     static BRUTUS_BDEFINE content_props[11] = {            // for the contents table
  872         /* 0  */ BRUTUS_BRUTUS_PR_ENTRYID,                     // short-term entryid
  873         /* 1  */ BRUTUS_BRUTUS_PR_RECORD_KEY,                  // provider unique ID
  874         /* 2  */ BRUTUS_BRUTUS_PR_DISPLAY_TO,                  //
  875         /* 3  */ BRUTUS_BRUTUS_PR_SENDER_NAME,                 //
  876         /* 4  */ BRUTUS_BRUTUS_PR_SUBJECT,                     //
  877         /* 5  */ BRUTUS_BRUTUS_PR_MESSAGE_DELIVERY_TIME,       //
  878         /* 6  */ BRUTUS_BRUTUS_PR_MSG_STATUS,                  // message status
  879         /* 7  */ BRUTUS_BRUTUS_PR_MESSAGE_FLAGS,               //
  880         /* 8  */ BRUTUS_BRUTUS_PR_SENSITIVITY,                 //
  881         /* 9  */ BRUTUS_BRUTUS_PR_IMPORTANCE,                  //
  882         /* 10 */ BRUTUS_BRUTUS_PR_MESSAGE_SIZE,                //
  883     };
  884     static BRUTUS_SPropTagArray content_proptag_array = {  // for the contents table
  885         ._maximum = 11,
  886         ._length = 11,
  887         ._buffer = content_props,
  888     };
  889     static BRUTUS_SSortOrderSet sort_order = {             // for the contents table
  890         .cCategories = 0,
  891         .cExpanded = 0,
  892         .aSort._maximum = 0,
  893         .aSort._length = 0,
  894         .aSort._buffer = NULL,
  895     };
  896 
  897     CORBA_exception_init(ev);
  898 
  899     d(folder->full_name);
  900 
  901     camel_operation_start(NULL, _("Fetching summary information for %s"), folder->name);
  902     camel_operation_progress(NULL, 0);
  903 
  904     folder->summary->time = brutus_get_server_utc_time(brutus_folder->brutus_server,
  905                                brutus_folder->mapi_session,
  906                                ((CamelService*)folder->parent_store)->url->host);
  907 
  908     // get contents table
  909     br = BRUTUS_IMAPIFolder_GetContentsTable(brutus_folder->mapi_folder,
  910                          0,
  911                          &content_table,
  912                          ev);
  913     if (ORBIT2_EX(ev)) {
  914         PRINT_ORBIT2_EX(ev);
  915         goto out_err;
  916     }
  917     if (BRUTUS_BRUTUS_S_OK != br) {
  918         d(brutus_bresult_to_str(br));
  919         d("Possibly this error: http://support.microsoft.com/kb/176001/en-us");
  920         goto out_err;
  921     }
  922 
  923     br = BRUTUS_IMAPITable_GetRowCount(content_table,
  924                        0,
  925                        &row_count,
  926                        ev);
  927     if (ORBIT2_EX(ev)) {
  928         PRINT_ORBIT2_EX(ev);
  929         goto out_err;
  930     }
  931     if (BRUTUS_BRUTUS_S_OK != br) {
  932         d(brutus_bresult_to_str(br));
  933         goto out_err;
  934     }
  935     if (!row_count)
  936         goto out;
  937 
  938     br = brutus_PrepareTable(content_table,
  939                  &content_proptag_array,
  940                  CORBA_OBJECT_NIL,
  941                  &sort_order,
  942                  ev);
  943     if (ORBIT2_EX(ev)) {
  944         PRINT_ORBIT2_EX(ev);
  945         goto out_err;
  946     }
  947     if (BRUTUS_BRUTUS_S_OK != br) {
  948         d(brutus_bresult_to_str(br));
  949         goto out_err;
  950     }
  951 
  952     // iterate over content (columns)
  953     dfmt2("Number of messages to parse in \"%s\" = %llu", folder->full_name, (long long unsigned int)row_count);
  954     do {
  955         changes = camel_folder_change_info_new();
  956         if (!changes)
  957             goto out_err;
  958 
  959         br = brutus_QuerySomeRows(content_table,
  960                       (CORBA_long)BRUTUS_IMAPITABLE_ROW_COUNT_MAX,
  961                       &row_set,
  962                       ev);
  963         if (ORBIT2_EX(ev)) {
  964             PRINT_ORBIT2_EX(ev);
  965             goto out_err;
  966         }
  967         if (BRUTUS_BRUTUS_S_OK != br) {
  968             d(brutus_bresult_to_str(br));
  969             goto out_err;
  970         }
  971 
  972         for (r = 0; r < row_set->_length; r++) {
  973 
  974             // progress bar
  975             camel_operation_progress(NULL, (100*processed)/row_count);
  976             processed++;
  977 
  978             // to catch goto's
  979             errors = TRUE;
  980 
  981             // get short-term ENTRYID
  982             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_ENTRYID);
  983             if (-1 == n) {
  984                 d("No ENTRYID");
  985                 continue;
  986             }
  987             brutus_sbinary_to_entryid(&row_set->_buffer[r]._buffer[n].Value._u.bin, &eid);
  988             if (!eid)
  989                 continue;
  990 
  991             // create message id string
  992             msg_id = brutus_entryid_to_string(eid);
  993             CORBA_free(eid);
  994             eid = NULL;
  995             if (!msg_id)
  996                 goto next;
  997 
  998             // create message info object
  999             msg_info = (CamelBrutusMessageInfo*)camel_message_info_new(folder->summary);
 1000             msg_info->pr_record_key = NULL;
 1001 
 1002             // set id
 1003             msg_info->info.uid = g_strdup(msg_id);
 1004             free(msg_id);
 1005             if (!msg_info->info.uid)
 1006                 goto rollback;
 1007 
 1008             // set record_id
 1009             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_RECORD_KEY);
 1010             if (-1 != n)
 1011                 msg_info->pr_record_key = brutus_print_spropvalue(&row_set->_buffer[r]._buffer[n]);
 1012             else {
 1013                 d("No PR_RECORD_KEY");
 1014                 goto rollback;
 1015             }
 1016 
 1017             // Message flags
 1018             msg_info->info.flags = 0;
 1019             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_MSG_STATUS);
 1020             if (-1 != n) {
 1021                 if (BRUTUS_BRUTUS_MSGSTATUS_ANSWERED & row_set->_buffer[r]._buffer[n].Value._u.l)
 1022                     msg_info->info.flags |= CAMEL_MESSAGE_ANSWERED;
 1023 
 1024                 if (BRUTUS_BRUTUS_MSGSTATUS_DELMARKED & row_set->_buffer[r]._buffer[n].Value._u.l)
 1025                     msg_info->info.flags |= CAMEL_MESSAGE_DELETED;
 1026 
 1027                 if (BRUTUS_BRUTUS_MSGSTATUS_DRAFT & row_set->_buffer[r]._buffer[n].Value._u.l)
 1028                     msg_info->info.flags |= CAMEL_MESSAGE_DRAFT;
 1029 
 1030                 if (BRUTUS_BRUTUS_MSGSTATUS_HIGHLIGHTED & row_set->_buffer[r]._buffer[n].Value._u.l)
 1031                     msg_info->info.flags |= CAMEL_MESSAGE_FLAGGED;
 1032             }
 1033             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_MESSAGE_FLAGS);
 1034             if (-1 != n) {
 1035                 if (BRUTUS_BRUTUS_MSGFLAG_READ & row_set->_buffer[r]._buffer[n].Value._u.l)
 1036                     msg_info->info.flags |= CAMEL_MESSAGE_SEEN;
 1037 
 1038                 if (BRUTUS_BRUTUS_MSGFLAG_HASATTACH & row_set->_buffer[r]._buffer[n].Value._u.l)
 1039                     msg_info->info.flags |= CAMEL_MESSAGE_ATTACHMENTS;
 1040             }
 1041 
 1042             // Subject:
 1043             tmp = NULL;
 1044             msg_info->info.subject = NULL;
 1045             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_SUBJECT);
 1046             if (-1 != n)
 1047                 tmp = camel_header_decode_string(row_set->_buffer[r]._buffer[n].Value._u.lpszA, NULL);
 1048             if (tmp) {
 1049                 msg_info->info.subject = camel_pstring_strdup(tmp);
 1050                 g_free(tmp);
 1051                 tmp = NULL;
 1052             }
 1053 
 1054             /*
 1055              * Recipients. The recipient is BCC if neither "To:" nor "CC:" is present
 1056              * in the recipient table.
 1057              */
 1058 
 1059             // To:
 1060             tmp = NULL;
 1061             msg_info->info.to = NULL;
 1062             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_DISPLAY_TO);
 1063             if (-1 != n)
 1064                 tmp = camel_header_decode_string(row_set->_buffer[r]._buffer[n].Value._u.lpszA, NULL);
 1065             if (tmp) {
 1066                 msg_info->info.to = camel_pstring_strdup(tmp);
 1067                 g_free(tmp);
 1068                 tmp = NULL;
 1069             }
 1070 
 1071             // From:
 1072             tmp = NULL;
 1073             msg_info->info.from = NULL;
 1074             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_SENDER_NAME);
 1075             if (-1 != n)
 1076                 tmp = camel_header_decode_string(row_set->_buffer[r]._buffer[n].Value._u.lpszA, NULL);
 1077             if (tmp) {
 1078                 msg_info->info.from = camel_pstring_strdup(tmp);
 1079                 g_free(tmp);
 1080                 tmp = NULL;
 1081             }
 1082 
 1083             // Received/Sent:
 1084             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_MESSAGE_DELIVERY_TIME);
 1085             if (-1 != n) {
 1086                 msg_info->info.date_received = brutus_filetime_to_time_t(row_set->_buffer[r]._buffer[n].Value._u.ft);
 1087                 msg_info->info.date_sent = msg_info->info.date_received;
 1088             } else {
 1089                 msg_info->info.date_received = 0;
 1090                 msg_info->info.date_sent = 0;
 1091             }
 1092 
 1093             // Size:
 1094             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_MESSAGE_SIZE);
 1095             if (-1 != n)
 1096                 msg_info->info.size = row_set->_buffer[r]._buffer[n].Value._u.l;
 1097             else
 1098                 msg_info->info.size = 0;
 1099 
 1100             // all is well
 1101             errors = FALSE;
 1102             goto next;
 1103 
 1104         rollback:
 1105             d("*************  ROLLBACK * ROLLBACK * ROLLBACK  **************");
 1106 
 1107             camel_message_info_free(&msg_info->info);
 1108 
 1109         next:
 1110             if (!errors) {
 1111                 camel_folder_summary_add(folder->summary,(CamelMessageInfo*)msg_info);
 1112                 camel_folder_change_info_add_uid(changes, camel_message_info_uid(&msg_info->info));
 1113                 camel_folder_change_info_recent_uid(changes, camel_message_info_uid(&msg_info->info));
 1114             }
 1115 
 1116             errors = TRUE;
 1117         }
 1118 
 1119         if (!row_set->_length)
 1120             do_break = TRUE;
 1121 
 1122         CORBA_free(row_set);
 1123         row_set = NULL;
 1124 
 1125         camel_folder_summary_touch(folder->summary);
 1126         camel_folder_summary_save(folder->summary);
 1127 
 1128         if (changes && camel_folder_change_info_changed(changes))
 1129             camel_object_trigger_event(folder, "folder_changed", changes);
 1130         if (changes) {
 1131             camel_folder_change_info_free(changes);
 1132             changes = NULL;
 1133         }
 1134 
 1135         if (do_break)
 1136             break;
 1137     } while (TRUE);
 1138 
 1139     // now set the session key
 1140     cbs = CAMEL_BRUTUS_SUMMARY(folder->summary);
 1141     if (((CamelOfflineFolder*)folder)->sync_offline)
 1142         cbs->flags |= BRUTUS_FOLDER_SYNC_OFFLINE;
 1143     else
 1144         cbs->flags &= ~BRUTUS_FOLDER_SYNC_OFFLINE;
 1145     memcpy((void*)cbs->session_key, (const void*)brutus_folder->session_key, sizeof(cbs->session_key));
 1146     camel_folder_summary_touch(folder->summary);
 1147     camel_folder_summary_save(folder->summary);
 1148 
 1149     goto out;
 1150 
 1151 out_err:
 1152     folder->summary->time = 0;
 1153 
 1154     camel_exception_set(ex, CAMEL_EXCEPTION_SYSTEM,
 1155                 _("Could not update folder summary"));
 1156 out:
 1157     brutus_release_object(BRUTUS_IMAPITable_tc, &content_table, CORBA_OBJECT_NIL, ev);
 1158     PRINT_IF_ORBIT2_EX(ev);
 1159 
 1160     CORBA_exception_free(ev);
 1161 
 1162     // start the asynchronous summary update
 1163     if (row_count) {
 1164         folder_data = g_new0(struct _folder_data, 1);
 1165         if (!folder_data)
 1166             goto out_no_mem;
 1167         folder_data->full_name = g_strdup(folder->full_name);
 1168         if (!folder_data->full_name) {
 1169             g_free(folder_data);
 1170             goto out_no_mem;
 1171         }
 1172         folder_data->store = camel_folder_get_parent_store(folder);
 1173         camel_object_ref(CAMEL_OBJECT(folder_data->store));
 1174 
 1175         g_thread_pool_push(folder_summary_updates_thread_pool,
 1176                    (gpointer)folder_data,
 1177                    NULL);
 1178     }
 1179 
 1180 out_no_mem:
 1181     camel_operation_progress(NULL, 100);
 1182     camel_operation_end(NULL);
 1183 }
 1184 
 1185 void
 1186 brutus_update_folder_summary(CamelFolder *folder,
 1187                  gboolean force_update,
 1188                  CamelException *ex)
 1189 {
 1190     struct _folder_data *folder_data = NULL;
 1191     CamelBrutusFolder *brutus_folder = CAMEL_BRUTUS_FOLDER(folder);
 1192     CamelBrutusSummary *cbs = CAMEL_BRUTUS_SUMMARY(folder->summary);
 1193     CamelBrutusStore *brutus_store = CAMEL_BRUTUS_STORE(camel_folder_get_parent_store(folder));
 1194     CamelBrutusStorePrivate *priv = brutus_store->priv;
 1195     BrutusBaseClass *brutus_base = BRUTUS_BASE_CLASS(priv);
 1196     CamelBrutusMessageInfo *msg_info = NULL;
 1197     CamelFolderChangeInfo *changes = NULL;
 1198     time_t last_summary_update = 0;   // last time the folder summary was updated
 1199     time_t msg_modification_time = 1; // greater than last_summary_update to make sure that changes are caught during the first run
 1200     struct _camel_header_raw *camel_header_raw = NULL;
 1201     struct _camel_header_address *camel_addr_list = NULL;
 1202     struct _camel_header_address *camel_addr = NULL;
 1203     struct _camel_header_references *refs = NULL;
 1204     struct _camel_header_references *irt = NULL;
 1205     struct _camel_header_references *scan = NULL;
 1206     CamelContentType *ct = NULL;
 1207     const char *content = NULL;
 1208     const char *charset = NULL;
 1209     gboolean exists = FALSE;
 1210     gboolean errors = TRUE;
 1211     gboolean inbound = FALSE;
 1212     gboolean do_break = FALSE;
 1213     GPtrArray *seen_msg_infos = NULL; // PR_RECORD_KEY array of CamelBrutusMessageInfo with corresponding remote message object
 1214     GPtrArray *expunge_msg_infos = NULL; // message infos to be deleted due to missing corresponding remote message object
 1215     char *pr_record_key = NULL;
 1216     char *msg_id = NULL;
 1217     char *smtp_header = NULL;
 1218     char *tmp = NULL;
 1219     guchar digest[16] = { 0 };
 1220     int count = 0;
 1221     CORBA_boolean cb = CORBA_TRUE;
 1222     CORBA_long n = 0;
 1223     CORBA_unsigned_long r = 0;
 1224     CORBA_unsigned_long k = 0;
 1225     CORBA_unsigned_long processed = 0;
 1226     CORBA_unsigned_long row_count = 0;
 1227     BRUTUS_BRESULT br = BRUTUS_BRUTUS_UNKNOWN_ERROR;
 1228     BRUTUS_ENTRYID *eid = NULL;
 1229     BRUTUS_ENTRYID *sender_eid = NULL;
 1230     BRUTUS_IMAPITable content_table = CORBA_OBJECT_NIL; // folder content
 1231     BRUTUS_SRowSet *row_set = NULL;
 1232     BRUTUS_SRowSet *recp_row_set = NULL;
 1233     BRUTUS_SPropValue *pv = NULL;
 1234     BRUTUS_seq_SPropValue *prop_values = NULL;
 1235     BRUTUS_seq_SPropValue *ex_prop_values = NULL;
 1236     CORBA_Environment ev[1];
 1237     static BRUTUS_BDEFINE content_props[4] = {            // for the contents table
 1238         /* 0 */ BRUTUS_BRUTUS_PR_ENTRYID,                     // short-term entryid
 1239         /* 1 */ BRUTUS_BRUTUS_PR_MSG_STATUS,                  // message status
 1240         /* 2 */ BRUTUS_BRUTUS_PR_LOCAL_COMMIT_TIME,      // message modification time
 1241         /* 3 */ BRUTUS_BRUTUS_PR_RECORD_KEY,                  // provider unique ID
 1242     };
 1243     static BRUTUS_SPropTagArray content_proptag_array = { // for the contents table
 1244         ._maximum = 4,
 1245         ._length = 4,
 1246         ._buffer = content_props,
 1247     };
 1248     static BRUTUS_SSortOrderSet sort_order = {            // for the contents table
 1249         .cCategories = 0,
 1250         .cExpanded = 0,
 1251         .aSort._maximum = 0,
 1252         .aSort._length = 0,
 1253         .aSort._buffer = NULL,
 1254     };
 1255     static BRUTUS_BDEFINE recp_props[3] = {               // for an recipients table
 1256         /* 0 */ BRUTUS_BRUTUS_PR_RECIPIENT_TYPE,             // MAPI_TO, MAPI_CC, MAPI_BCC
 1257         /* 1 */ BRUTUS_BRUTUS_PR_EMAIL_ADDRESS,              // if not there use PR_DISPLAY_NAME
 1258         /* 2 */ BRUTUS_BRUTUS_PR_DISPLAY_NAME,               // display name, possibly email adress if recipient does not resolve in the Exchange address book
 1259     };
 1260     static BRUTUS_SPropTagArray recp_proptag_array = {    // for an recipients table
 1261         ._maximum = 3,
 1262         ._length = 3,
 1263         ._buffer = recp_props,
 1264     };
 1265     static BRUTUS_BDEFINE msg_props[20] = {               // for a message object
 1266         /* 0  */ BRUTUS_BRUTUS_PR_ENTRYID,                   // long-term entryid
 1267         /* 1  */ BRUTUS_BRUTUS_PR_OBJECT_TYPE,               // must be MAPI_MESSAGE
 1268         /* 2  */ BRUTUS_BRUTUS_PR_MESSAGE_FLAGS,             // flags
 1269         /* 3  */ BRUTUS_BRUTUS_PR_SUBJECT,                   // subject
 1270         /* 4  */ BRUTUS_BRUTUS_PR_DISPLAY_TO,                // display name of TO recipients
 1271         /* 5  */ BRUTUS_BRUTUS_PR_DISPLAY_CC,                // display name of CC recipients
 1272         /* 6  */ BRUTUS_BRUTUS_PR_SENDER_NAME,               // only display name of sender
 1273         /* 7  */ BRUTUS_BRUTUS_PR_SENDER_EMAIL_ADDRESS,      // email address of sender
 1274         /* 8  */ BRUTUS_BRUTUS_PR_TRANSPORT_MESSAGE_HEADERS, // smtp envelope of inbound messages
 1275         /* 9  */ BRUTUS_BRUTUS_PR_MESSAGE_DELIVERY_TIME,     // PT_SYSTIME - sent_time if sent, recieved_time if inbound
 1276         /* 10 */ BRUTUS_BRUTUS_PR_MESSAGE_SIZE,              // accumulated size of all properties on message
 1277         /* 11 */ BRUTUS_BRUTUS_PR_INTERNET_CPID,             // Equivalent to RFC 2822 "Content-Type".
 1278         /* 12 */ BRUTUS_BRUTUS_PR_SENDER_ADDRTYPE,           // MHS, PROFS, SMTP, X400 or EX
 1279         /* 13 */ BRUTUS_BRUTUS_PR_CLIENT_SUBMIT_TIME,        // Equivalent to RFC 2822 "Date:" when inbound
 1280         /* 14 */ BRUTUS_BRUTUS_PR_PROVIDER_SUBMIT_TIME,      // Equivalent to RFC 2822 "Date:" when outbound
 1281         /* 15 */ BRUTUS_BRUTUS_PR_INTERNET_MESSAGE_ID,       // Equivalent to RFC 2822 "Message-Id:"
 1282         /* 16 */ BRUTUS_BRUTUS_PR_INTERNET_REFERENCES,       // Equivalent to RFC 2822 "References:" (rarely seen)
 1283         /* 17 */ BRUTUS_BRUTUS_PR_IN_REPLY_TO_ID,            // Equivalent to RFC 2822 "In-Reply-To:"
 1284         /* 18 */ BRUTUS_BRUTUS_PR_RECEIVED_BY_ADDRTYPE,      // inbound if not found
 1285         /* 19 */ BRUTUS_BRUTUS_PR_SENDER_ENTRYID,            // open and get PR_SMTP_ADDRESS if PR_SENDER_ADDRTYPE==EX
 1286         /* 20 *//*  BRUTUS_BRUTUS_PR_, */
 1287     };
 1288     static BRUTUS_SPropTagArray msg_proptag_array = {     // for message object properties
 1289         ._maximum = 20,
 1290         ._length = 20,
 1291         ._buffer = msg_props,
 1292     };
 1293     static BRUTUS_SPropTagArray ex_msg_proptag_array = {     // for message object properties
 1294         ._maximum = 0,
 1295         ._length = 0,
 1296         ._buffer = NULL,
 1297     };
 1298 
 1299     if (!brutus_folder->is_a_folder)
 1300         return;
 1301 
 1302     if (!brutus_is_likely_connected(brutus_base)) {
 1303         camel_exception_set(ex,
 1304                     CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
 1305                     _("Not connected"));
 1306         return;
 1307     }
 1308 
 1309     CORBA_exception_init(ev);
 1310 
 1311     d(folder->full_name);
 1312 
 1313 #ifdef BRUTUS_SPY
 1314     force_update = TRUE;
 1315 #endif
 1316     /* _light() and regular updates are protected by the folder mutex.
 1317      * _post_light() are running with another folder object and are *NOT*
 1318      * protected by the folder mutex.
 1319      * We will therefore never get past this mutex if a _light() or a
 1320      * regular update is in progress. We can, OTOH, get past this if a
 1321      * _post_light() update is in progress.
 1322      */
 1323     BRUTUS_FOLDER_TRY_LOCK(brutus_folder, summary_mutex);
 1324 
 1325     /*
 1326      * OK, no _light() or another regular update is running so we are running
 1327      * a new regular update, intercepting a _post_light() update or is looking
 1328      * at this folder for the very first time.
 1329      */
 1330 
 1331     // we will not get past this if we the folder is being deleted or if
 1332     // a _post_light() update is in progress
 1333     if (folder_locked(folder->full_name))
 1334         goto out_unlock;
 1335 
 1336     /*
 1337      * Now we know that we are not intercepting a _post_light() update or a
 1338      * delete in progress.
 1339      */
 1340 
 1341     // seeing this folder for the first time?
 1342     if (0 >= camel_folder_get_message_count(folder)) {
 1343         brutus_update_folder_summary_light(folder, ex);
 1344         goto out_unlock;
 1345     }
 1346 
 1347     /*
 1348      * Determine if we should use the lightweight functions or
 1349      * if we can progress from here
 1350      */
 1351     if (!(cbs->flags & BRUTUS_FOLDER_SUMMARY_HAS_LONG_TERM_ENTRYIDS)) { // does the summary contain long-term entryids?
 1352         if (strcmp(cbs->session_key, brutus_folder->session_key)) { // the short-term entryids are *not* valid
 1353             camel_folder_summary_clear(folder->summary);
 1354             memset((void*)cbs->session_key, '\0', sizeof(cbs->session_key));
 1355             brutus_update_folder_summary_light(folder, ex);
 1356         } else { // the short-term entryids *are* valid
 1357             if (folder_summary_post_update_may_commence(folder->full_name)) {
 1358                 folder_data = g_new0(struct _folder_data, 1);
 1359                 if (!folder_data)
 1360                     goto out_unlock;
 1361                 folder_data->full_name = g_strdup(folder->full_name);
 1362                 if (!folder_data->full_name) {
 1363                     g_free(folder_data);
 1364                     goto out_unlock;
 1365                 }
 1366                 folder_data->store = camel_folder_get_parent_store(folder);
 1367                 camel_object_ref(CAMEL_OBJECT(folder_data->store));
 1368 
 1369                 g_thread_pool_push(folder_summary_updates_thread_pool,
 1370                            (gpointer)folder_data,
 1371                            NULL);
 1372             }
 1373         }
 1374         goto out_unlock;
 1375     }
 1376 
 1377     camel_operation_start(NULL, _("Fetching summary information for %s"), folder->name);
 1378     camel_operation_progress(NULL, 0);
 1379 
 1380     if (force_update) // using PR_LOCAL_COMMIT_TIME of content table to detect changes
 1381         last_summary_update = 0;
 1382     else
 1383         last_summary_update = folder->summary->time;
 1384     folder->summary->time = brutus_get_server_utc_time(brutus_folder->brutus_server,
 1385                                brutus_folder->mapi_session,
 1386                                ((CamelService*)folder->parent_store)->url->host);
 1387 
 1388     // get contents table
 1389     cb = CORBA_Object_is_nil((CORBA_Object)brutus_folder->mapi_folder, ev);
 1390     if (ORBIT2_EX(ev) || cb) {
 1391         PRINT_ORBIT2_EX(ev);
 1392         brutus_folder->mapi_folder = CORBA_OBJECT_NIL;
 1393         goto out_err;
 1394     }
 1395     br = BRUTUS_IMAPIFolder_GetContentsTable(brutus_folder->mapi_folder,
 1396                          0,
 1397                          &content_table,
 1398                          ev);
 1399     if (ORBIT2_EX(ev)) {
 1400         PRINT_ORBIT2_EX(ev);
 1401         goto out_err;
 1402     }
 1403     if (BRUTUS_BRUTUS_S_OK != br) {
 1404         d(brutus_bresult_to_str(br));
 1405         d("Possibly this error: http://support.microsoft.com/kb/176001/en-us");
 1406         goto out_err;
 1407     }
 1408 
 1409     br = BRUTUS_IMAPITable_GetRowCount(content_table,
 1410                        0,
 1411                        &row_count,
 1412                        ev);
 1413     if (ORBIT2_EX(ev)) {
 1414         PRINT_ORBIT2_EX(ev);
 1415         goto out_err;
 1416     }
 1417     if (BRUTUS_BRUTUS_S_OK != br) {
 1418         d(brutus_bresult_to_str(br));
 1419         goto out_err;
 1420     }
 1421     if (!row_count)
 1422         goto out_end_progress;
 1423 
 1424     br = brutus_PrepareTable(content_table,
 1425                  &content_proptag_array,
 1426                  CORBA_OBJECT_NIL,
 1427                  &sort_order,
 1428                  ev);
 1429     if (ORBIT2_EX(ev)) {
 1430         PRINT_ORBIT2_EX(ev);
 1431         goto out_err;
 1432     }
 1433     if (BRUTUS_BRUTUS_S_OK != br) {
 1434         d(brutus_bresult_to_str(br));
 1435         goto out_err;
 1436     }
 1437 
 1438     // for later use for figuring out if any messages has been deleted behind our back
 1439     seen_msg_infos = g_ptr_array_sized_new(row_count);
 1440     if (!seen_msg_infos)
 1441         goto out_err;
 1442 
 1443     // iterate over content (columns)
 1444     dfmt2("Number of messages to parse in \"%s\" = %llu", folder->full_name, (long long unsigned int)row_count);
 1445     do {
 1446         changes = camel_folder_change_info_new();
 1447         if (!changes)
 1448             goto out_err;
 1449 
 1450         br = brutus_QuerySomeRows(content_table,
 1451                       (CORBA_long)BRUTUS_IMAPITABLE_ROW_COUNT_MAX,
 1452                       &row_set,
 1453                       ev);
 1454         if (ORBIT2_EX(ev)) {
 1455             PRINT_ORBIT2_EX(ev);
 1456             goto out_err;
 1457         }
 1458         if (BRUTUS_BRUTUS_S_OK != br) {
 1459             d(brutus_bresult_to_str(br));
 1460             goto out_err;
 1461         }
 1462 
 1463         for (r = 0; r < row_set->_length; r++) {
 1464 
 1465             if (camel_operation_cancel_check(NULL)) {
 1466                 d("Canceled");
 1467                 camel_exception_set(ex,
 1468                             CAMEL_EXCEPTION_USER_CANCEL,
 1469                             _("Fetching folder summary information canceled"));
 1470                 goto canceled;
 1471             }
 1472 
 1473             if (!brutus_is_likely_connected(brutus_base)) {
 1474                 camel_exception_set(ex,
 1475                             CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
 1476                             _("Not connected"));
 1477                 goto disconnected;
 1478             }
 1479 
 1480             // progress bar
 1481             camel_operation_progress(NULL, (100*processed)/(2*row_count));
 1482             processed++;
 1483 
 1484             // to catch goto's
 1485             errors = TRUE;
 1486 
 1487             free(pr_record_key);
 1488             pr_record_key = NULL;
 1489 
 1490             // add to the array of pr_record_key for existing remote messages
 1491             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_RECORD_KEY);
 1492             if (-1 != n) {
 1493                 pr_record_key = brutus_print_spropvalue(&row_set->_buffer[r]._buffer[n]);
 1494                 g_ptr_array_add(seen_msg_infos, (gpointer)g_strdup(pr_record_key));
 1495             } else
 1496                 d("No PR_RECORD_KEY");
 1497 
 1498             // check whether the message has been modified since the last summary update. If force_update is TRUE this check is skipped
 1499             if (!force_update) {
 1500                 n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_LOCAL_COMMIT_TIME);
 1501                 if (-1 != n) {
 1502                     msg_modification_time = brutus_filetime_to_time_t(row_set->_buffer[r]._buffer[n].Value._u.ft);
 1503                     if (last_summary_update > msg_modification_time)
 1504                         continue;
 1505                 }
 1506             }
 1507 
 1508             // get short-term ENTRYID
 1509             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_ENTRYID);
 1510             if (-1 == n) {
 1511                 d("No ENTRYID");
 1512                 continue;
 1513             }
 1514             brutus_sbinary_to_entryid(&row_set->_buffer[r]._buffer[n].Value._u.bin, &eid);
 1515             if (!eid)
 1516                 continue;
 1517 
 1518             // get properties from message object
 1519             br = BRUTUS_IMAPISession_QueryMessage(brutus_folder->mapi_session,
 1520                                   eid,
 1521                                   &msg_proptag_array,
 1522                                   &ex_msg_proptag_array,
 1523                                   &recp_proptag_array,
 1524                                   &prop_values,
 1525                                   &ex_prop_values,
 1526                                   &recp_row_set,
 1527                                   ev);
 1528             CORBA_free(ex_prop_values); // we are not asking for any additional properties
 1529             ex_prop_values = NULL;
 1530             CORBA_free(eid);
 1531             eid = NULL;
 1532             if (ORBIT2_EX(ev)) {
 1533                 PRINT_ORBIT2_EX(ev);
 1534                 goto next;
 1535             }
 1536             if ((BRUTUS_BRUTUS_MAPI_W_ERRORS_RETURNED != br) && (BRUTUS_BRUTUS_S_OK != br)) {
 1537                 d(brutus_bresult_to_str(br));
 1538                 goto next;
 1539             }
 1540 
 1541             // inbound or outbound?
 1542             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[18].ulPropTag)) // PR_RECEIVED_BY_ADDRTYPE
 1543                 inbound = TRUE;
 1544             else
 1545                 inbound = FALSE; // draft, sent or being edited
 1546 
 1547             // get full SMTP header if present, alternatively check MSGFLAG_ORIGIN_INTERNET first
 1548             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[8].ulPropTag)) { // PR_TRANSPORT_MESSAGE_HEADERS
 1549                 smtp_header = brutus_unfold_rfc822_header(prop_values->_buffer[8].Value._u.lpszA);
 1550                 if (smtp_header) {
 1551                     camel_header_raw = brutus_get_camel_header_raw(smtp_header);
 1552                     free(smtp_header);
 1553                     smtp_header = NULL;
 1554                 } else
 1555                     goto next;
 1556             } else
 1557                 camel_header_raw = NULL;
 1558 
 1559             // get long-term ENTRYID
 1560             brutus_sbinary_to_entryid(&prop_values->_buffer[0].Value._u.bin, &eid);
 1561             if (!eid)
 1562                 goto next;
 1563 
 1564             msg_id = brutus_entryid_to_string(eid);
 1565             CORBA_free(eid);
 1566             eid = NULL;
 1567             if (!msg_id)
 1568                 goto next;
 1569 
 1570             // charset and content type
 1571             ct = NULL;
 1572             content = NULL;
 1573             charset = NULL;
 1574             if (camel_header_raw) {
 1575                 if ((content = camel_header_raw_find(&camel_header_raw, "Content-Type", NULL))
 1576                     && (ct = camel_content_type_decode(content))
 1577                     && (charset = camel_content_type_param(ct, "charset"))
 1578                     && (!g_ascii_strcasecmp(charset, "us-ascii")))
 1579                     charset = NULL;
 1580             } else {
 1581                 if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[11].ulPropTag)) // PR_INTERNET_CPID
 1582                     charset = brutus_cpid_to_label(prop_values->_buffer[11].Value._u.l);
 1583             }
 1584             charset = charset ? e_iconv_charset_name(charset) : NULL;
 1585             camel_content_type_unref(ct);
 1586 
 1587             /* get or create message info object */
 1588             msg_info = (CamelBrutusMessageInfo*)camel_folder_summary_uid(folder->summary, msg_id);
 1589             if (msg_info) {
 1590                 exists = TRUE;
 1591                 if (msg_info->pr_record_key)
 1592                     g_free(msg_info->pr_record_key);
 1593                 brutus_message_info_empty(folder->summary, &msg_info->info);
 1594             } else {
 1595                 exists = FALSE;
 1596                 msg_info = (CamelBrutusMessageInfo*)camel_message_info_new(folder->summary);
 1597             }
 1598             msg_info->pr_record_key = NULL;
 1599 
 1600             // Message flags
 1601             msg_info->info.flags = 0;
 1602             n = brutus_get_srow_index(&row_set->_buffer[r], BRUTUS_BRUTUS_PR_MSG_STATUS); // required column in folder content tables
 1603             if (-1 != n) {
 1604                 if (BRUTUS_BRUTUS_MSGSTATUS_ANSWERED & row_set->_buffer[r]._buffer[n].Value._u.l)
 1605                     msg_info->info.flags |= CAMEL_MESSAGE_ANSWERED;
 1606 
 1607                 if (BRUTUS_BRUTUS_MSGSTATUS_DELMARKED & row_set->_buffer[r]._buffer[n].Value._u.l)
 1608                     msg_info->info.flags |= CAMEL_MESSAGE_DELETED;
 1609 
 1610                 if (BRUTUS_BRUTUS_MSGSTATUS_DRAFT & row_set->_buffer[r]._buffer[n].Value._u.l)
 1611                     msg_info->info.flags |= CAMEL_MESSAGE_DRAFT;
 1612 
 1613                 if (BRUTUS_BRUTUS_MSGSTATUS_HIGHLIGHTED & row_set->_buffer[r]._buffer[n].Value._u.l)
 1614                     msg_info->info.flags |= CAMEL_MESSAGE_FLAGGED;
 1615             }
 1616             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[2].ulPropTag)) { // PR_MESSAGE_FLAGS
 1617                 if (BRUTUS_BRUTUS_MSGFLAG_READ & prop_values->_buffer[2].Value._u.l)
 1618                     msg_info->info.flags |= CAMEL_MESSAGE_SEEN;
 1619 
 1620                 if (BRUTUS_BRUTUS_MSGFLAG_HASATTACH & prop_values->_buffer[2].Value._u.l)
 1621                     msg_info->info.flags |= CAMEL_MESSAGE_ATTACHMENTS;
 1622             }
 1623 
 1624             msg_info->info.uid = g_strdup(msg_id);
 1625             if (!msg_info->info.uid)
 1626                 goto rollback;
 1627             free(msg_id);
 1628             msg_id = NULL;
 1629 
 1630             // PR_RECORD_KEY
 1631             msg_info->pr_record_key = g_strdup(pr_record_key);
 1632             free(pr_record_key);
 1633             pr_record_key = NULL;
 1634 
 1635             // Message-Id:
 1636             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[15].ulPropTag)) // PR_INTERNET_MESSAGE_ID
 1637                 msg_id = camel_header_msgid_decode(prop_values->_buffer[15].Value._u.lpszA);
 1638             else if (camel_header_raw)
 1639                 msg_id = camel_header_msgid_decode(camel_header_raw_find(&camel_header_raw, "Message-Id", NULL));
 1640             else {
 1641                 d("Invalid RFC 822 message header");
 1642 #ifndef BRUTUS_SPY
 1643                 goto rollback;
 1644 #endif
 1645             }
 1646             if (!msg_id) {
 1647                 d("No memory or invalid RFC 822 message header");
 1648 #ifdef BRUTUS_SPY
 1649                 memset(&msg_info->info.message_id, 0, sizeof(CamelSummaryMessageID));
 1650 #else
 1651                 goto rollback;
 1652 #endif
 1653             } else {
 1654                 md5_get_digest(msg_id, strlen(msg_id), digest);
 1655                 memcpy(msg_info->info.message_id.id.hash, digest, sizeof(msg_info->info.message_id.id.hash));
 1656                 g_free(msg_id);
 1657                 msg_id = NULL;
 1658             }
 1659 
 1660             // Subject:
 1661             tmp = NULL;
 1662             msg_info->info.subject = NULL;
 1663             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[3].ulPropTag))
 1664                 tmp = camel_header_decode_string(prop_values->_buffer[3].Value._u.lpszA, charset);
 1665             else if (camel_header_raw)
 1666                 tmp = brutus_camel_summary_format_string(camel_header_raw, "Subject", charset);
 1667             if (tmp) {
 1668                 msg_info->info.subject = camel_pstring_strdup(tmp);
 1669                 g_free(tmp);
 1670                 tmp = NULL;
 1671             }
 1672 
 1673             /*
 1674              * Recipients. The recipient is BCC if neither "To:" nor "CC:" is present
 1675              * in the recipient table.
 1676              */
 1677 
 1678             // To:
 1679             camel_header_address_list_clear(&camel_addr_list);
 1680             msg_info->info.to = NULL;
 1681             if (camel_header_raw) {
 1682                 tmp = brutus_camel_summary_format_address(camel_header_raw, "To", charset);
 1683             } else if ((recp_row_set->_length) && (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(recp_row_set->_buffer[0]._buffer[0].ulPropTag))) { // we don't know if STORE_SUBMIT_OK is set
 1684                 for (k = 0; k<recp_row_set->_length; k++) { // loop all recipients
 1685                     if (BRUTUS_BRUTUS_MAPI_TO & recp_row_set->_buffer[k]._buffer[0].Value._u.l) {
 1686                         n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_EMAIL_ADDRESS);
 1687                         if (-1 == n) // no PR_EMAIL_ADDRESS
 1688                             n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_DISPLAY_NAME);
 1689 
 1690                         camel_addr = camel_header_address_decode(recp_row_set->_buffer[k]._buffer[n].Value._u.lpszA, charset);
 1691                         camel_header_address_list_append(&camel_addr_list, camel_addr);
 1692                     }
 1693                 }
 1694                 if (camel_addr_list) {
 1695                     tmp = camel_header_address_list_format(camel_addr_list);
 1696                     camel_header_address_list_clear(&camel_addr_list);
 1697                 }
 1698             }
 1699             if (tmp) {
 1700                 msg_info->info.to = camel_pstring_strdup(tmp);
 1701                 g_free(tmp);
 1702                 tmp = NULL;
 1703             }
 1704 
 1705             // CC:
 1706             camel_header_address_list_clear(&camel_addr_list);
 1707             msg_info->info.cc = NULL;
 1708             if (camel_header_raw) {
 1709                 tmp = brutus_camel_summary_format_address(camel_header_raw, "CC", charset);
 1710             } else if ((recp_row_set->_length) && (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(recp_row_set->_buffer[0]._buffer[0].ulPropTag))) { // we don't know if STORE_SUBMIT_OK is set
 1711                 for (k = 0; k<recp_row_set->_length; k++) { // loop all recipients
 1712                     if (BRUTUS_BRUTUS_MAPI_CC & recp_row_set->_buffer[k]._buffer[0].Value._u.l) {
 1713                         n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_EMAIL_ADDRESS);
 1714                         if (-1 == n) // no PR_EMAIL_ADDRESS
 1715                             n = brutus_get_srow_index(&recp_row_set->_buffer[k], BRUTUS_BRUTUS_PR_DISPLAY_NAME);
 1716 
 1717                         camel_addr = camel_header_address_decode(recp_row_set->_buffer[k]._buffer[n].Value._u.lpszA, charset);
 1718                         camel_header_address_list_append(&camel_addr_list, camel_addr);
 1719                     }
 1720                 }
 1721                 if (camel_addr_list) {
 1722                     tmp = camel_header_address_list_format(camel_addr_list);
 1723                     camel_header_address_list_clear(&camel_addr_list);
 1724                 }
 1725             }
 1726             if (tmp) {
 1727                 msg_info->info.to = camel_pstring_strdup(tmp);
 1728                 g_free(tmp);
 1729                 tmp = NULL;
 1730             }
 1731 
 1732             // From:
 1733             camel_header_address_list_clear(&camel_addr_list);
 1734             msg_info->info.from = NULL;
 1735             if (camel_header_raw) {
 1736                 tmp = brutus_camel_summary_format_address(camel_header_raw, "From", charset);
 1737             } else { // check for sender addrtype: SMTP=>Get SENDER_EMAIL_ADDRESS. EX=>Open sender and get PR_SMTP_ADDRESS.
 1738                 if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[12].ulPropTag)) { // PR_SENDER_ADDRTYPE
 1739                     if (!g_ascii_strcasecmp("SMTP", prop_values->_buffer[12].Value._u.lpszA)) {
 1740                         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[7].ulPropTag)) { // PR_SENDER_EMAIL_ADDRESS
 1741                             camel_addr_list = camel_header_address_decode(prop_values->_buffer[7].Value._u.lpszA, charset);
 1742                             tmp = camel_header_address_list_format(camel_addr_list);
 1743                             camel_header_address_list_clear(&camel_addr_list);
 1744                         } else if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[6].ulPropTag)) { // PR_SENDER_NAME
 1745                             tmp = camel_header_decode_string(prop_values->_buffer[6].Value._u.lpszA, charset);
 1746                         }
 1747                     } else if (!g_ascii_strcasecmp("EX", prop_values->_buffer[12].Value._u.lpszA)) {
 1748                         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[19].ulPropTag)) { // PR_SENDER_ENTRYID
 1749                             brutus_sbinary_to_entryid(&prop_values->_buffer[19].Value._u.bin, &sender_eid);
 1750                             if (sender_eid) {
 1751                                 pv = brutus_open_object_get_one_prop(brutus_folder->mapi_session,
 1752                                                      CORBA_OBJECT_NIL,
 1753                                                      sender_eid,
 1754                                                      BRUTUS_BRUTUS_PR_SMTP_ADDRESS);
 1755                                 if ((pv) && (BRUTUS_BRUTUS_PR_SMTP_ADDRESS == pv->ulPropTag)) {
 1756                                     camel_addr_list = camel_header_address_decode(pv->Value._u.lpszA, charset);
 1757                                     tmp = camel_header_address_list_format(camel_addr_list);
 1758                                     camel_header_address_list_clear(&camel_addr_list);
 1759                                 } else  if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[6].ulPropTag)) { // PR_SENDER_NAME
 1760                                     tmp = camel_header_decode_string(prop_values->_buffer[6].Value._u.lpszA, charset);
 1761                                 }
 1762                                 CORBA_free(pv);
 1763                                 pv = NULL;
 1764                                 CORBA_free(sender_eid);
 1765                                 sender_eid = NULL;
 1766                             } else if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[6].ulPropTag)) { // PR_SENDER_NAME
 1767                                 tmp = camel_header_decode_string(prop_values->_buffer[6].Value._u.lpszA, charset);
 1768                             }
 1769                         }
 1770                     } else { // for all other address types than SMTP or EX use the sender name
 1771                         if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[6].ulPropTag)) { // PR_SENDER_NAME
 1772                             tmp = camel_header_decode_string(prop_values->_buffer[6].Value._u.lpszA, charset);
 1773                         }
 1774                     }
 1775                 } else { // unknown address type
 1776                     if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[7].ulPropTag)) { // PR_SENDER_EMAIL_ADDRESS
 1777                         camel_addr_list = camel_header_address_decode(prop_values->_buffer[7].Value._u.lpszA, charset);
 1778                         tmp = camel_header_address_list_format(camel_addr_list);
 1779                         camel_header_address_list_clear(&camel_addr_list);
 1780                     } else if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[6].ulPropTag)) { // PR_SENDER_NAME
 1781                         tmp = camel_header_decode_string(prop_values->_buffer[6].Value._u.lpszA, charset);
 1782                     }
 1783                 }
 1784             }
 1785             if (tmp) {
 1786                 msg_info->info.from = camel_pstring_strdup(tmp);
 1787                 g_free(tmp);
 1788                 tmp = NULL;
 1789             }
 1790 
 1791             // Received/Sent:
 1792             if (inbound) {
 1793                 if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[9].ulPropTag)) // PR_MESSAGE_DELIVERY_TIME
 1794                     msg_info->info.date_received = brutus_filetime_to_time_t(prop_values->_buffer[9].Value._u.ft);
 1795                 else
 1796                     msg_info->info.date_received = 0;
 1797 
 1798                 if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[13].ulPropTag)) // PR_CLIENT_SUBMIT_TIME
 1799                     msg_info->info.date_sent = brutus_filetime_to_time_t(prop_values->_buffer[13].Value._u.ft);
 1800                 else if (camel_header_raw)
 1801                     msg_info->info.date_sent = camel_header_decode_date(camel_header_raw_find(&camel_header_raw, "Date", NULL), NULL);
 1802                 else
 1803                     msg_info->info.date_sent = 0;
 1804             } else {
 1805                 if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[9].ulPropTag)) // PR_MESSAGE_DELIVERY_TIME
 1806                     msg_info->info.date_received = brutus_filetime_to_time_t(prop_values->_buffer[9].Value._u.ft);
 1807                 else
 1808                     msg_info->info.date_received = 0;
 1809 
 1810                 if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[14].ulPropTag))        // PR_PROVIDER_SUBMIT_TIME
 1811                     msg_info->info.date_sent = brutus_filetime_to_time_t(prop_values->_buffer[14].Value._u.ft);
 1812                 else if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[13].ulPropTag))   // PR_CLIENT_SUBMIT_TIME
 1813                     msg_info->info.date_sent = brutus_filetime_to_time_t(prop_values->_buffer[13].Value._u.ft);
 1814                 else if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[9].ulPropTag))    // PR_MESSAGE_DELIVERY_TIME
 1815                     msg_info->info.date_sent = brutus_filetime_to_time_t(prop_values->_buffer[9].Value._u.ft);
 1816                 else
 1817                     msg_info->info.date_sent = 0;
 1818             }
 1819 
 1820             // Size:
 1821             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[10].ulPropTag)) // PR_MESSAGE_SIZE
 1822                 msg_info->info.size = prop_values->_buffer[10].Value._u.l;
 1823             else
 1824                 msg_info->info.size = 0;
 1825 
 1826             // Mailing list:
 1827             msg_info->info.mlist = NULL;
 1828             if (camel_header_raw) {
 1829                 tmp = camel_header_raw_check_mailing_list(&camel_header_raw);
 1830                 if (tmp) {
 1831                     msg_info->info.mlist = camel_pstring_strdup(tmp);
 1832                     g_free(tmp);
 1833                     tmp = NULL;
 1834                 }
 1835             }
 1836 
 1837             // References:
 1838             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[16].ulPropTag)) // PR_INTERNET_REFERENCES
 1839                 refs = camel_header_references_decode(prop_values->_buffer[16].Value._u.lpszA);
 1840             else if (camel_header_raw)
 1841                 refs = camel_header_references_decode(camel_header_raw_find(&camel_header_raw, "References", NULL));
 1842             else
 1843                 refs = NULL;
 1844             if (BRUTUS_BRUTUS_PT_ERROR != BRUTUS_PROP_TYPE(prop_values->_buffer[17].ulPropTag)) // PR_IN_REPLY_TO_ID
 1845                 irt = camel_header_references_inreplyto_decode(prop_values->_buffer[17].Value._u.lpszA);
 1846             else if (camel_header_raw)
 1847                 irt = camel_header_references_inreplyto_decode(camel_header_raw_find(&camel_header_raw, "In-Reply-To", NULL));
 1848             else
 1849                 irt = NULL;
 1850             if (refs || irt) { // straight from camel-folder-summary.c
 1851                 if (irt) {
 1852                     /* The References field is populated from the ``References'' and/or ``In-Reply-To''
 1853                        headers. If both headers exist, take the first thing in the In-Reply-To header
 1854                        that looks like a Message-ID, and append it to the References header. */
 1855                     if (refs)
 1856                         irt->next = refs;
 1857 
 1858                     refs = irt;
 1859                 }
 1860 
 1861                 count = camel_header_references_list_size(&refs);
 1862                 msg_info->info.references = g_malloc(sizeof(*msg_info->info.references) + ((count-1) * sizeof(msg_info->info.references->references[0])));
 1863                 count = 0;
 1864                 scan = refs;
 1865                 while (scan) {
 1866                     md5_get_digest(scan->id, strlen(scan->id), digest);
 1867                     memcpy(msg_info->info.references->references[count].id.hash, digest, sizeof(msg_info->info.message_id.id.hash));
 1868                     count++;
 1869                     scan = scan->next;
 1870                 }
 1871                 msg_info->info.references->size = count;
 1872                 camel_header_references_list_clear(&refs);
 1873             }
 1874 
 1875             // all is well
 1876             errors = FALSE;
 1877 
 1878             goto next;
 1879 
 1880         rollback:
 1881             d("*************  ROLLBACK * ROLLBACK * ROLLBACK  **************");
 1882 
 1883             // msg_id msg_info->info.uid
 1884             if (!exists) {
 1885                 camel_message_info_free(&msg_info->info);
 1886             } else {
 1887                 if (msg_id) {
 1888                     camel_folder_summary_remove_uid(folder->summary, msg_id);
 1889                     free(msg_id);
 1890                     msg_id = NULL;
 1891                 } else
 1892                     camel_folder_summary_remove_uid(folder->summary, camel_message_info_uid(&msg_info->info));
 1893             }
 1894         next:
 1895             camel_header_raw_clear(&camel_header_raw);
 1896 
 1897             CORBA_free(eid);
 1898             eid = NULL;
 1899 
 1900             CORBA_free(prop_values);
 1901             prop_values = NULL;
 1902 
 1903             CORBA_free(recp_row_set);
 1904             recp_row_set = NULL;
 1905 
 1906             if (!errors) {
 1907                 if (exists) {
 1908                     camel_folder_change_info_change_uid(changes, camel_message_info_uid(&msg_info->info));
 1909                     camel_message_info_free(&msg_info->info);  // unref
 1910                 } else { // don't unref here
 1911                     camel_folder_summary_add(folder->summary,(CamelMessageInfo*)msg_info);
 1912                     camel_folder_change_info_add_uid(changes, camel_message_info_uid(&msg_info->info));
 1913                     camel_folder_change_info_recent_uid(changes, camel_message_info_uid(&msg_info->info));
 1914                 }
 1915             }
 1916         }
 1917 
 1918         if (!row_set->_length)
 1919             do_break = TRUE;
 1920 
 1921         CORBA_free(row_set);
 1922         row_set = NULL;
 1923 
 1924         // report the additions and modifications
 1925         camel_folder_summary_touch(folder->summary);
 1926         camel_folder_summary_save(folder->summary);
 1927         if (changes && camel_folder_change_info_changed(changes))
 1928             camel_object_trigger_event(folder, "folder_changed", changes);
 1929         if (changes) {
 1930             camel_folder_change_info_free(changes);
 1931             changes = NULL;
 1932         }
 1933 
 1934         if (do_break)
 1935             break;
 1936     } while (TRUE);
 1937 
 1938     // from an early loop exit
 1939     free(pr_record_key);
 1940     pr_record_key = NULL;
 1941 
 1942     // cleanup for deleted or moved message objects
 1943     expunge_msg_infos = g_ptr_array_sized_new(0);
 1944     if (!expunge_msg_infos)
 1945         goto out_err;
 1946 
 1947 #if (EDS_EPOCH >= 224)
 1948     for (k = 0; k < folder->summary->uids->len; k++) {
 1949 
 1950         // progress bar
 1951         camel_operation_progress(NULL, (100*(processed+k))/(2*row_count));
 1952 
 1953         exists = FALSE;
 1954         msg_info = (CamelBrutusMessageInfo*)g_hash_table_lookup(folder->summary->loaded_infos, g_ptr_array_index(folder->summary->uids, k));
 1955         for (r = 0; r < seen_msg_infos->len; r++) { // compare by pr_record_key
 1956             if (!g_ascii_strcasecmp((gchar*)g_ptr_array_index(seen_msg_infos, r), msg_info->pr_record_key)) {
 1957                 exists = TRUE;
 1958                 break;
 1959             }
 1960         }
 1961         if (!exists) // there is no remote corresponding message object for this info and it must be deleted by uid
 1962             g_ptr_array_add(expunge_msg_infos, g_ptr_array_index(folder->summary->uids, k));
 1963     }
 1964 #else
 1965     for (k = 0; k < folder->summary->messages->len; k++) {
 1966 
 1967         // progress bar
 1968         camel_operation_progress(NULL, (100*(processed+k))/(2*row_count));
 1969 
 1970         exists = FALSE;
 1971         msg_info = ((CamelBrutusMessageInfo*)g_ptr_array_index(folder->summary->messages, k));
 1972         for (r = 0; r < seen_msg_infos->len; r++) { // compare by pr_record_key
 1973             if (!g_ascii_strcasecmp((gchar*)g_ptr_array_index(seen_msg_infos, r), msg_info->pr_record_key)) {
 1974                 exists = TRUE;
 1975                 break;
 1976             }
 1977         }
 1978         if (!exists) // there is no remote corresponding message object for this info and it must be deleted by uid
 1979             g_ptr_array_add(expunge_msg_infos, (gpointer)camel_message_info_uid(&((CamelBrutusMessageInfo*)g_ptr_array_index(folder->summary->messages, k))->info));
 1980     }
 1981 #endif
 1982     for (r = 0; r < expunge_msg_infos->len; r++) {
 1983         msg_id = g_ptr_array_index(expunge_msg_infos, r);
 1984         if (!msg_id) {
 1985             d("ghost uid");
 1986             continue;
 1987         }
 1988         camel_folder_change_info_remove_uid(changes, (const char*)msg_id);
 1989         camel_folder_summary_remove_uid(folder->summary, (const char*)msg_id);
 1990     }
 1991     msg_id = NULL;
 1992 
 1993     // now set the session key
 1994     cbs = CAMEL_BRUTUS_SUMMARY(folder->summary);
 1995     if (((CamelOfflineFolder*)folder)->sync_offline)
 1996         cbs->flags |= BRUTUS_FOLDER_SYNC_OFFLINE;
 1997     else
 1998         cbs->flags &= ~BRUTUS_FOLDER_SYNC_OFFLINE;
 1999     memcpy((void*)cbs->session_key, (const void*)brutus_folder->session_key, sizeof(cbs->session_key));
 2000     camel_folder_summary_touch(folder->summary);
 2001     camel_folder_summary_save(folder->summary);
 2002 
 2003     // report the deletions
 2004     if (changes && camel_folder_change_info_changed(changes))
 2005         camel_object_trigger_event(folder, "folder_changed", changes);
 2006     if (changes) {
 2007         camel_folder_change_info_free(changes);
 2008         changes = NULL;
 2009     }
 2010 
 2011     goto out_end_progress;
 2012 
 2013 out_err:
 2014     camel_exception_set(ex, CAMEL_EXCEPTION_SYSTEM,
 2015                 _("Could not update folder summary"));
 2016 canceled:
 2017 disconnected:
 2018     folder->summary->time = last_summary_update;
 2019 
 2020 out_end_progress:
 2021     camel_operation_progress(NULL, 100);
 2022     camel_operation_end(NULL);
 2023 
 2024 out_unlock:
 2025     BRUTUS_FOLDER_UNLOCK(brutus_folder, summary_mutex);
 2026 out:
 2027     brutus_release_object(BRUTUS_IMAPITable_tc, &content_table, CORBA_OBJECT_NIL, ev);
 2028     PRINT_IF_ORBIT2_EX(ev);
 2029 
 2030     CORBA_exception_free(ev);
 2031 
 2032     if (seen_msg_infos) {
 2033         g_ptr_array_foreach(seen_msg_infos, brutus_for_each_g_free, NULL);
 2034         g_ptr_array_free(seen_msg_infos, TRUE);
 2035     }
 2036 
 2037     if (expunge_msg_infos)
 2038         g_ptr_array_free(expunge_msg_infos, TRUE);
 2039 }
 2040 
 2041 CamelType
 2042 camel_brutus_summary_get_type (void)
 2043 {
 2044     static CamelType type = CAMEL_INVALID_TYPE;
 2045 
 2046     if (type == CAMEL_INVALID_TYPE) {
 2047         type = camel_type_register(
 2048             camel_folder_summary_get_type(),
 2049             "CamelBrutusSummary",
 2050             sizeof(CamelBrutusSummary),
 2051             sizeof(CamelBrutusSummaryClass),
 2052             (CamelObjectClassInitFunc)camel_brutus_summary_class_init,
 2053             NULL,
 2054             (CamelObjectInitFunc)camel_brutus_summary_init,
 2055             NULL);
 2056     }
 2057 
 2058     return type;
 2059 }