Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / providers / groupwise / camel-groupwise-utils.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* camel-groupwise-utils.c
3  *
4  * Copyright (C) 2001 Ximian, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29
30 #include <glib.h>
31 #include <glib/gstdio.h>
32
33 #include <libsoup/soup-misc.h>
34
35 #include "camel/camel-address.h"
36 #include "camel/camel-mime-filter-charset.h"
37 #include "camel/camel-mime-message.h"
38 #include "camel/camel-multipart.h"
39 #include "camel/camel-service.h"
40 #include "camel/camel-stream-filter.h"
41 #include "camel/camel-stream-mem.h"
42
43 #include "camel-groupwise-utils.h"
44
45 #define SUBFOLDER_DIR_NAME     "subfolders"
46 #define SUBFOLDER_DIR_NAME_LEN 10
47 #define RFC_822 "message/rfc822"
48
49 static void do_multipart (EGwConnection *cnc, EGwItem *item, CamelMultipart *mp, GSList **attach_list);
50 /**
51  * e_path_to_physical:
52  * @prefix: a prefix to prepend to the path, or %NULL
53  * @path: the virtual path to convert to a filesystem path.
54  *
55  * This converts the "virtual" path @path into an expanded form that
56  * allows a given name to refer to both a file and a directory. The
57  * expanded path will have a "subfolders" directory inserted between
58  * each path component. If the path ends with "/", the returned
59  * physical path will end with "/subfolders"
60  *
61  * If @prefix is non-%NULL, it will be prepended to the returned path.
62  *
63  * Return value: the expanded path
64  **/
65 char *
66 e_path_to_physical (const char *prefix, const char *vpath)
67 {
68         const char *p, *newp;
69         char *dp;
70         char *ppath;
71         int ppath_len;
72         int prefix_len;
73
74         while (*vpath == '/')
75                 vpath++;
76         if (!prefix)
77                 prefix = "";
78
79         /* Calculate the length of the real path. */
80         ppath_len = strlen (vpath);
81         ppath_len++;    /* For the ending zero.  */
82
83         prefix_len = strlen (prefix);
84         ppath_len += prefix_len;
85         ppath_len++;    /* For the separating slash.  */
86
87         /* Take account of the fact that we need to translate every
88          * separator into `subfolders/'.
89          */
90         p = vpath;
91         while (1) {
92                 newp = strchr (p, '/');
93                 if (newp == NULL)
94                         break;
95
96                 ppath_len += SUBFOLDER_DIR_NAME_LEN;
97                 ppath_len++; /* For the separating slash.  */
98
99                 /* Skip consecutive slashes.  */
100                 while (*newp == '/')
101                         newp++;
102
103                 p = newp;
104         };
105
106         ppath = g_malloc (ppath_len);
107         dp = ppath;
108
109         memcpy (dp, prefix, prefix_len);
110         dp += prefix_len;
111         *(dp++) = '/';
112
113         /* Copy the mangled path.  */
114         p = vpath;
115         while (1) {
116                 newp = strchr (p, '/');
117                 if (newp == NULL) {
118                         strcpy (dp, p);
119                         break;
120                 }
121
122                 memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too.  */
123                 dp += newp - p + 1;
124
125                 memcpy (dp, SUBFOLDER_DIR_NAME, SUBFOLDER_DIR_NAME_LEN);
126                 dp += SUBFOLDER_DIR_NAME_LEN;
127
128                 *(dp++) = '/';
129
130                 /* Skip consecutive slashes.  */
131                 while (*newp == '/')
132                         newp++;
133
134                 p = newp;
135         }
136
137         return ppath;
138 }
139
140
141 static gboolean
142 find_folders_recursive (const char *physical_path, const char *path,
143                         EPathFindFoldersCallback callback, gpointer data)
144 {
145         GDir *dir;
146         char *subfolder_directory_path;
147         gboolean ok;
148
149         if (*path) {
150                 if (!callback (physical_path, path, data))
151                         return FALSE;
152
153                 subfolder_directory_path = g_strdup_printf ("%s/%s", physical_path, SUBFOLDER_DIR_NAME);
154         } else {
155                 /* On the top level, we have no folders and,
156                  * consequently, no subfolder directory.
157                  */
158
159                 subfolder_directory_path = g_strdup (physical_path);
160         }
161
162         /* Now scan the subfolders and load them. */
163         dir = g_dir_open (subfolder_directory_path, 0, NULL);
164         if (dir == NULL) {
165                 g_free (subfolder_directory_path);
166                 return TRUE;
167         }
168
169         ok = TRUE;
170         while (ok) {
171                 struct stat file_stat;
172                 const char *dirent;
173                 char *file_path;
174                 char *new_path;
175
176                 dirent = g_dir_read_name (dir);
177                 if (dirent == NULL)
178                         break;
179
180                 file_path = g_strdup_printf ("%s/%s", subfolder_directory_path, dirent);
181
182                 if (g_stat (file_path, &file_stat) < 0 ||
183                     ! S_ISDIR (file_stat.st_mode)) {
184                         g_free (file_path);
185                         continue;
186                 }
187
188                 new_path = g_strdup_printf ("%s/%s", path, dirent);
189
190                 ok = find_folders_recursive (file_path, new_path, callback, data);
191
192                 g_free (file_path);
193                 g_free (new_path);
194         }
195
196         g_dir_close (dir);
197         g_free (subfolder_directory_path);
198
199         return ok;
200 }
201
202 /**
203  * e_path_find_folders:
204  * @prefix: directory to start from
205  * @callback: Callback to invoke on each folder
206  * @data: Data for @callback
207  *
208  * Walks the folder tree starting at @prefix and calls @callback
209  * on each folder.
210  *
211  * Return value: %TRUE on success, %FALSE if an error occurs at any point
212  **/
213 gboolean
214 e_path_find_folders (const char *prefix,
215                      EPathFindFoldersCallback callback,
216                      gpointer data)
217 {
218         return find_folders_recursive (prefix, "", callback, data);
219 }
220
221
222 /**
223  * e_path_rmdir:
224  * @prefix: a prefix to prepend to the path, or %NULL
225  * @path: the virtual path to convert to a filesystem path.
226  *
227  * This removes the directory pointed to by @prefix and @path
228  * and attempts to remove its parent "subfolders" directory too
229  * if it's empty.
230  *
231  * Return value: -1 (with errno set) if it failed to rmdir the
232  * specified directory. 0 otherwise, whether or not it removed
233  * the parent directory.
234  **/
235 int
236 e_path_rmdir (const char *prefix, const char *vpath)
237 {
238         char *physical_path, *p;
239
240         /* Remove the directory itself */
241         physical_path = e_path_to_physical (prefix, vpath);
242         if (g_rmdir (physical_path) == -1) {
243                 g_free (physical_path);
244                 return -1;
245         }
246
247         /* Attempt to remove its parent "subfolders" directory,
248          * ignoring errors since it might not be empty.
249          */
250
251         p = strrchr (physical_path, '/');
252         if (p[1] == '\0') {
253                 g_free (physical_path);
254                 return 0;
255         }
256         *p = '\0';
257         p = strrchr (physical_path, '/');
258         if (!p || strcmp (p + 1, SUBFOLDER_DIR_NAME) != 0) {
259                 g_free (physical_path);
260                 return 0;
261         }
262
263         g_rmdir (physical_path);
264         g_free (physical_path);
265         return 0;
266 }
267
268 static GSList *
269 add_recipients(GSList *recipient_list, CamelAddress *recipients, int recipient_type)
270 {
271         int total_add,i;
272         EGwItemRecipient *recipient;
273         
274         total_add = camel_address_length (recipients);
275         for (i=0 ; i<total_add ; i++) {
276                 const char *name = NULL, *addr = NULL;
277                 if(camel_internet_address_get ((CamelInternetAddress *)recipients, i , &name, &addr )) {
278
279                         recipient = g_new0 (EGwItemRecipient, 1);
280
281                         recipient->email = g_strdup (addr);
282                         recipient->display_name = g_strdup (name);
283                         recipient->type = recipient_type;
284                         recipient->status = E_GW_ITEM_STAT_NONE;
285                         recipient_list = g_slist_prepend (recipient_list, recipient);
286                 }
287         }
288         return recipient_list;
289 }
290
291 static void 
292 send_as_attachment (EGwConnection *cnc, EGwItem *item, CamelStreamMem *content, CamelContentType *type, CamelDataWrapper *dw, const char *filename, const char *cid, GSList **attach_list)
293 {
294         EGwItemLinkInfo *info = NULL;
295         EGwConnectionStatus status;
296         EGwItemAttachment *attachment;
297         EGwItem *temp_item;
298         
299         attachment = g_new0 (EGwItemAttachment, 1);
300         attachment->contentType = camel_content_type_simple (type);
301         
302         if (cid)
303                 attachment->contentid = camel_header_contentid_decode (cid);
304         
305         if (filename) {
306                 if (camel_content_type_is (type, "application", "pgp-signature")) {
307                         char *temp_str;
308                         int temp_len;
309                         temp_str = soup_base64_encode (content->buffer->data, content->buffer->len);
310                         temp_len = strlen (temp_str);
311                         attachment->data = g_strdup (temp_str);
312                         attachment->size = temp_len;
313                         g_free (temp_str);
314                         temp_str = NULL;
315                         temp_len = 0;
316                 } else {
317                         attachment->data = soup_base64_encode(content->buffer->data, content->buffer->len);
318                         attachment->size = strlen (attachment->data);
319                 }
320         } else {
321                 char *temp_str;
322                 int temp_len;
323                 if (!strcmp (attachment->contentType, "multipart/digest")) {
324                         /* FIXME? */
325                 } else {
326                         temp_str = soup_base64_encode (content->buffer->data, content->buffer->len);
327                         temp_len = strlen (temp_str);
328                         attachment->data = g_strdup (temp_str);
329                         attachment->size = temp_len;
330                         g_free (temp_str);
331                         temp_str = NULL;
332                         temp_len = 0;
333                 }
334         }
335         
336         if (camel_content_type_is (type, "text", "html") || camel_content_type_is (type, "multipart", "alternative")) {
337                 if (!filename)
338                         filename = "text.htm";
339                 if (camel_content_type_is (type, "multipart", "alternative")) {
340                         /* FIXME: this just feels so wrong... */
341                         g_free (attachment->contentType);
342                         attachment->contentType = g_strdup ("text/html");
343                 }
344         }
345
346         attachment->name = g_strdup (filename ? filename : "");
347         if (camel_content_type_is (type, "message", "rfc822")) {
348                 const char *message_id;
349                 char *msgid;
350                 int len;
351                 
352                 message_id = camel_medium_get_header (CAMEL_MEDIUM (dw), "Message-Id");
353                 /*
354                  * XXX: The following code piece is a screwed up way of doing stuff.
355                  * But we dont have much choice. Do not use 'camel_header_msgid_decode'
356                  * since it removes the container id portion from the id and which the
357                  * groupwise server needs.
358                  */
359                 
360                 len = strlen (message_id);
361                 msgid = (char *)g_malloc0 (len-1);
362                 msgid = memcpy(msgid, message_id+2, len-3);
363                 g_print ("||| msgid:%s\n", msgid);
364
365                 status = e_gw_connection_forward_item (cnc, msgid, NULL, TRUE, &temp_item);
366                 g_free (msgid);
367                 
368                 if (status != E_GW_CONNECTION_STATUS_OK) {
369                         g_warning ("Could not send a forwardRequest...continuing without!!\n");
370                 } else {
371                         GSList *attach_list = e_gw_item_get_attach_id_list (temp_item);
372                         EGwItemAttachment *temp_attach = (EGwItemAttachment *)attach_list->data;
373                         attachment->id = g_strdup (temp_attach->id);
374                         attachment->item_reference = g_strdup (temp_attach->item_reference);
375                         g_free (attachment->name);
376                         attachment->name = g_strdup (temp_attach->name);
377                         g_free (attachment->contentType);
378                         attachment->contentType = g_strdup ("Mail");
379                         g_free (attachment->data); 
380                         attachment->data = NULL;
381                         attachment->size = 0;
382                         info = e_gw_item_get_link_info (temp_item);
383                         e_gw_item_set_link_info (item, info);
384                 }
385         }
386
387         *attach_list = g_slist_append (*attach_list, attachment);
388 }
389
390 EGwItem *
391 camel_groupwise_util_item_from_message (EGwConnection *cnc, CamelMimeMessage *message, CamelAddress *from)
392 {
393         EGwItem *item;
394         EGwItemOrganizer *org = g_new0 (EGwItemOrganizer, 1);
395         const char *display_name = NULL, *email = NULL;
396         char *send_options = NULL;
397         CamelMultipart *mp;
398         GSList *recipient_list = NULL, *attach_list = NULL;
399         CamelAddress *recipients;
400
401         /*Egroupwise item*/
402         item = e_gw_item_new_empty ();
403         
404         /*populate recipient list*/
405         recipients = CAMEL_ADDRESS (camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO));
406         recipient_list=add_recipients(recipient_list,recipients,E_GW_ITEM_RECIPIENT_TO);
407         
408         recipients = CAMEL_ADDRESS (camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC));
409         recipient_list=add_recipients(recipient_list,recipients,E_GW_ITEM_RECIPIENT_CC);
410         
411         recipients = CAMEL_ADDRESS (camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_BCC));
412         recipient_list=add_recipients(recipient_list,recipients,E_GW_ITEM_RECIPIENT_BC);
413         recipient_list = g_slist_reverse (recipient_list);
414         
415         /** Get the mime parts from CamelMimemessge **/
416         mp = (CamelMultipart *)camel_medium_get_content_object (CAMEL_MEDIUM (message));
417         if(!mp) {
418                 g_warning ("ERROR: Could not get content object");
419                 camel_operation_end (NULL);
420                 return FALSE;
421         }
422
423         if (CAMEL_IS_MULTIPART (mp)) {
424                 /*contains multiple parts*/
425                 do_multipart (cnc, item, mp, &attach_list);
426         } else {
427                 /*only message*/
428                 CamelStreamMem *content = (CamelStreamMem *)camel_stream_mem_new ();
429                 CamelDataWrapper *dw = NULL;
430                 CamelContentType *type;
431                 
432                 dw = camel_medium_get_content_object (CAMEL_MEDIUM (message));
433                 type = camel_mime_part_get_content_type((CamelMimePart *)message);
434                 
435                 if (camel_content_type_is (type, "text", "plain")) {
436                         CamelStream *filtered_stream;
437                         CamelMimeFilter *filter;
438                         const char *charset;
439                         char *content_type;
440                         
441                         content_type = camel_content_type_simple (type);
442                         e_gw_item_set_content_type (item, content_type);
443                         g_free (content_type);
444                         
445                         charset = camel_content_type_param (type, "charset");
446                         if (charset && g_ascii_strcasecmp (charset, "US-ASCII") && g_ascii_strcasecmp (charset, "UTF-8")) {
447                                 filter = (CamelMimeFilter *) camel_mime_filter_charset_new_convert (charset, "UTF-8");
448                                 filtered_stream = (CamelStream *) camel_stream_filter_new_with_stream ((CamelStream *) content);
449                                 camel_stream_filter_add ((CamelStreamFilter *) filtered_stream, filter);
450                                 camel_object_unref (filter);
451                         } else {
452                                 /* US-ASCII or UTF-8 */
453                                 filtered_stream = (CamelStream *) content;
454                                 camel_object_ref (content);
455                         }
456                         
457                         camel_data_wrapper_decode_to_stream (dw, filtered_stream);
458                         camel_stream_flush (filtered_stream);
459                         camel_object_unref (filtered_stream);
460                         
461                         camel_stream_write ((CamelStream *) content, "", 1);
462                         e_gw_item_set_message (item, (const char *)content->buffer->data);
463                 } else {
464                         camel_data_wrapper_decode_to_stream (dw, (CamelStream *) content);
465                         send_as_attachment (cnc, item, content, type, dw, NULL, NULL, &attach_list);    
466                 }
467                 
468                 camel_object_unref (content);
469         }
470         /*Populate EGwItem*/
471         /*From Address*/
472         camel_internet_address_get ((CamelInternetAddress *)from, 0 , &display_name, &email);
473         org->display_name = g_strdup (display_name);
474         org->email = g_strdup (email);
475         e_gw_item_set_organizer (item, org);
476         /*recipient list*/
477         e_gw_item_set_recipient_list (item, recipient_list);
478         /*Item type is mail*/
479         e_gw_item_set_item_type (item, E_GW_ITEM_TYPE_MAIL);
480         /*subject*/
481         e_gw_item_set_subject (item, camel_mime_message_get_subject(message));
482         /*attachmets*/
483         e_gw_item_set_attach_id_list (item, attach_list);
484         
485         /*send options*/
486         e_gw_item_set_sendoptions (item, TRUE);
487
488         if ((char *)camel_medium_get_header (CAMEL_MEDIUM(message), X_REPLY_CONVENIENT)) 
489                 e_gw_item_set_reply_request (item, TRUE);
490         
491         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM(message), X_REPLY_WITHIN);
492         if (send_options) { 
493                 e_gw_item_set_reply_request (item, TRUE);
494                 e_gw_item_set_reply_within (item, send_options);
495         }
496         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM(message),X_EXPIRE_AFTER);
497         if (send_options)
498                 e_gw_item_set_expires (item, send_options);
499
500         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM(message), X_DELAY_UNTIL);
501         if (send_options)
502                 e_gw_item_set_delay_until (item, send_options);
503
504         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM(message), X_TRACK_WHEN);
505
506         /*we check if user has modified the status tracking options, if no then we anyway 
507          * set status tracking all*/
508         if (send_options) {
509                 switch (atoi(send_options)) {
510                         case 1: e_gw_item_set_track_info (item, E_GW_ITEM_DELIVERED);
511                                 break;
512                         case 2: e_gw_item_set_track_info (item, E_GW_ITEM_DELIVERED_OPENED);
513                                 break;
514                         case 3: e_gw_item_set_track_info (item, E_GW_ITEM_ALL);
515                                 break;
516                         default: e_gw_item_set_track_info (item, E_GW_ITEM_NONE);
517                                  break;
518                 }
519         } else
520                 e_gw_item_set_track_info (item, E_GW_ITEM_ALL);
521
522         if ((char *)camel_medium_get_header (CAMEL_MEDIUM(message), X_AUTODELETE))
523                 e_gw_item_set_autodelete (item, TRUE);
524
525         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM (message), X_RETURN_NOTIFY_OPEN);
526         if (send_options) {
527                 switch (atoi(send_options)) {
528                         case 0: e_gw_item_set_notify_opened (item, E_GW_ITEM_NOTIFY_NONE);
529                                 break;
530                         case 1: e_gw_item_set_notify_opened (item, E_GW_ITEM_NOTIFY_MAIL);
531                 }
532         }
533         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM (message), X_RETURN_NOTIFY_DELETE);
534         if (send_options) {
535                 switch (atoi(send_options)) {
536                         case 0: e_gw_item_set_notify_deleted (item, E_GW_ITEM_NOTIFY_NONE);
537                                 break;
538                         case 1: e_gw_item_set_notify_deleted (item, E_GW_ITEM_NOTIFY_MAIL);
539                 }
540         }       
541         
542         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM (message), X_SEND_OPT_PRIORITY);
543         if (send_options) {
544                 switch (atoi(send_options)) {
545                         case E_GW_PRIORITY_HIGH: e_gw_item_set_priority(item, "High");
546                                                  break;
547                         case E_GW_PRIORITY_LOW:  e_gw_item_set_priority(item, "Low");
548                                                  break;
549                         case E_GW_PRIORITY_STANDARD: e_gw_item_set_priority(item, "Standard");
550                                                      break;
551                 }
552         }
553
554         send_options = (char *)camel_medium_get_header (CAMEL_MEDIUM (message), X_SEND_OPT_SECURITY);
555         if (send_options) {
556                 switch (atoi(send_options)) {
557                         case E_GW_SECURITY_NORMAL : e_gw_item_set_security(item, "Normal");
558                                                     break;
559                         case E_GW_SECURITY_PROPRIETARY : e_gw_item_set_security(item, "Proprietary");
560                                                          break;
561                         case E_GW_SECURITY_CONFIDENTIAL : e_gw_item_set_security(item, "Confidential");
562                                                           break;
563                         case E_GW_SECURITY_SECRET : e_gw_item_set_security(item, "Secret");
564                                                     break;
565                         case E_GW_SECURITY_TOP_SECRET : e_gw_item_set_security(item, "TopSecret");
566                                                         break;
567                         case E_GW_SECURITY_FOR_YOUR_EYES_ONLY : e_gw_item_set_security(item, "ForYourEyesOnly");
568                                                                 break;
569                 }
570         } 
571         return item;
572 }
573
574 void
575 do_flags_diff (flags_diff_t *diff, guint32 old, guint32 _new)
576 {
577         diff->changed = old ^ _new;
578         diff->bits = _new & diff->changed;
579 }
580
581 char *
582 gw_concat ( const char *prefix, const char *suffix)
583 {
584         size_t len;
585
586         len = strlen (prefix);
587         if (len == 0 || prefix[len - 1] == '/')
588                 return g_strdup_printf ("%s%s", prefix, suffix);
589         else
590                 return g_strdup_printf ("%s%c%s", prefix, '/', suffix);
591 }
592
593 void
594 strip_lt_gt (char **string, int s_offset, int e_offset)
595 {
596         char *temp = NULL;
597         int len;
598         
599         temp = g_strdup (*string);
600         len = strlen (*string);
601
602         *string = (char *)g_malloc0 (len-1);
603         *string = memcpy(*string, temp+s_offset, len-e_offset);
604         g_free (temp);
605 }
606
607 static void
608 do_multipart (EGwConnection *cnc, EGwItem *item, CamelMultipart *mp, GSList **attach_list)
609 {
610         /*contains multiple parts*/
611         guint part_count;
612         int i;
613
614         part_count = camel_multipart_get_number (mp);
615         for ( i=0 ; i<part_count ; i++) {
616                 CamelContentType *type;
617                 CamelMimePart *part;
618                 CamelStreamMem *content = (CamelStreamMem *)camel_stream_mem_new ();
619                 CamelDataWrapper *dw = NULL;
620                 const char *disposition, *filename;
621                 const char *content_id = NULL;
622                 gboolean is_alternative = FALSE;
623                 /*
624                  * XXX:
625                  * Assuming the first part always is the actual message
626                  * and an attachment otherwise.....
627                  */
628                 part = camel_multipart_get_part (mp, i);
629
630                 if (!part)
631                         continue;
632
633                 type = camel_mime_part_get_content_type(part);
634                 dw = camel_medium_get_content_object (CAMEL_MEDIUM (part));
635                 
636                 if (CAMEL_IS_MULTIPART (dw)) {
637                         do_multipart (cnc, item, (CamelMultipart *) camel_medium_get_content_object ((CamelMedium *) part), attach_list);
638                         continue;
639                 }
640                 
641                 if (type->subtype && !strcmp (type->subtype, "alternative")) {
642                         /* eh... I don't think this code will ever get hit? */
643                         CamelMimePart *temp_part;
644                         const char *cid = NULL;
645                         CamelStreamMem *temp_content = (CamelStreamMem *)camel_stream_mem_new ();
646                         CamelDataWrapper *temp_dw = NULL;
647                         
648                         temp_part = camel_multipart_get_part ((CamelMultipart *)dw, 1);
649                         if (temp_part) {
650                                 is_alternative = TRUE;
651                                 temp_dw = camel_medium_get_content_object (CAMEL_MEDIUM (temp_part));
652                                 camel_data_wrapper_write_to_stream(temp_dw, (CamelStream *)temp_content);
653                                 filename = camel_mime_part_get_filename (temp_part);
654                                 disposition = camel_mime_part_get_disposition (temp_part);
655                                 cid = camel_mime_part_get_content_id (temp_part);
656                                 send_as_attachment (cnc, item, temp_content, type, temp_dw, filename, cid, attach_list);
657                         }
658                         camel_object_unref (temp_content);
659                         continue;
660                 } 
661                 
662                 if (i == 0 && camel_content_type_is (type, "text", "plain")) {
663                         CamelStream *filtered_stream;
664                         CamelMimeFilter *filter;
665                         const char *charset;
666                         char *content_type;
667                         
668                         content_type = camel_content_type_simple (type);
669                         e_gw_item_set_content_type (item, content_type);
670                         g_free (content_type);
671                         
672                         charset = camel_content_type_param (type, "charset");
673                         if (charset && g_ascii_strcasecmp (charset, "US-ASCII") && g_ascii_strcasecmp (charset, "UTF-8")) {
674                                 filter = (CamelMimeFilter *) camel_mime_filter_charset_new_convert (charset, "UTF-8");
675                                 filtered_stream = (CamelStream *) camel_stream_filter_new_with_stream ((CamelStream *) content);
676                                 camel_stream_filter_add ((CamelStreamFilter *) filtered_stream, filter);
677                                 camel_object_unref (filter);
678                         } else {
679                                 /* US-ASCII or UTF-8 */
680                                 filtered_stream = (CamelStream *) content;
681                                 camel_object_ref (content);
682                         }
683                         
684                         camel_data_wrapper_decode_to_stream (dw, filtered_stream);
685                         camel_stream_flush (filtered_stream);
686                         camel_object_unref (filtered_stream);
687                         
688                         camel_stream_write ((CamelStream *) content, "", 1);
689                         e_gw_item_set_message (item, (const char *)content->buffer->data);
690                 } else {
691                         filename = camel_mime_part_get_filename (part);
692                         disposition = camel_mime_part_get_disposition (part);
693                         content_id = camel_mime_part_get_content_id (part);
694                         
695                         camel_data_wrapper_decode_to_stream (dw, (CamelStream *) content);
696                         send_as_attachment (cnc, item, content, type, dw, filename, content_id, attach_list);
697                 }
698                 
699                 camel_object_unref (content);
700         } /*end of for*/
701 }