Index: libbalsa/mime.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mime.c,v
retrieving revision 1.42
diff -u -b -r1.42 mime.c
--- libbalsa/mime.c	23 Feb 2002 22:30:15 -0000	1.42
+++ libbalsa/mime.c	3 Apr 2002 15:54:27 -0000
@@ -20,21 +20,218 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
  * 02111-1307, USA.
  */
+#include <stdlib.h>
 
 #include <string.h>
+#include <ctype.h>
 #include "config.h"
 
 #include "libbalsa.h"
 #include "mailbackend.h"
 #include "misc.h"
 
-/* FIXME: The content of this file could go to message.c */
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <libgnome/libgnome.h>
+
+
+
+
+#define HTML_TO_TEXT "lynx -force_html -dump file:%s > %s" /* *** FIXME: Use preference setting instead */
+
 
-static GString *process_mime_multipart(LibBalsaMessage * message,
+static GString *
+process_mime_multipart(LibBalsaMessage * message,
                                        LibBalsaMessageBody * body,
-				       gchar * reply_prefix_str,
-				       gint llen, gboolean ignore_html,
-                                       gboolean flow);
+		       gchar * reply_prefix_str, gint llen,
+		       gboolean ignore_html, gboolean flow);
+
+/* FIXME: The content of this file could go to message.c */
+
+static gchar char_ref_char(const gchar *char_ref) 
+{
+    if(char_ref[1]=='#')
+	return (gchar )atoi(char_ref+1);
+    else {
+	int i;
+
+	const struct {
+	    const char *entity;
+	    int character;
+	} entity_table[] = {
+	    { "lt", '<' }, { "gt", '>' }, 
+	    { "amp", '&' }, { "nbsp", ' ' },
+	    { "aelig", 'æ' }, { "AElig", 'Æ' },
+	    { "oslash", 'ø' }, { "Oslash", 'Ø' },
+	    { "aring", 'å' }, { "Aring", 'Å' },
+	    { NULL, '?' }};
+	    
+	for(i=0; entity_table[i].entity; i++)
+	    if(strcmp(entity_table[i].entity, char_ref)==0)
+		return entity_table[i].character;
+    }
+   /* Return first character for the rest. Often makes sense because reference
+      is "<character base><info on accent etc.>" */
+   return char_ref[0];
+}
+
+static gchar *extract_tag(gchar **html, gchar end_sep)
+/* Pre : *html is at start of tag, i.e. points to '<' or similar
+   Post: *html points to position after end of tag. */
+{
+    gchar *end=strchr(*html, end_sep), *tag;
+
+    if(!end)			/* No '>', skip rest of string. */
+	end=*html+strlen(*html);
+    
+    tag=g_strndup(*html+1, end-*html-1);
+    *html=end+1;
+    
+    return tag;
+}
+
+static gchar *convert_html_internal(const gchar *html)
+/* Remarks: Fall-back used when no real HTML converter was configured, or 
+            call failed. */
+{
+    gchar *txt=calloc(strlen(html)+1, sizeof(gchar));
+
+    if(txt) {
+	gchar *c_html=(gchar *)html, *c_txt=txt;
+	gboolean skip=FALSE;
+
+	while(*c_html) {
+	    if(*c_html=='<') {
+		gchar *tag=extract_tag(&c_html, '>');
+		
+		if(g_strncasecmp(tag, "head", 4)==0) {
+		    skip=TRUE;
+		} else if(g_strncasecmp(tag, "body", 4)==0) {
+		    skip=FALSE;
+		} 
+
+		if(!skip) {
+		    if(g_strcasecmp(tag, "br")==0 || 
+		       g_strcasecmp(tag, "tr")==0) {
+			*c_txt++='\n';
+		    } else if(g_strcasecmp(tag, "p")==0 ||
+			      (tolower(tag[0])=='h' && isdigit(tag[1]))) {
+			*c_txt++='\n';
+			*c_txt++='\n';
+		    } else if(g_strcasecmp(tag, "li")==0) {
+			*c_txt++='\n';
+			*c_txt++='*';
+			*c_txt++='\t';
+		    } else if(g_strcasecmp(tag, "td")==0 || 
+			      g_strcasecmp(tag, "th")==0) {
+		     /* Note: Can't do a lot more than starting a new
+			      paragraph (more or less), since we are not
+			      able to interleave text from different cells. */
+			*c_txt++='\n';
+			*c_txt++='\n';
+			*c_txt++='\t';
+		    } else {
+			gchar *ref=strstr(tag, "href=");
+		    
+			if(!ref) { /* *** Want 'strcasestr' */
+			    ref=strstr(tag, "HREF=");
+			}
+		    
+			if(ref) {
+			    *c_txt++='[';
+			    ref+=5;
+			    
+			    while(*ref && *ref!=' ')
+				*c_txt++=*ref++;
+			    *c_txt++=']';
+			}
+		    }
+		}
+		g_free(tag);
+	    } else if(skip) {
+		c_html++;
+	    } else if(*c_html=='&') {
+		gchar *char_ref=extract_tag(&c_html, ';');
+
+		*c_txt++=char_ref_char(char_ref);
+		g_free(char_ref);
+	    } else if(*c_html=='\n' || *c_html==' ' || *c_html=='\t') {
+		gchar prev=*(c_txt-1);
+
+		c_html++;
+		
+		if(c_txt!=txt && prev!=' ' && prev!='\n' && prev!='\t')
+		    *c_txt++=' ';
+	    } else {
+		*c_txt++=*c_html++;
+	    }
+	}
+    }
+    return txt;
+}
+
+int convert_html_file(const gchar *txt_file, const gchar *html_file)
+{
+    gchar cmd[PATH_MAX + 1];
+    pid_t cmd_pid;
+    
+    snprintf(cmd, sizeof(cmd), HTML_TO_TEXT, html_file, txt_file);
+
+    /* Note: Should probably find gnome_ alternative to fork() + exec(),
+            but this is at least better than system() (gnome_execute_shell
+            is not what we want as it will start process in the background 
+    */
+    
+    if((cmd_pid=fork())==0) {
+	gchar *shell=gnome_util_user_shell();
+
+	execl(shell, shell, "-c", cmd, NULL);
+	g_free(shell);	/* In case exec fails */
+	_exit(1);
+    } else if(cmd_pid>0) {
+	waitpid(cmd_pid, NULL, 0);
+	return 1;
+    }
+    return 0;
+}
+
+gchar *convert_html(const gchar *html)
+{
+#ifdef HTML_TO_TEXT
+    gchar html_file[PATH_MAX + 1], txt_file[PATH_MAX + 1];
+    gchar *txt=NULL;
+    FILE *fp;
+
+    libbalsa_lock_mutt();
+    mutt_mktemp(html_file);
+    mutt_mktemp(txt_file);
+    libbalsa_unlock_mutt();
+
+    fp=safe_fopen(html_file, "w");
+    
+    if(fp) {
+	fprintf(fp, "%s", html);
+	fclose(fp);
+
+	if(convert_html_file(txt_file, html_file)) {
+	    fp=fopen(txt_file, "r");
+	    if(fp) {
+		libbalsa_readfile(fp, &txt);
+		fclose(fp);
+	    }
+	}
+    }
+    unlink(txt_file);
+    unlink(html_file);
+
+    if(txt)
+	return txt;
+
+#endif
+    return convert_html_internal(html);
+}
+
+
 
 /* process_mime_part:
    returns string representation of given message part.
@@ -49,6 +246,9 @@
     size_t alloced;
     gchar *res = NULL;
     GString *reply = NULL;
+    gchar *content_type = libbalsa_message_body_get_content_type(body);
+    gboolean ishtml=(g_strcasecmp(content_type, "text/html") == 0);
+
 
     switch (libbalsa_message_body_type(body)) {
     case LIBBALSA_MESSAGE_BODY_TYPE_OTHER:
@@ -56,19 +256,14 @@
     case LIBBALSA_MESSAGE_BODY_TYPE_APPLICATION:
     case LIBBALSA_MESSAGE_BODY_TYPE_IMAGE:
     case LIBBALSA_MESSAGE_BODY_TYPE_MODEL:
-    case LIBBALSA_MESSAGE_BODY_TYPE_MESSAGE:
     case LIBBALSA_MESSAGE_BODY_TYPE_VIDEO:
 	break;
     case LIBBALSA_MESSAGE_BODY_TYPE_MULTIPART:
+    case LIBBALSA_MESSAGE_BODY_TYPE_MESSAGE:
         reply = process_mime_multipart(message, body, reply_prefix_str,
                                        llen, ignore_html, flow);
 	break;
     case LIBBALSA_MESSAGE_BODY_TYPE_TEXT:
-	/* don't return text/html stuff... */
-	if (ignore_html && body->mutt_body->subtype &&
-	    !strcmp("html", body->mutt_body->subtype))
-	    break;
-
 	libbalsa_message_body_save_temporary(body, NULL);
 
 	part = fopen(body->temp_filename, "r");
@@ -79,6 +274,16 @@
 	if (!res)
 	    break;
 
+	if(ishtml) {
+	    gchar *res_ascii=convert_html(res);
+	    
+	    if(res_ascii) {
+		g_free(res);
+		res=res_ascii;
+	    }
+	}
+	    
+
 	if (llen > 0) {
             if (flow && libbalsa_flowed_rfc2646(body)) {
                 /* we're making a `format=flowed' message, and the
@@ -127,6 +332,8 @@
 	g_free(res);
 	break;
     }
+    g_free(content_type);	
+
     return reply;
 }
 
@@ -138,18 +345,38 @@
 {
     LibBalsaMessageBody *part;
     GString *res = NULL, *s;
+    gchar *content_type = libbalsa_message_body_get_content_type(body);
+
+    fprintf(stderr, "process_mime_multipart\n");
 
+    if(g_strcasecmp(content_type, "multipart/alternative")==0) {
+	part = preferred_part(body->parts, ignore_html);
+	if(part)
+	    res = process_mime_part(message, part, reply_prefix_str, llen,
+				    ignore_html, flow);
+    } else {
+	fprintf(stderr, "HEIIIII\n");
     for (part = body->parts; part; part = part->next) {
+	    if(part->mutt_body->disposition==DISPINLINE)
 	s = process_mime_part(message, part, reply_prefix_str, llen,
                           ignore_html, flow);
+	    else
+		s = NULL;
+	    fprintf(stderr, "%d %x %x\n", part->mutt_body->disposition, res, s);
+
 	if (!s)
 	    continue;
+	    
+
 	if (res) {
 	    res = g_string_append(res, s->str);
 	    g_string_free(s, TRUE);
 	} else
 	    res = s;
     }
+    }
+
+    g_free(content_type);
     return res;
 }
 
@@ -174,4 +401,38 @@
     }
 
     return reply;
+}
+
+LibBalsaMessageBody*
+preferred_part(LibBalsaMessageBody *parts, gboolean ignore_html)
+/* Remarks: Try to find LAST suitable part, which should be considered the
+            best according to RFC 1341 */
+{
+    /* TODO: - Look for additional specific types, and have more flags 
+               to control their selection?
+             - Let user preferences or previous selections override order 
+	       (e.g. choose text/html part even when text/plain is included
+	       after it)? */
+    LibBalsaMessageBody *body;
+    gchar *content_type;
+    LibBalsaMessageBody *best_part=NULL, *last_part=NULL;
+
+    for(body=parts; body; body=body->next) {
+	content_type = libbalsa_message_body_get_content_type(body);
+	
+	if(g_strcasecmp(content_type, "text/plain")==0 ||
+	   !ignore_html && (g_strcasecmp(content_type, "text/html")==0 ||
+			    g_strcasecmp(content_type, "multipart/related")==0) ||
+	   !best_part && g_strncasecmp(content_type, "text/", 5)==0)
+	    best_part=body;
+	   
+	last_part=body;
+
+	g_free(content_type);
+    }
+    
+    if(!best_part)
+	best_part=last_part;
+    
+    return best_part;
 }
Index: libbalsa/mime.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mime.h,v
retrieving revision 1.16
diff -u -b -r1.16 mime.h
--- libbalsa/mime.h	23 Sep 2001 18:04:48 -0000	1.16
+++ libbalsa/mime.h	3 Apr 2002 15:54:27 -0000
@@ -31,8 +31,15 @@
 			   LibBalsaMessageBody * body,
 			   gchar * reply_prefix_str, gint llen,
 			   gboolean ignore_html, gboolean flow);
+
 GString *content2reply(LibBalsaMessage * message,
 		       gchar * reply_prefix_str, gint llen,
 		       gboolean ignore_html, gboolean flow);	/* arp */
+
+int convert_html_file(const gchar *text_file, const gchar *html_file);
+gchar *convert_html(const gchar *html);
+
+LibBalsaMessageBody*
+preferred_part(LibBalsaMessageBody *parts, gboolean ignore_html);
 
 #endif				/* __LIBBALSA_MIME_H__ */
Index: libbalsa/send.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/send.c,v
retrieving revision 1.147
diff -u -b -r1.147 send.c
--- libbalsa/send.c	10 Mar 2002 14:52:50 -0000	1.147
+++ libbalsa/send.c	3 Apr 2002 15:54:28 -0000
@@ -37,6 +37,7 @@
 #include "mailbox_imap.h"
 #include "misc.h"
 #include "information.h"
+#include "mime.h"		/* For HTML conversion routines */
 
 #ifdef BALSA_USE_THREADS
 #include "threads.h"
@@ -50,6 +51,12 @@
 #include <sys/stat.h>
 #endif
 
+#ifdef HAVE_GNOME_VFS
+#include <libgnomevfs/gnome-vfs-mime.h>
+#endif
+
+
+
 typedef struct _MessageQueueItem MessageQueueItem;
 
 struct _MessageQueueItem {
@@ -304,6 +311,7 @@
     return body;
 }
 
+
 static BODY *
 add_mutt_body_as_extbody(const gchar *filename, const gchar *mime_type)
 {
@@ -338,6 +346,41 @@
     return body;
 }
 
+static BODY *real_body(BODY *body)
+{
+    if(body->disposition==DISPINLINE && body->type==TYPETEXT && 
+       strcmp(body->subtype, "html")==0) {
+	gchar txt_file[PATH_MAX + 1];
+
+	libbalsa_lock_mutt();
+	mutt_mktemp(txt_file);
+	
+	mutt_delete_parameter("format", &body->parameter);
+
+	if(convert_html_file(txt_file, body->filename)) {
+	    BODY *plain_body, *multipart;
+	    
+	    plain_body=libmutt_copy_body(body, body->hdr);
+	    plain_body->subtype=strdup("plain");
+	    plain_body->filename=g_strdup(txt_file);
+
+	    plain_body->next=body;
+
+	    multipart=mutt_make_multipart(plain_body);
+	    g_free(multipart->subtype);
+	    multipart->subtype=g_strdup("alternative");
+
+	    libbalsa_unlock_mutt();
+
+	    return multipart;
+	} 
+	libbalsa_unlock_mutt();
+    }
+    
+    return body;
+}
+
+
 #if 0
 /* you never know when you will need this one... */
 static void dump_queue(const char*msg)
@@ -1437,18 +1480,30 @@
 		}
 	    }
 	} else if (body->buffer) {
+	    const char *mime_type;
+	    
 	    newbdy = add_mutt_body_plain(body->charset, encoding, flow);
-	    if (body->mime_type) {
+#ifdef HAVE_GNOME_VFS
+	    mime_type=gnome_vfs_get_mime_type_for_data(body->buffer, 
+						       strlen(body->buffer));
+
+	    if(!mime_type || strcmp(mime_type, "text/html")!=0)
+		mime_type=body->mime_type;
+#else
+	    mime_type=body->mime_type;
+#endif
+	    if (mime_type) {
 		/* change the type and subtype within the mutt body */
 		gchar *type, *subtype;
 		
-		type = g_strdup (body->mime_type);
+		type = g_strdup (mime_type);
 		if ((subtype = strchr (type, '/'))) {
 		    *subtype++ = 0;
 		    libbalsa_lock_mutt();
 		    newbdy->type = mutt_check_mime_type (type);
 		    g_free(newbdy->subtype);
 		    newbdy->subtype = g_strdup(subtype);
+		    
 		    libbalsa_unlock_mutt();
 		}
 		g_free (type);
@@ -1466,9 +1521,9 @@
 
 	if (newbdy) {
 	    if (last)
-		last->next = newbdy;
+		last->next = real_body(newbdy);
 	    else
-		msg->content = newbdy;
+		msg->content = real_body(newbdy);
 
 	    last = newbdy;
 	}
